409809600ddce1978da363f61ddd7e4ecb8c8266
[linux-drm-fsl-dcu.git] / sound / aoa / fabrics / snd-aoa-fabric-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 static int control_info(struct snd_kcontrol *kcontrol,
586                         struct snd_ctl_elem_info *uinfo)
587 {
588         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
589         uinfo->count = 1;
590         uinfo->value.integer.min = 0;
591         uinfo->value.integer.max = 1;
592         return 0;
593 }
594
595 #define AMP_CONTROL(n, description)                                     \
596 static int n##_control_get(struct snd_kcontrol *kcontrol,               \
597                            struct snd_ctl_elem_value *ucontrol)         \
598 {                                                                       \
599         struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);        \
600         if (gpio->methods && gpio->methods->get_##n)                    \
601                 ucontrol->value.integer.value[0] =                      \
602                         gpio->methods->get_##n(gpio);                   \
603         return 0;                                                       \
604 }                                                                       \
605 static int n##_control_put(struct snd_kcontrol *kcontrol,               \
606                            struct snd_ctl_elem_value *ucontrol)         \
607 {                                                                       \
608         struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);        \
609         if (gpio->methods && gpio->methods->get_##n)                    \
610                 gpio->methods->set_##n(gpio,                            \
611                         ucontrol->value.integer.value[0]);              \
612         return 1;                                                       \
613 }                                                                       \
614 static struct snd_kcontrol_new n##_ctl = {                              \
615         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                            \
616         .name = description,                                            \
617         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,                      \
618         .info = control_info,                                           \
619         .get = n##_control_get,                                         \
620         .put = n##_control_put,                                         \
621 }
622
623 AMP_CONTROL(headphone, "Headphone Switch");
624 AMP_CONTROL(speakers, "Speakers Switch");
625 AMP_CONTROL(lineout, "Line-Out Switch");
626
627 static int detect_choice_get(struct snd_kcontrol *kcontrol,
628                              struct snd_ctl_elem_value *ucontrol)
629 {
630         struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
631
632         switch (kcontrol->private_value) {
633         case 0:
634                 ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
635                 break;
636         case 1:
637                 ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
638                 break;
639         default:
640                 return -ENODEV;
641         }
642         return 0;
643 }
644
645 static int detect_choice_put(struct snd_kcontrol *kcontrol,
646                              struct snd_ctl_elem_value *ucontrol)
647 {
648         struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
649
650         switch (kcontrol->private_value) {
651         case 0:
652                 ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
653                 break;
654         case 1:
655                 ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
656                 break;
657         default:
658                 return -ENODEV;
659         }
660         return 1;
661 }
662
663 static struct snd_kcontrol_new headphone_detect_choice = {
664         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
665         .name = "Headphone Detect Autoswitch",
666         .info = control_info,
667         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
668         .get = detect_choice_get,
669         .put = detect_choice_put,
670         .private_value = 0,
671 };
672
673 static struct snd_kcontrol_new lineout_detect_choice = {
674         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
675         .name = "Line-Out Detect Autoswitch",
676         .info = control_info,
677         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
678         .get = detect_choice_get,
679         .put = detect_choice_put,
680         .private_value = 1,
681 };
682
683 static int detected_get(struct snd_kcontrol *kcontrol,
684                         struct snd_ctl_elem_value *ucontrol)
685 {
686         struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
687         int v;
688
689         switch (kcontrol->private_value) {
690         case 0:
691                 v = ldev->gpio.methods->get_detect(&ldev->gpio,
692                                                    AOA_NOTIFY_HEADPHONE);
693                 break;
694         case 1:
695                 v = ldev->gpio.methods->get_detect(&ldev->gpio,
696                                                    AOA_NOTIFY_LINE_OUT);
697                 break;
698         default:
699                 return -ENODEV;
700         }
701         ucontrol->value.integer.value[0] = v;
702         return 0;
703 }
704
705 static struct snd_kcontrol_new headphone_detected = {
706         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
707         .name = "Headphone Detected",
708         .info = control_info,
709         .access = SNDRV_CTL_ELEM_ACCESS_READ,
710         .get = detected_get,
711         .private_value = 0,
712 };
713
714 static struct snd_kcontrol_new lineout_detected = {
715         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
716         .name = "Line-Out Detected",
717         .info = control_info,
718         .access = SNDRV_CTL_ELEM_ACCESS_READ,
719         .get = detected_get,
720         .private_value = 1,
721 };
722
723 static int check_codec(struct aoa_codec *codec,
724                        struct layout_dev *ldev,
725                        struct codec_connect_info *cci)
726 {
727         u32 *ref;
728         char propname[32];
729         struct codec_connection *cc;
730
731         /* if the codec has a 'codec' node, we require a reference */
732         if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
733                 snprintf(propname, sizeof(propname),
734                          "platform-%s-codec-ref", codec->name);
735                 ref = (u32*)get_property(ldev->sound, propname, NULL);
736                 if (!ref) {
737                         printk(KERN_INFO "snd-aoa-fabric-layout: "
738                                 "required property %s not present\n", propname);
739                         return -ENODEV;
740                 }
741                 if (*ref != codec->node->linux_phandle) {
742                         printk(KERN_INFO "snd-aoa-fabric-layout: "
743                                 "%s doesn't match!\n", propname);
744                         return -ENODEV;
745                 }
746         } else {
747                 if (layouts_list_items != 1) {
748                         printk(KERN_INFO "snd-aoa-fabric-layout: "
749                                 "more than one soundbus, but no references.\n");
750                         return -ENODEV;
751                 }
752         }
753         codec->soundbus_dev = ldev->sdev;
754         codec->gpio = &ldev->gpio;
755
756         cc = cci->connections;
757         if (!cc)
758                 return -EINVAL;
759
760         printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
761
762         codec->connected = 0;
763         codec->fabric_data = cc;
764
765         while (cc->connected) {
766                 codec->connected |= 1<<cc->codec_bit;
767                 cc++;
768         }
769
770         return 0;
771 }
772
773 static int layout_found_codec(struct aoa_codec *codec)
774 {
775         struct layout_dev *ldev;
776         int i;
777
778         list_for_each_entry(ldev, &layouts_list, list) {
779                 for (i=0; i<MAX_CODECS_PER_BUS; i++) {
780                         if (!ldev->layout->codecs[i].name)
781                                 continue;
782                         if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
783                                 if (check_codec(codec,
784                                                 ldev,
785                                                 &ldev->layout->codecs[i]) == 0)
786                                         return 0;
787                         }
788                 }
789         }
790         return -ENODEV;
791 }
792
793 static void layout_remove_codec(struct aoa_codec *codec)
794 {
795         int i;
796         /* here remove the codec from the layout dev's
797          * codec reference */
798
799         codec->soundbus_dev = NULL;
800         codec->gpio = NULL;
801         for (i=0; i<MAX_CODECS_PER_BUS; i++) {
802         }
803 }
804
805 static void layout_notify(void *data)
806 {
807         struct layout_dev_ptr *dptr = data;
808         struct layout_dev *ldev;
809         int v, update;
810         struct snd_kcontrol *detected, *c;
811         struct snd_card *card = aoa_get_card();
812
813         ldev = dptr->ptr;
814         if (data == &ldev->selfptr_headphone) {
815                 v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
816                 detected = ldev->headphone_detected_ctrl;
817                 update = ldev->switch_on_headphone;
818                 if (update) {
819                         ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
820                         ldev->gpio.methods->set_headphone(&ldev->gpio, v);
821                         ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
822                 }
823         } else if (data == &ldev->selfptr_lineout) {
824                 v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
825                 detected = ldev->lineout_detected_ctrl;
826                 update = ldev->switch_on_lineout;
827                 if (update) {
828                         ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
829                         ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
830                         ldev->gpio.methods->set_lineout(&ldev->gpio, v);
831                 }
832         } else
833                 return;
834
835         if (detected)
836                 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
837         if (update) {
838                 c = ldev->headphone_ctrl;
839                 if (c)
840                         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
841                 c = ldev->speaker_ctrl;
842                 if (c)
843                         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
844                 c = ldev->lineout_ctrl;
845                 if (c)
846                         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
847         }
848 }
849
850 static void layout_attached_codec(struct aoa_codec *codec)
851 {
852         struct codec_connection *cc;
853         struct snd_kcontrol *ctl;
854         int headphones, lineout;
855         struct layout_dev *ldev = layout_device;
856
857         /* need to add this codec to our codec array! */
858
859         cc = codec->fabric_data;
860
861         headphones = codec->gpio->methods->get_detect(codec->gpio,
862                                                       AOA_NOTIFY_HEADPHONE);
863         lineout = codec->gpio->methods->get_detect(codec->gpio,
864                                                    AOA_NOTIFY_LINE_OUT);
865
866         while (cc->connected) {
867                 if (cc->connected & CC_SPEAKERS) {
868                         if (headphones <= 0 && lineout <= 0)
869                                 ldev->gpio.methods->set_speakers(codec->gpio, 1);
870                         ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
871                         ldev->speaker_ctrl = ctl;
872                         aoa_snd_ctl_add(ctl);
873                 }
874                 if (cc->connected & CC_HEADPHONE) {
875                         if (headphones == 1)
876                                 ldev->gpio.methods->set_headphone(codec->gpio, 1);
877                         ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
878                         ldev->headphone_ctrl = ctl;
879                         aoa_snd_ctl_add(ctl);
880                         ldev->have_headphone_detect =
881                                 !ldev->gpio.methods
882                                         ->set_notify(&ldev->gpio,
883                                                      AOA_NOTIFY_HEADPHONE,
884                                                      layout_notify,
885                                                      &ldev->selfptr_headphone);
886                         if (ldev->have_headphone_detect) {
887                                 ctl = snd_ctl_new1(&headphone_detect_choice,
888                                                    ldev);
889                                 aoa_snd_ctl_add(ctl);
890                                 ctl = snd_ctl_new1(&headphone_detected,
891                                                    ldev);
892                                 ldev->headphone_detected_ctrl = ctl;
893                                 aoa_snd_ctl_add(ctl);
894                         }
895                 }
896                 if (cc->connected & CC_LINEOUT) {
897                         if (lineout == 1)
898                                 ldev->gpio.methods->set_lineout(codec->gpio, 1);
899                         ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
900                         if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
901                                 strlcpy(ctl->id.name,
902                                         "Headphone Switch", sizeof(ctl->id.name));
903                         ldev->lineout_ctrl = ctl;
904                         aoa_snd_ctl_add(ctl);
905                         ldev->have_lineout_detect =
906                                 !ldev->gpio.methods
907                                         ->set_notify(&ldev->gpio,
908                                                      AOA_NOTIFY_LINE_OUT,
909                                                      layout_notify,
910                                                      &ldev->selfptr_lineout);
911                         if (ldev->have_lineout_detect) {
912                                 ctl = snd_ctl_new1(&lineout_detect_choice,
913                                                    ldev);
914                                 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
915                                         strlcpy(ctl->id.name,
916                                                 "Headphone Detect Autoswitch",
917                                                 sizeof(ctl->id.name));
918                                 aoa_snd_ctl_add(ctl);
919                                 ctl = snd_ctl_new1(&lineout_detected,
920                                                    ldev);
921                                 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
922                                         strlcpy(ctl->id.name,
923                                                 "Headphone Detected",
924                                                 sizeof(ctl->id.name));
925                                 ldev->lineout_detected_ctrl = ctl;
926                                 aoa_snd_ctl_add(ctl);
927                         }
928                 }
929                 cc++;
930         }
931         /* now update initial state */
932         if (ldev->have_headphone_detect)
933                 layout_notify(&ldev->selfptr_headphone);
934         if (ldev->have_lineout_detect)
935                 layout_notify(&ldev->selfptr_lineout);
936 }
937
938 static struct aoa_fabric layout_fabric = {
939         .name = "SoundByLayout",
940         .owner = THIS_MODULE,
941         .found_codec = layout_found_codec,
942         .remove_codec = layout_remove_codec,
943         .attached_codec = layout_attached_codec,
944 };
945
946 static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
947 {
948         struct device_node *sound = NULL;
949         unsigned int *layout_id;
950         struct layout *layout;
951         struct layout_dev *ldev = NULL;
952         int err;
953
954         /* hm, currently we can only have one ... */
955         if (layout_device)
956                 return -ENODEV;
957
958         /* by breaking out we keep a reference */
959         while ((sound = of_get_next_child(sdev->ofdev.node, sound))) {
960                 if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
961                         break;
962         }
963         if (!sound) return -ENODEV;
964
965         layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
966         if (!layout_id)
967                 goto outnodev;
968         printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
969                *layout_id);
970
971         layout = find_layout_by_id(*layout_id);
972         if (!layout) {
973                 printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
974                 goto outnodev;
975         }
976
977         ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
978         if (!ldev)
979                 goto outnodev;
980
981         layout_device = ldev;
982         ldev->sdev = sdev;
983         ldev->sound = sound;
984         ldev->layout = layout;
985         ldev->gpio.node = sound->parent;
986         switch (layout->layout_id) {
987         case 41: /* that unknown machine no one seems to have */
988         case 51: /* PowerBook5,4 */
989         case 58: /* Mac Mini */
990                 ldev->gpio.methods = ftr_gpio_methods;
991                 printk(KERN_DEBUG
992                        "snd-aoa-fabric-layout: Using direct GPIOs\n");
993                 break;
994         default:
995                 ldev->gpio.methods = pmf_gpio_methods;
996                 printk(KERN_DEBUG
997                        "snd-aoa-fabric-layout: Using PMF GPIOs\n");
998         }
999         ldev->selfptr_headphone.ptr = ldev;
1000         ldev->selfptr_lineout.ptr = ldev;
1001         sdev->ofdev.dev.driver_data = ldev;
1002         list_add(&ldev->list, &layouts_list);
1003         layouts_list_items++;
1004
1005         /* assign these before registering ourselves, so
1006          * callbacks that are done during registration
1007          * already have the values */
1008         sdev->pcmid = ldev->layout->pcmid;
1009         if (ldev->layout->busname) {
1010                 sdev->pcmname = ldev->layout->busname;
1011         } else {
1012                 sdev->pcmname = "Master";
1013         }
1014
1015         ldev->gpio.methods->init(&ldev->gpio);
1016
1017         err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
1018         if (err && err != -EALREADY) {
1019                 printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
1020                                  " another fabric is active!\n");
1021                 goto outlistdel;
1022         }
1023
1024         use_layout(layout);
1025         ldev->switch_on_headphone = 1;
1026         ldev->switch_on_lineout = 1;
1027         return 0;
1028  outlistdel:
1029         /* we won't be using these then... */
1030         ldev->gpio.methods->exit(&ldev->gpio);
1031         /* reset if we didn't use it */
1032         sdev->pcmname = NULL;
1033         sdev->pcmid = -1;
1034         list_del(&ldev->list);
1035         layouts_list_items--;
1036  outnodev:
1037         if (sound) of_node_put(sound);
1038         layout_device = NULL;
1039         if (ldev) kfree(ldev);
1040         return -ENODEV;
1041 }
1042
1043 static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
1044 {
1045         struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
1046         int i;
1047
1048         for (i=0; i<MAX_CODECS_PER_BUS; i++) {
1049                 if (ldev->codecs[i]) {
1050                         aoa_fabric_unlink_codec(ldev->codecs[i]);
1051                 }
1052                 ldev->codecs[i] = NULL;
1053         }
1054         list_del(&ldev->list);
1055         layouts_list_items--;
1056         of_node_put(ldev->sound);
1057
1058         ldev->gpio.methods->set_notify(&ldev->gpio,
1059                                        AOA_NOTIFY_HEADPHONE,
1060                                        NULL,
1061                                        NULL);
1062         ldev->gpio.methods->set_notify(&ldev->gpio,
1063                                        AOA_NOTIFY_LINE_OUT,
1064                                        NULL,
1065                                        NULL);
1066
1067         ldev->gpio.methods->exit(&ldev->gpio);
1068         layout_device = NULL;
1069         kfree(ldev);
1070         sdev->pcmid = -1;
1071         sdev->pcmname = NULL;
1072         return 0;
1073 }
1074
1075 #ifdef CONFIG_PM
1076 static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
1077 {
1078         struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
1079
1080         printk("aoa_fabric_layout_suspend()\n");
1081
1082         if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
1083                 ldev->gpio.methods->all_amps_off(&ldev->gpio);
1084
1085         return 0;
1086 }
1087
1088 static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
1089 {
1090         struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
1091
1092         printk("aoa_fabric_layout_resume()\n");
1093
1094         if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
1095                 ldev->gpio.methods->all_amps_restore(&ldev->gpio);
1096
1097         return 0;
1098 }
1099 #endif
1100
1101 static struct soundbus_driver aoa_soundbus_driver = {
1102         .name = "snd_aoa_soundbus_drv",
1103         .owner = THIS_MODULE,
1104         .probe = aoa_fabric_layout_probe,
1105         .remove = aoa_fabric_layout_remove,
1106 #ifdef CONFIG_PM
1107         .suspend = aoa_fabric_layout_suspend,
1108         .resume = aoa_fabric_layout_resume,
1109 #endif
1110         .driver = {
1111                 .owner = THIS_MODULE,
1112         }
1113 };
1114
1115 static int __init aoa_fabric_layout_init(void)
1116 {
1117         int err;
1118
1119         err = soundbus_register_driver(&aoa_soundbus_driver);
1120         if (err)
1121                 return err;
1122         return 0;
1123 }
1124
1125 static void __exit aoa_fabric_layout_exit(void)
1126 {
1127         soundbus_unregister_driver(&aoa_soundbus_driver);
1128         aoa_fabric_unregister(&layout_fabric);
1129 }
1130
1131 module_init(aoa_fabric_layout_init);
1132 module_exit(aoa_fabric_layout_exit);