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