Linux Audio

Check our new training course

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