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