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