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