Linux Audio

Check our new training course

Loading...
   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");
 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,7 */
 365	{ .layout_id = 80,
 366	  .codecs[0] = {
 367		.name = "tas",
 368		.connections = tas_connections_noline,
 369	  },
 370	},
 371	/* PowerBook6,8 */
 372	{ .layout_id = 72,
 373	  .codecs[0] = {
 374		.name = "tas",
 375		.connections = tas_connections_nolineout,
 376	  },
 377	},
 378	/* PowerMac8,2 */
 379	{ .layout_id = 86,
 380	  .codecs[0] = {
 381		.name = "onyx",
 382		.connections = onyx_connections_nomic,
 383	  },
 384	  .codecs[1] = {
 385		.name = "topaz",
 386		.connections = topaz_input,
 387	  },
 388	},
 389	/* PowerBook6,7 */
 390	{ .layout_id = 92,
 391	  .codecs[0] = {
 392		.name = "tas",
 393		.connections = tas_connections_nolineout,
 394	  },
 395	},
 396	/* PowerMac10,1 (Mac Mini) */
 397	{ .layout_id = 58,
 398	  .codecs[0] = {
 399		.name = "toonie",
 400		.connections = toonie_connections,
 401	  },
 402	},
 403	{
 404	  .layout_id = 96,
 405	  .codecs[0] = {
 406	  	.name = "onyx",
 407	  	.connections = onyx_connections_noheadphones,
 408	  },
 409	},
 410	/* unknown, untested, but this comes from Apple */
 411	{ .layout_id = 41,
 412	  .codecs[0] = {
 413		.name = "tas",
 414		.connections = tas_connections_all,
 415	  },
 416	},
 417	{ .layout_id = 36,
 418	  .codecs[0] = {
 419		.name = "tas",
 420		.connections = tas_connections_nomic,
 421	  },
 422	  .codecs[1] = {
 423		.name = "topaz",
 424		.connections = topaz_inout,
 425	  },
 426	},
 427	{ .layout_id = 47,
 428	  .codecs[0] = {
 429		.name = "onyx",
 430		.connections = onyx_connections_noheadphones,
 431	  },
 432	},
 433	{ .layout_id = 48,
 434	  .codecs[0] = {
 435		.name = "topaz",
 436		.connections = topaz_input,
 437	  },
 438	},
 439	{ .layout_id = 49,
 440	  .codecs[0] = {
 441		.name = "onyx",
 442		.connections = onyx_connections_nomic,
 443	  },
 444	},
 445	{ .layout_id = 50,
 446	  .codecs[0] = {
 447		.name = "topaz",
 448		.connections = topaz_input,
 449	  },
 450	},
 451	{ .layout_id = 56,
 452	  .codecs[0] = {
 453		.name = "onyx",
 454		.connections = onyx_connections_noheadphones,
 455	  },
 456	},
 457	{ .layout_id = 57,
 458	  .codecs[0] = {
 459		.name = "topaz",
 460		.connections = topaz_input,
 461	  },
 462	},
 463	{ .layout_id = 62,
 464	  .codecs[0] = {
 465		.name = "onyx",
 466		.connections = onyx_connections_noheadphones,
 467	  },
 468	  .codecs[1] = {
 469		.name = "topaz",
 470		.connections = topaz_output,
 471	  },
 472	},
 473	{ .layout_id = 66,
 474	  .codecs[0] = {
 475		.name = "onyx",
 476		.connections = onyx_connections_noheadphones,
 477	  },
 478	},
 479	{ .layout_id = 67,
 480	  .codecs[0] = {
 481		.name = "topaz",
 482		.connections = topaz_input,
 483	  },
 484	},
 485	{ .layout_id = 76,
 486	  .codecs[0] = {
 487		.name = "tas",
 488		.connections = tas_connections_nomic,
 489	  },
 490	  .codecs[1] = {
 491		.name = "topaz",
 492		.connections = topaz_inout,
 493	  },
 494	},
 495	{ .layout_id = 90,
 496	  .codecs[0] = {
 497		.name = "tas",
 498		.connections = tas_connections_noline,
 499	  },
 500	},
 501	{ .layout_id = 94,
 502	  .codecs[0] = {
 503		.name = "onyx",
 504		/* but it has an external mic?? how to select? */
 505		.connections = onyx_connections_noheadphones,
 506	  },
 507	},
 508	{ .layout_id = 98,
 509	  .codecs[0] = {
 510		.name = "toonie",
 511		.connections = toonie_connections,
 512	  },
 513	},
 514	{ .layout_id = 100,
 515	  .codecs[0] = {
 516		.name = "topaz",
 517		.connections = topaz_input,
 518	  },
 519	  .codecs[1] = {
 520		.name = "onyx",
 521		.connections = onyx_connections_noheadphones,
 522	  },
 523	},
 524	/* PowerMac3,4 */
 525	{ .device_id = 14,
 526	  .codecs[0] = {
 527		.name = "tas",
 528		.connections = tas_connections_noline,
 529	  },
 530	},
 531	/* PowerMac3,6 */
 532	{ .device_id = 22,
 533	  .codecs[0] = {
 534		.name = "tas",
 535		.connections = tas_connections_all,
 536	  },
 537	},
 538	/* PowerBook5,2 */
 539	{ .device_id = 35,
 540	  .codecs[0] = {
 541		.name = "tas",
 542		.connections = tas_connections_all,
 543	  },
 544	},
 545	{}
 546};
 547
 548static struct layout *find_layout_by_id(unsigned int id)
 549{
 550	struct layout *l;
 551
 552	l = layouts;
 553	while (l->codecs[0].name) {
 554		if (l->layout_id == id)
 555			return l;
 556		l++;
 557	}
 558	return NULL;
 559}
 560
 561static struct layout *find_layout_by_device(unsigned int id)
 562{
 563	struct layout *l;
 564
 565	l = layouts;
 566	while (l->codecs[0].name) {
 567		if (l->device_id == id)
 568			return l;
 569		l++;
 570	}
 571	return NULL;
 572}
 573
 574static void use_layout(struct layout *l)
 575{
 576	int i;
 577
 578	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
 579		if (l->codecs[i].name) {
 580			request_module("snd-aoa-codec-%s", l->codecs[i].name);
 581		}
 582	}
 583	/* now we wait for the codecs to call us back */
 584}
 585
 586struct layout_dev;
 587
 588struct layout_dev_ptr {
 589	struct layout_dev *ptr;
 590};
 591
 592struct layout_dev {
 593	struct list_head list;
 594	struct soundbus_dev *sdev;
 595	struct device_node *sound;
 596	struct aoa_codec *codecs[MAX_CODECS_PER_BUS];
 597	struct layout *layout;
 598	struct gpio_runtime gpio;
 599
 600	/* we need these for headphone/lineout detection */
 601	struct snd_kcontrol *headphone_ctrl;
 602	struct snd_kcontrol *lineout_ctrl;
 603	struct snd_kcontrol *speaker_ctrl;
 604	struct snd_kcontrol *master_ctrl;
 605	struct snd_kcontrol *headphone_detected_ctrl;
 606	struct snd_kcontrol *lineout_detected_ctrl;
 607
 608	struct layout_dev_ptr selfptr_headphone;
 609	struct layout_dev_ptr selfptr_lineout;
 610
 611	u32 have_lineout_detect:1,
 612	    have_headphone_detect:1,
 613	    switch_on_headphone:1,
 614	    switch_on_lineout:1;
 615};
 616
 617static LIST_HEAD(layouts_list);
 618static int layouts_list_items;
 619/* this can go away but only if we allow multiple cards,
 620 * make the fabric handle all the card stuff, etc... */
 621static struct layout_dev *layout_device;
 622
 623#define control_info	snd_ctl_boolean_mono_info
 624
 625#define AMP_CONTROL(n, description)					\
 626static int n##_control_get(struct snd_kcontrol *kcontrol,		\
 627			   struct snd_ctl_elem_value *ucontrol)		\
 628{									\
 629	struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);	\
 630	if (gpio->methods && gpio->methods->get_##n)			\
 631		ucontrol->value.integer.value[0] =			\
 632			gpio->methods->get_##n(gpio);			\
 633	return 0;							\
 634}									\
 635static int n##_control_put(struct snd_kcontrol *kcontrol,		\
 636			   struct snd_ctl_elem_value *ucontrol)		\
 637{									\
 638	struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);	\
 639	if (gpio->methods && gpio->methods->get_##n)			\
 640		gpio->methods->set_##n(gpio,				\
 641			!!ucontrol->value.integer.value[0]);		\
 642	return 1;							\
 643}									\
 644static struct snd_kcontrol_new n##_ctl = {				\
 645	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				\
 646	.name = description,						\
 647	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,                      \
 648	.info = control_info,						\
 649	.get = n##_control_get,						\
 650	.put = n##_control_put,						\
 651}
 652
 653AMP_CONTROL(headphone, "Headphone Switch");
 654AMP_CONTROL(speakers, "Speakers Switch");
 655AMP_CONTROL(lineout, "Line-Out Switch");
 656AMP_CONTROL(master, "Master Switch");
 657
 658static int detect_choice_get(struct snd_kcontrol *kcontrol,
 659			     struct snd_ctl_elem_value *ucontrol)
 660{
 661	struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
 662
 663	switch (kcontrol->private_value) {
 664	case 0:
 665		ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
 666		break;
 667	case 1:
 668		ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
 669		break;
 670	default:
 671		return -ENODEV;
 672	}
 673	return 0;
 674}
 675
 676static int detect_choice_put(struct snd_kcontrol *kcontrol,
 677			     struct snd_ctl_elem_value *ucontrol)
 678{
 679	struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
 680
 681	switch (kcontrol->private_value) {
 682	case 0:
 683		ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
 684		break;
 685	case 1:
 686		ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
 687		break;
 688	default:
 689		return -ENODEV;
 690	}
 691	return 1;
 692}
 693
 694static struct snd_kcontrol_new headphone_detect_choice = {
 695	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 696	.name = "Headphone Detect Autoswitch",
 697	.info = control_info,
 698	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 699	.get = detect_choice_get,
 700	.put = detect_choice_put,
 701	.private_value = 0,
 702};
 703
 704static struct snd_kcontrol_new lineout_detect_choice = {
 705	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 706	.name = "Line-Out Detect Autoswitch",
 707	.info = control_info,
 708	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 709	.get = detect_choice_get,
 710	.put = detect_choice_put,
 711	.private_value = 1,
 712};
 713
 714static int detected_get(struct snd_kcontrol *kcontrol,
 715			struct snd_ctl_elem_value *ucontrol)
 716{
 717	struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
 718	int v;
 719
 720	switch (kcontrol->private_value) {
 721	case 0:
 722		v = ldev->gpio.methods->get_detect(&ldev->gpio,
 723						   AOA_NOTIFY_HEADPHONE);
 724		break;
 725	case 1:
 726		v = ldev->gpio.methods->get_detect(&ldev->gpio,
 727						   AOA_NOTIFY_LINE_OUT);
 728		break;
 729	default:
 730		return -ENODEV;
 731	}
 732	ucontrol->value.integer.value[0] = v;
 733	return 0;
 734}
 735
 736static struct snd_kcontrol_new headphone_detected = {
 737	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 738	.name = "Headphone Detected",
 739	.info = control_info,
 740	.access = SNDRV_CTL_ELEM_ACCESS_READ,
 741	.get = detected_get,
 742	.private_value = 0,
 743};
 744
 745static struct snd_kcontrol_new lineout_detected = {
 746	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 747	.name = "Line-Out Detected",
 748	.info = control_info,
 749	.access = SNDRV_CTL_ELEM_ACCESS_READ,
 750	.get = detected_get,
 751	.private_value = 1,
 752};
 753
 754static int check_codec(struct aoa_codec *codec,
 755		       struct layout_dev *ldev,
 756		       struct codec_connect_info *cci)
 757{
 758	const u32 *ref;
 759	char propname[32];
 760	struct codec_connection *cc;
 761
 762	/* if the codec has a 'codec' node, we require a reference */
 763	if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
 764		snprintf(propname, sizeof(propname),
 765			 "platform-%s-codec-ref", codec->name);
 766		ref = of_get_property(ldev->sound, propname, NULL);
 767		if (!ref) {
 768			printk(KERN_INFO "snd-aoa-fabric-layout: "
 769				"required property %s not present\n", propname);
 770			return -ENODEV;
 771		}
 772		if (*ref != codec->node->phandle) {
 773			printk(KERN_INFO "snd-aoa-fabric-layout: "
 774				"%s doesn't match!\n", propname);
 775			return -ENODEV;
 776		}
 777	} else {
 778		if (layouts_list_items != 1) {
 779			printk(KERN_INFO "snd-aoa-fabric-layout: "
 780				"more than one soundbus, but no references.\n");
 781			return -ENODEV;
 782		}
 783	}
 784	codec->soundbus_dev = ldev->sdev;
 785	codec->gpio = &ldev->gpio;
 786
 787	cc = cci->connections;
 788	if (!cc)
 789		return -EINVAL;
 790
 791	printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
 792
 793	codec->connected = 0;
 794	codec->fabric_data = cc;
 795
 796	while (cc->connected) {
 797		codec->connected |= 1<<cc->codec_bit;
 798		cc++;
 799	}
 800
 801	return 0;
 802}
 803
 804static int layout_found_codec(struct aoa_codec *codec)
 805{
 806	struct layout_dev *ldev;
 807	int i;
 808
 809	list_for_each_entry(ldev, &layouts_list, list) {
 810		for (i=0; i<MAX_CODECS_PER_BUS; i++) {
 811			if (!ldev->layout->codecs[i].name)
 812				continue;
 813			if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
 814				if (check_codec(codec,
 815						ldev,
 816						&ldev->layout->codecs[i]) == 0)
 817					return 0;
 818			}
 819		}
 820	}
 821	return -ENODEV;
 822}
 823
 824static void layout_remove_codec(struct aoa_codec *codec)
 825{
 826	int i;
 827	/* here remove the codec from the layout dev's
 828	 * codec reference */
 829
 830	codec->soundbus_dev = NULL;
 831	codec->gpio = NULL;
 832	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
 833	}
 834}
 835
 836static void layout_notify(void *data)
 837{
 838	struct layout_dev_ptr *dptr = data;
 839	struct layout_dev *ldev;
 840	int v, update;
 841	struct snd_kcontrol *detected, *c;
 842	struct snd_card *card = aoa_get_card();
 843
 844	ldev = dptr->ptr;
 845	if (data == &ldev->selfptr_headphone) {
 846		v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
 847		detected = ldev->headphone_detected_ctrl;
 848		update = ldev->switch_on_headphone;
 849		if (update) {
 850			ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
 851			ldev->gpio.methods->set_headphone(&ldev->gpio, v);
 852			ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
 853		}
 854	} else if (data == &ldev->selfptr_lineout) {
 855		v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
 856		detected = ldev->lineout_detected_ctrl;
 857		update = ldev->switch_on_lineout;
 858		if (update) {
 859			ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
 860			ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
 861			ldev->gpio.methods->set_lineout(&ldev->gpio, v);
 862		}
 863	} else
 864		return;
 865
 866	if (detected)
 867		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
 868	if (update) {
 869		c = ldev->headphone_ctrl;
 870		if (c)
 871			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
 872		c = ldev->speaker_ctrl;
 873		if (c)
 874			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
 875		c = ldev->lineout_ctrl;
 876		if (c)
 877			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
 878	}
 879}
 880
 881static void layout_attached_codec(struct aoa_codec *codec)
 882{
 883	struct codec_connection *cc;
 884	struct snd_kcontrol *ctl;
 885	int headphones, lineout;
 886	struct layout_dev *ldev = layout_device;
 887
 888	/* need to add this codec to our codec array! */
 889
 890	cc = codec->fabric_data;
 891
 892	headphones = codec->gpio->methods->get_detect(codec->gpio,
 893						      AOA_NOTIFY_HEADPHONE);
 894 	lineout = codec->gpio->methods->get_detect(codec->gpio,
 895						   AOA_NOTIFY_LINE_OUT);
 896
 897	if (codec->gpio->methods->set_master) {
 898		ctl = snd_ctl_new1(&master_ctl, codec->gpio);
 899		ldev->master_ctrl = ctl;
 900		aoa_snd_ctl_add(ctl);
 901	}
 902	while (cc->connected) {
 903		if (cc->connected & CC_SPEAKERS) {
 904			if (headphones <= 0 && lineout <= 0)
 905				ldev->gpio.methods->set_speakers(codec->gpio, 1);
 906			ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
 907			ldev->speaker_ctrl = ctl;
 908			aoa_snd_ctl_add(ctl);
 909		}
 910		if (cc->connected & CC_HEADPHONE) {
 911			if (headphones == 1)
 912				ldev->gpio.methods->set_headphone(codec->gpio, 1);
 913			ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
 914			ldev->headphone_ctrl = ctl;
 915			aoa_snd_ctl_add(ctl);
 916			ldev->have_headphone_detect =
 917				!ldev->gpio.methods
 918					->set_notify(&ldev->gpio,
 919						     AOA_NOTIFY_HEADPHONE,
 920						     layout_notify,
 921						     &ldev->selfptr_headphone);
 922			if (ldev->have_headphone_detect) {
 923				ctl = snd_ctl_new1(&headphone_detect_choice,
 924						   ldev);
 925				aoa_snd_ctl_add(ctl);
 926				ctl = snd_ctl_new1(&headphone_detected,
 927						   ldev);
 928				ldev->headphone_detected_ctrl = ctl;
 929				aoa_snd_ctl_add(ctl);
 930			}
 931		}
 932		if (cc->connected & CC_LINEOUT) {
 933			if (lineout == 1)
 934				ldev->gpio.methods->set_lineout(codec->gpio, 1);
 935			ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
 936			if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
 937				strlcpy(ctl->id.name,
 938					"Headphone Switch", sizeof(ctl->id.name));
 939			ldev->lineout_ctrl = ctl;
 940			aoa_snd_ctl_add(ctl);
 941			ldev->have_lineout_detect =
 942				!ldev->gpio.methods
 943					->set_notify(&ldev->gpio,
 944						     AOA_NOTIFY_LINE_OUT,
 945						     layout_notify,
 946						     &ldev->selfptr_lineout);
 947			if (ldev->have_lineout_detect) {
 948				ctl = snd_ctl_new1(&lineout_detect_choice,
 949						   ldev);
 950				if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
 951					strlcpy(ctl->id.name,
 952						"Headphone Detect Autoswitch",
 953						sizeof(ctl->id.name));
 954				aoa_snd_ctl_add(ctl);
 955				ctl = snd_ctl_new1(&lineout_detected,
 956						   ldev);
 957				if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
 958					strlcpy(ctl->id.name,
 959						"Headphone Detected",
 960						sizeof(ctl->id.name));
 961				ldev->lineout_detected_ctrl = ctl;
 962				aoa_snd_ctl_add(ctl);
 963			}
 964		}
 965		cc++;
 966	}
 967	/* now update initial state */
 968	if (ldev->have_headphone_detect)
 969		layout_notify(&ldev->selfptr_headphone);
 970	if (ldev->have_lineout_detect)
 971		layout_notify(&ldev->selfptr_lineout);
 972}
 973
 974static struct aoa_fabric layout_fabric = {
 975	.name = "SoundByLayout",
 976	.owner = THIS_MODULE,
 977	.found_codec = layout_found_codec,
 978	.remove_codec = layout_remove_codec,
 979	.attached_codec = layout_attached_codec,
 980};
 981
 982static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
 983{
 984	struct device_node *sound = NULL;
 985	const unsigned int *id;
 986	struct layout *layout = NULL;
 987	struct layout_dev *ldev = NULL;
 988	int err;
 989
 990	/* hm, currently we can only have one ... */
 991	if (layout_device)
 992		return -ENODEV;
 993
 994	/* by breaking out we keep a reference */
 995	while ((sound = of_get_next_child(sdev->ofdev.dev.of_node, sound))) {
 996		if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
 997			break;
 998	}
 999	if (!sound)
1000		return -ENODEV;
1001
1002	id = of_get_property(sound, "layout-id", NULL);
1003	if (id) {
1004		layout = find_layout_by_id(*id);
1005	} else {
1006		id = of_get_property(sound, "device-id", NULL);
1007		if (id)
1008			layout = find_layout_by_device(*id);
1009	}
1010
1011	if (!layout) {
1012		printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
1013		goto outnodev;
1014	}
1015
1016	ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
1017	if (!ldev)
1018		goto outnodev;
1019
1020	layout_device = ldev;
1021	ldev->sdev = sdev;
1022	ldev->sound = sound;
1023	ldev->layout = layout;
1024	ldev->gpio.node = sound->parent;
1025	switch (layout->layout_id) {
1026	case 0:  /* anything with device_id, not layout_id */
1027	case 41: /* that unknown machine no one seems to have */
1028	case 51: /* PowerBook5,4 */
1029	case 58: /* Mac Mini */
1030		ldev->gpio.methods = ftr_gpio_methods;
1031		printk(KERN_DEBUG
1032		       "snd-aoa-fabric-layout: Using direct GPIOs\n");
1033		break;
1034	default:
1035		ldev->gpio.methods = pmf_gpio_methods;
1036		printk(KERN_DEBUG
1037		       "snd-aoa-fabric-layout: Using PMF GPIOs\n");
1038	}
1039	ldev->selfptr_headphone.ptr = ldev;
1040	ldev->selfptr_lineout.ptr = ldev;
1041	dev_set_drvdata(&sdev->ofdev.dev, ldev);
1042	list_add(&ldev->list, &layouts_list);
1043	layouts_list_items++;
1044
1045	/* assign these before registering ourselves, so
1046	 * callbacks that are done during registration
1047	 * already have the values */
1048	sdev->pcmid = ldev->layout->pcmid;
1049	if (ldev->layout->busname) {
1050		sdev->pcmname = ldev->layout->busname;
1051	} else {
1052		sdev->pcmname = "Master";
1053	}
1054
1055	ldev->gpio.methods->init(&ldev->gpio);
1056
1057	err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
1058	if (err && err != -EALREADY) {
1059		printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
1060				 " another fabric is active!\n");
1061		goto outlistdel;
1062	}
1063
1064	use_layout(layout);
1065	ldev->switch_on_headphone = 1;
1066	ldev->switch_on_lineout = 1;
1067	return 0;
1068 outlistdel:
1069	/* we won't be using these then... */
1070	ldev->gpio.methods->exit(&ldev->gpio);
1071	/* reset if we didn't use it */
1072	sdev->pcmname = NULL;
1073	sdev->pcmid = -1;
1074	list_del(&ldev->list);
1075	layouts_list_items--;
1076	kfree(ldev);
1077 outnodev:
1078 	of_node_put(sound);
1079 	layout_device = NULL;
1080	return -ENODEV;
1081}
1082
1083static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
1084{
1085	struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
1086	int i;
1087
1088	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
1089		if (ldev->codecs[i]) {
1090			aoa_fabric_unlink_codec(ldev->codecs[i]);
1091		}
1092		ldev->codecs[i] = NULL;
1093	}
1094	list_del(&ldev->list);
1095	layouts_list_items--;
1096	of_node_put(ldev->sound);
1097
1098	ldev->gpio.methods->set_notify(&ldev->gpio,
1099				       AOA_NOTIFY_HEADPHONE,
1100				       NULL,
1101				       NULL);
1102	ldev->gpio.methods->set_notify(&ldev->gpio,
1103				       AOA_NOTIFY_LINE_OUT,
1104				       NULL,
1105				       NULL);
1106
1107	ldev->gpio.methods->exit(&ldev->gpio);
1108	layout_device = NULL;
1109	kfree(ldev);
1110	sdev->pcmid = -1;
1111	sdev->pcmname = NULL;
1112	return 0;
1113}
1114
1115#ifdef CONFIG_PM
1116static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
1117{
1118	struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
1119
1120	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
1121		ldev->gpio.methods->all_amps_off(&ldev->gpio);
1122
1123	return 0;
1124}
1125
1126static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
1127{
1128	struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
1129
1130	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
1131		ldev->gpio.methods->all_amps_restore(&ldev->gpio);
1132
1133	return 0;
1134}
1135#endif
1136
1137static struct soundbus_driver aoa_soundbus_driver = {
1138	.name = "snd_aoa_soundbus_drv",
1139	.owner = THIS_MODULE,
1140	.probe = aoa_fabric_layout_probe,
1141	.remove = aoa_fabric_layout_remove,
1142#ifdef CONFIG_PM
1143	.suspend = aoa_fabric_layout_suspend,
1144	.resume = aoa_fabric_layout_resume,
1145#endif
1146	.driver = {
1147		.owner = THIS_MODULE,
1148	}
1149};
1150
1151static int __init aoa_fabric_layout_init(void)
1152{
1153	int err;
1154
1155	err = soundbus_register_driver(&aoa_soundbus_driver);
1156	if (err)
1157		return err;
1158	return 0;
1159}
1160
1161static void __exit aoa_fabric_layout_exit(void)
1162{
1163	soundbus_unregister_driver(&aoa_soundbus_driver);
1164	aoa_fabric_unregister(&layout_fabric);
1165}
1166
1167module_init(aoa_fabric_layout_init);
1168module_exit(aoa_fabric_layout_exit);