Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Apple Onboard Audio driver -- layout/machine id fabric
0004  *
0005  * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
0006  *
0007  * This fabric module looks for sound codecs based on the
0008  * layout-id or device-id property in the device tree.
0009  */
0010 #include <asm/prom.h>
0011 #include <linux/list.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include "../aoa.h"
0015 #include "../soundbus/soundbus.h"
0016 
0017 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
0018 MODULE_LICENSE("GPL");
0019 MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa");
0020 
0021 #define MAX_CODECS_PER_BUS  2
0022 
0023 /* These are the connections the layout fabric
0024  * knows about. It doesn't really care about the
0025  * input ones, but I thought I'd separate them
0026  * to give them proper names. The thing is that
0027  * Apple usually will distinguish the active output
0028  * by GPIOs, while the active input is set directly
0029  * on the codec. Hence we here tell the codec what
0030  * we think is connected. This information is hard-
0031  * coded below ... */
0032 #define CC_SPEAKERS (1<<0)
0033 #define CC_HEADPHONE    (1<<1)
0034 #define CC_LINEOUT  (1<<2)
0035 #define CC_DIGITALOUT   (1<<3)
0036 #define CC_LINEIN   (1<<4)
0037 #define CC_MICROPHONE   (1<<5)
0038 #define CC_DIGITALIN    (1<<6)
0039 /* pretty bogus but users complain...
0040  * This is a flag saying that the LINEOUT
0041  * should be renamed to HEADPHONE.
0042  * be careful with input detection! */
0043 #define CC_LINEOUT_LABELLED_HEADPHONE   (1<<7)
0044 
0045 struct codec_connection {
0046     /* CC_ flags from above */
0047     int connected;
0048     /* codec dependent bit to be set in the aoa_codec.connected field.
0049      * This intentionally doesn't have any generic flags because the
0050      * fabric has to know the codec anyway and all codecs might have
0051      * different connectors */
0052     int codec_bit;
0053 };
0054 
0055 struct codec_connect_info {
0056     char *name;
0057     struct codec_connection *connections;
0058 };
0059 
0060 #define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
0061 
0062 struct layout {
0063     unsigned int layout_id, device_id;
0064     struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
0065     int flags;
0066 
0067     /* if busname is not assigned, we use 'Master' below,
0068      * so that our layout table doesn't need to be filled
0069      * too much.
0070      * We only assign these two if we expect to find more
0071      * than one soundbus, i.e. on those machines with
0072      * multiple layout-ids */
0073     char *busname;
0074     int pcmid;
0075 };
0076 
0077 MODULE_ALIAS("sound-layout-36");
0078 MODULE_ALIAS("sound-layout-41");
0079 MODULE_ALIAS("sound-layout-45");
0080 MODULE_ALIAS("sound-layout-47");
0081 MODULE_ALIAS("sound-layout-48");
0082 MODULE_ALIAS("sound-layout-49");
0083 MODULE_ALIAS("sound-layout-50");
0084 MODULE_ALIAS("sound-layout-51");
0085 MODULE_ALIAS("sound-layout-56");
0086 MODULE_ALIAS("sound-layout-57");
0087 MODULE_ALIAS("sound-layout-58");
0088 MODULE_ALIAS("sound-layout-60");
0089 MODULE_ALIAS("sound-layout-61");
0090 MODULE_ALIAS("sound-layout-62");
0091 MODULE_ALIAS("sound-layout-64");
0092 MODULE_ALIAS("sound-layout-65");
0093 MODULE_ALIAS("sound-layout-66");
0094 MODULE_ALIAS("sound-layout-67");
0095 MODULE_ALIAS("sound-layout-68");
0096 MODULE_ALIAS("sound-layout-69");
0097 MODULE_ALIAS("sound-layout-70");
0098 MODULE_ALIAS("sound-layout-72");
0099 MODULE_ALIAS("sound-layout-76");
0100 MODULE_ALIAS("sound-layout-80");
0101 MODULE_ALIAS("sound-layout-82");
0102 MODULE_ALIAS("sound-layout-84");
0103 MODULE_ALIAS("sound-layout-86");
0104 MODULE_ALIAS("sound-layout-90");
0105 MODULE_ALIAS("sound-layout-92");
0106 MODULE_ALIAS("sound-layout-94");
0107 MODULE_ALIAS("sound-layout-96");
0108 MODULE_ALIAS("sound-layout-98");
0109 MODULE_ALIAS("sound-layout-100");
0110 
0111 MODULE_ALIAS("aoa-device-id-14");
0112 MODULE_ALIAS("aoa-device-id-22");
0113 MODULE_ALIAS("aoa-device-id-31");
0114 MODULE_ALIAS("aoa-device-id-35");
0115 MODULE_ALIAS("aoa-device-id-44");
0116 
0117 /* onyx with all but microphone connected */
0118 static struct codec_connection onyx_connections_nomic[] = {
0119     {
0120         .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
0121         .codec_bit = 0,
0122     },
0123     {
0124         .connected = CC_DIGITALOUT,
0125         .codec_bit = 1,
0126     },
0127     {
0128         .connected = CC_LINEIN,
0129         .codec_bit = 2,
0130     },
0131     {} /* terminate array by .connected == 0 */
0132 };
0133 
0134 /* onyx on machines without headphone */
0135 static struct codec_connection onyx_connections_noheadphones[] = {
0136     {
0137         .connected = CC_SPEAKERS | CC_LINEOUT |
0138                  CC_LINEOUT_LABELLED_HEADPHONE,
0139         .codec_bit = 0,
0140     },
0141     {
0142         .connected = CC_DIGITALOUT,
0143         .codec_bit = 1,
0144     },
0145     /* FIXME: are these correct? probably not for all the machines
0146      * below ... If not this will need separating. */
0147     {
0148         .connected = CC_LINEIN,
0149         .codec_bit = 2,
0150     },
0151     {
0152         .connected = CC_MICROPHONE,
0153         .codec_bit = 3,
0154     },
0155     {} /* terminate array by .connected == 0 */
0156 };
0157 
0158 /* onyx on machines with real line-out */
0159 static struct codec_connection onyx_connections_reallineout[] = {
0160     {
0161         .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
0162         .codec_bit = 0,
0163     },
0164     {
0165         .connected = CC_DIGITALOUT,
0166         .codec_bit = 1,
0167     },
0168     {
0169         .connected = CC_LINEIN,
0170         .codec_bit = 2,
0171     },
0172     {} /* terminate array by .connected == 0 */
0173 };
0174 
0175 /* tas on machines without line out */
0176 static struct codec_connection tas_connections_nolineout[] = {
0177     {
0178         .connected = CC_SPEAKERS | CC_HEADPHONE,
0179         .codec_bit = 0,
0180     },
0181     {
0182         .connected = CC_LINEIN,
0183         .codec_bit = 2,
0184     },
0185     {
0186         .connected = CC_MICROPHONE,
0187         .codec_bit = 3,
0188     },
0189     {} /* terminate array by .connected == 0 */
0190 };
0191 
0192 /* tas on machines with neither line out nor line in */
0193 static struct codec_connection tas_connections_noline[] = {
0194     {
0195         .connected = CC_SPEAKERS | CC_HEADPHONE,
0196         .codec_bit = 0,
0197     },
0198     {
0199         .connected = CC_MICROPHONE,
0200         .codec_bit = 3,
0201     },
0202     {} /* terminate array by .connected == 0 */
0203 };
0204 
0205 /* tas on machines without microphone */
0206 static struct codec_connection tas_connections_nomic[] = {
0207     {
0208         .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
0209         .codec_bit = 0,
0210     },
0211     {
0212         .connected = CC_LINEIN,
0213         .codec_bit = 2,
0214     },
0215     {} /* terminate array by .connected == 0 */
0216 };
0217 
0218 /* tas on machines with everything connected */
0219 static struct codec_connection tas_connections_all[] = {
0220     {
0221         .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
0222         .codec_bit = 0,
0223     },
0224     {
0225         .connected = CC_LINEIN,
0226         .codec_bit = 2,
0227     },
0228     {
0229         .connected = CC_MICROPHONE,
0230         .codec_bit = 3,
0231     },
0232     {} /* terminate array by .connected == 0 */
0233 };
0234 
0235 static struct codec_connection toonie_connections[] = {
0236     {
0237         .connected = CC_SPEAKERS | CC_HEADPHONE,
0238         .codec_bit = 0,
0239     },
0240     {} /* terminate array by .connected == 0 */
0241 };
0242 
0243 static struct codec_connection topaz_input[] = {
0244     {
0245         .connected = CC_DIGITALIN,
0246         .codec_bit = 0,
0247     },
0248     {} /* terminate array by .connected == 0 */
0249 };
0250 
0251 static struct codec_connection topaz_output[] = {
0252     {
0253         .connected = CC_DIGITALOUT,
0254         .codec_bit = 1,
0255     },
0256     {} /* terminate array by .connected == 0 */
0257 };
0258 
0259 static struct codec_connection topaz_inout[] = {
0260     {
0261         .connected = CC_DIGITALIN,
0262         .codec_bit = 0,
0263     },
0264     {
0265         .connected = CC_DIGITALOUT,
0266         .codec_bit = 1,
0267     },
0268     {} /* terminate array by .connected == 0 */
0269 };
0270 
0271 static struct layout layouts[] = {
0272     /* last PowerBooks (15" Oct 2005) */
0273     { .layout_id = 82,
0274       .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
0275       .codecs[0] = {
0276         .name = "onyx",
0277         .connections = onyx_connections_noheadphones,
0278       },
0279       .codecs[1] = {
0280         .name = "topaz",
0281         .connections = topaz_input,
0282       },
0283     },
0284     /* PowerMac9,1 */
0285     { .layout_id = 60,
0286       .codecs[0] = {
0287         .name = "onyx",
0288         .connections = onyx_connections_reallineout,
0289       },
0290     },
0291     /* PowerMac9,1 */
0292     { .layout_id = 61,
0293       .codecs[0] = {
0294         .name = "topaz",
0295         .connections = topaz_input,
0296       },
0297     },
0298     /* PowerBook5,7 */
0299     { .layout_id = 64,
0300       .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
0301       .codecs[0] = {
0302         .name = "onyx",
0303         .connections = onyx_connections_noheadphones,
0304       },
0305     },
0306     /* PowerBook5,7 */
0307     { .layout_id = 65,
0308       .codecs[0] = {
0309         .name = "topaz",
0310         .connections = topaz_input,
0311       },
0312     },
0313     /* PowerBook5,9 [17" Oct 2005] */
0314     { .layout_id = 84,
0315       .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
0316       .codecs[0] = {
0317         .name = "onyx",
0318         .connections = onyx_connections_noheadphones,
0319       },
0320       .codecs[1] = {
0321         .name = "topaz",
0322         .connections = topaz_input,
0323       },
0324     },
0325     /* PowerMac8,1 */
0326     { .layout_id = 45,
0327       .codecs[0] = {
0328         .name = "onyx",
0329         .connections = onyx_connections_noheadphones,
0330       },
0331       .codecs[1] = {
0332         .name = "topaz",
0333         .connections = topaz_input,
0334       },
0335     },
0336     /* Quad PowerMac (analog in, analog/digital out) */
0337     { .layout_id = 68,
0338       .codecs[0] = {
0339         .name = "onyx",
0340         .connections = onyx_connections_nomic,
0341       },
0342     },
0343     /* Quad PowerMac (digital in) */
0344     { .layout_id = 69,
0345       .codecs[0] = {
0346         .name = "topaz",
0347         .connections = topaz_input,
0348       },
0349       .busname = "digital in", .pcmid = 1 },
0350     /* Early 2005 PowerBook (PowerBook 5,6) */
0351     { .layout_id = 70,
0352       .codecs[0] = {
0353         .name = "tas",
0354         .connections = tas_connections_nolineout,
0355       },
0356     },
0357     /* PowerBook 5,4 */
0358     { .layout_id = 51,
0359       .codecs[0] = {
0360         .name = "tas",
0361         .connections = tas_connections_nolineout,
0362       },
0363     },
0364     /* PowerBook6,1 */
0365     { .device_id = 31,
0366       .codecs[0] = {
0367         .name = "tas",
0368         .connections = tas_connections_nolineout,
0369       },
0370     },
0371     /* PowerBook6,5 */
0372     { .device_id = 44,
0373       .codecs[0] = {
0374         .name = "tas",
0375         .connections = tas_connections_all,
0376       },
0377     },
0378     /* PowerBook6,7 */
0379     { .layout_id = 80,
0380       .codecs[0] = {
0381         .name = "tas",
0382         .connections = tas_connections_noline,
0383       },
0384     },
0385     /* PowerBook6,8 */
0386     { .layout_id = 72,
0387       .codecs[0] = {
0388         .name = "tas",
0389         .connections = tas_connections_nolineout,
0390       },
0391     },
0392     /* PowerMac8,2 */
0393     { .layout_id = 86,
0394       .codecs[0] = {
0395         .name = "onyx",
0396         .connections = onyx_connections_nomic,
0397       },
0398       .codecs[1] = {
0399         .name = "topaz",
0400         .connections = topaz_input,
0401       },
0402     },
0403     /* PowerBook6,7 */
0404     { .layout_id = 92,
0405       .codecs[0] = {
0406         .name = "tas",
0407         .connections = tas_connections_nolineout,
0408       },
0409     },
0410     /* PowerMac10,1 (Mac Mini) */
0411     { .layout_id = 58,
0412       .codecs[0] = {
0413         .name = "toonie",
0414         .connections = toonie_connections,
0415       },
0416     },
0417     {
0418       .layout_id = 96,
0419       .codecs[0] = {
0420         .name = "onyx",
0421         .connections = onyx_connections_noheadphones,
0422       },
0423     },
0424     /* unknown, untested, but this comes from Apple */
0425     { .layout_id = 41,
0426       .codecs[0] = {
0427         .name = "tas",
0428         .connections = tas_connections_all,
0429       },
0430     },
0431     { .layout_id = 36,
0432       .codecs[0] = {
0433         .name = "tas",
0434         .connections = tas_connections_nomic,
0435       },
0436       .codecs[1] = {
0437         .name = "topaz",
0438         .connections = topaz_inout,
0439       },
0440     },
0441     { .layout_id = 47,
0442       .codecs[0] = {
0443         .name = "onyx",
0444         .connections = onyx_connections_noheadphones,
0445       },
0446     },
0447     { .layout_id = 48,
0448       .codecs[0] = {
0449         .name = "topaz",
0450         .connections = topaz_input,
0451       },
0452     },
0453     { .layout_id = 49,
0454       .codecs[0] = {
0455         .name = "onyx",
0456         .connections = onyx_connections_nomic,
0457       },
0458     },
0459     { .layout_id = 50,
0460       .codecs[0] = {
0461         .name = "topaz",
0462         .connections = topaz_input,
0463       },
0464     },
0465     { .layout_id = 56,
0466       .codecs[0] = {
0467         .name = "onyx",
0468         .connections = onyx_connections_noheadphones,
0469       },
0470     },
0471     { .layout_id = 57,
0472       .codecs[0] = {
0473         .name = "topaz",
0474         .connections = topaz_input,
0475       },
0476     },
0477     { .layout_id = 62,
0478       .codecs[0] = {
0479         .name = "onyx",
0480         .connections = onyx_connections_noheadphones,
0481       },
0482       .codecs[1] = {
0483         .name = "topaz",
0484         .connections = topaz_output,
0485       },
0486     },
0487     { .layout_id = 66,
0488       .codecs[0] = {
0489         .name = "onyx",
0490         .connections = onyx_connections_noheadphones,
0491       },
0492     },
0493     { .layout_id = 67,
0494       .codecs[0] = {
0495         .name = "topaz",
0496         .connections = topaz_input,
0497       },
0498     },
0499     { .layout_id = 76,
0500       .codecs[0] = {
0501         .name = "tas",
0502         .connections = tas_connections_nomic,
0503       },
0504       .codecs[1] = {
0505         .name = "topaz",
0506         .connections = topaz_inout,
0507       },
0508     },
0509     { .layout_id = 90,
0510       .codecs[0] = {
0511         .name = "tas",
0512         .connections = tas_connections_noline,
0513       },
0514     },
0515     { .layout_id = 94,
0516       .codecs[0] = {
0517         .name = "onyx",
0518         /* but it has an external mic?? how to select? */
0519         .connections = onyx_connections_noheadphones,
0520       },
0521     },
0522     { .layout_id = 98,
0523       .codecs[0] = {
0524         .name = "toonie",
0525         .connections = toonie_connections,
0526       },
0527     },
0528     { .layout_id = 100,
0529       .codecs[0] = {
0530         .name = "topaz",
0531         .connections = topaz_input,
0532       },
0533       .codecs[1] = {
0534         .name = "onyx",
0535         .connections = onyx_connections_noheadphones,
0536       },
0537     },
0538     /* PowerMac3,4 */
0539     { .device_id = 14,
0540       .codecs[0] = {
0541         .name = "tas",
0542         .connections = tas_connections_noline,
0543       },
0544     },
0545     /* PowerMac3,6 */
0546     { .device_id = 22,
0547       .codecs[0] = {
0548         .name = "tas",
0549         .connections = tas_connections_all,
0550       },
0551     },
0552     /* PowerBook5,2 */
0553     { .device_id = 35,
0554       .codecs[0] = {
0555         .name = "tas",
0556         .connections = tas_connections_all,
0557       },
0558     },
0559     {}
0560 };
0561 
0562 static struct layout *find_layout_by_id(unsigned int id)
0563 {
0564     struct layout *l;
0565 
0566     l = layouts;
0567     while (l->codecs[0].name) {
0568         if (l->layout_id == id)
0569             return l;
0570         l++;
0571     }
0572     return NULL;
0573 }
0574 
0575 static struct layout *find_layout_by_device(unsigned int id)
0576 {
0577     struct layout *l;
0578 
0579     l = layouts;
0580     while (l->codecs[0].name) {
0581         if (l->device_id == id)
0582             return l;
0583         l++;
0584     }
0585     return NULL;
0586 }
0587 
0588 static void use_layout(struct layout *l)
0589 {
0590     int i;
0591 
0592     for (i=0; i<MAX_CODECS_PER_BUS; i++) {
0593         if (l->codecs[i].name) {
0594             request_module("snd-aoa-codec-%s", l->codecs[i].name);
0595         }
0596     }
0597     /* now we wait for the codecs to call us back */
0598 }
0599 
0600 struct layout_dev;
0601 
0602 struct layout_dev_ptr {
0603     struct layout_dev *ptr;
0604 };
0605 
0606 struct layout_dev {
0607     struct list_head list;
0608     struct soundbus_dev *sdev;
0609     struct device_node *sound;
0610     struct aoa_codec *codecs[MAX_CODECS_PER_BUS];
0611     struct layout *layout;
0612     struct gpio_runtime gpio;
0613 
0614     /* we need these for headphone/lineout detection */
0615     struct snd_kcontrol *headphone_ctrl;
0616     struct snd_kcontrol *lineout_ctrl;
0617     struct snd_kcontrol *speaker_ctrl;
0618     struct snd_kcontrol *master_ctrl;
0619     struct snd_kcontrol *headphone_detected_ctrl;
0620     struct snd_kcontrol *lineout_detected_ctrl;
0621 
0622     struct layout_dev_ptr selfptr_headphone;
0623     struct layout_dev_ptr selfptr_lineout;
0624 
0625     u32 have_lineout_detect:1,
0626         have_headphone_detect:1,
0627         switch_on_headphone:1,
0628         switch_on_lineout:1;
0629 };
0630 
0631 static LIST_HEAD(layouts_list);
0632 static int layouts_list_items;
0633 /* this can go away but only if we allow multiple cards,
0634  * make the fabric handle all the card stuff, etc... */
0635 static struct layout_dev *layout_device;
0636 
0637 #define control_info    snd_ctl_boolean_mono_info
0638 
0639 #define AMP_CONTROL(n, description)                 \
0640 static int n##_control_get(struct snd_kcontrol *kcontrol,       \
0641                struct snd_ctl_elem_value *ucontrol)     \
0642 {                                   \
0643     struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);    \
0644     if (gpio->methods && gpio->methods->get_##n)            \
0645         ucontrol->value.integer.value[0] =          \
0646             gpio->methods->get_##n(gpio);           \
0647     return 0;                           \
0648 }                                   \
0649 static int n##_control_put(struct snd_kcontrol *kcontrol,       \
0650                struct snd_ctl_elem_value *ucontrol)     \
0651 {                                   \
0652     struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);    \
0653     if (gpio->methods && gpio->methods->set_##n)            \
0654         gpio->methods->set_##n(gpio,                \
0655             !!ucontrol->value.integer.value[0]);        \
0656     return 1;                           \
0657 }                                   \
0658 static const struct snd_kcontrol_new n##_ctl = {            \
0659     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                \
0660     .name = description,                        \
0661     .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,                      \
0662     .info = control_info,                       \
0663     .get = n##_control_get,                     \
0664     .put = n##_control_put,                     \
0665 }
0666 
0667 AMP_CONTROL(headphone, "Headphone Switch");
0668 AMP_CONTROL(speakers, "Speakers Switch");
0669 AMP_CONTROL(lineout, "Line-Out Switch");
0670 AMP_CONTROL(master, "Master Switch");
0671 
0672 static int detect_choice_get(struct snd_kcontrol *kcontrol,
0673                  struct snd_ctl_elem_value *ucontrol)
0674 {
0675     struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
0676 
0677     switch (kcontrol->private_value) {
0678     case 0:
0679         ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
0680         break;
0681     case 1:
0682         ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
0683         break;
0684     default:
0685         return -ENODEV;
0686     }
0687     return 0;
0688 }
0689 
0690 static int detect_choice_put(struct snd_kcontrol *kcontrol,
0691                  struct snd_ctl_elem_value *ucontrol)
0692 {
0693     struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
0694 
0695     switch (kcontrol->private_value) {
0696     case 0:
0697         ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
0698         break;
0699     case 1:
0700         ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
0701         break;
0702     default:
0703         return -ENODEV;
0704     }
0705     return 1;
0706 }
0707 
0708 static const struct snd_kcontrol_new headphone_detect_choice = {
0709     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0710     .name = "Headphone Detect Autoswitch",
0711     .info = control_info,
0712     .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0713     .get = detect_choice_get,
0714     .put = detect_choice_put,
0715     .private_value = 0,
0716 };
0717 
0718 static const struct snd_kcontrol_new lineout_detect_choice = {
0719     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0720     .name = "Line-Out Detect Autoswitch",
0721     .info = control_info,
0722     .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0723     .get = detect_choice_get,
0724     .put = detect_choice_put,
0725     .private_value = 1,
0726 };
0727 
0728 static int detected_get(struct snd_kcontrol *kcontrol,
0729             struct snd_ctl_elem_value *ucontrol)
0730 {
0731     struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
0732     int v;
0733 
0734     switch (kcontrol->private_value) {
0735     case 0:
0736         v = ldev->gpio.methods->get_detect(&ldev->gpio,
0737                            AOA_NOTIFY_HEADPHONE);
0738         break;
0739     case 1:
0740         v = ldev->gpio.methods->get_detect(&ldev->gpio,
0741                            AOA_NOTIFY_LINE_OUT);
0742         break;
0743     default:
0744         return -ENODEV;
0745     }
0746     ucontrol->value.integer.value[0] = v;
0747     return 0;
0748 }
0749 
0750 static const struct snd_kcontrol_new headphone_detected = {
0751     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0752     .name = "Headphone Detected",
0753     .info = control_info,
0754     .access = SNDRV_CTL_ELEM_ACCESS_READ,
0755     .get = detected_get,
0756     .private_value = 0,
0757 };
0758 
0759 static const struct snd_kcontrol_new lineout_detected = {
0760     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0761     .name = "Line-Out Detected",
0762     .info = control_info,
0763     .access = SNDRV_CTL_ELEM_ACCESS_READ,
0764     .get = detected_get,
0765     .private_value = 1,
0766 };
0767 
0768 static int check_codec(struct aoa_codec *codec,
0769                struct layout_dev *ldev,
0770                struct codec_connect_info *cci)
0771 {
0772     const u32 *ref;
0773     char propname[32];
0774     struct codec_connection *cc;
0775 
0776     /* if the codec has a 'codec' node, we require a reference */
0777     if (of_node_name_eq(codec->node, "codec")) {
0778         snprintf(propname, sizeof(propname),
0779              "platform-%s-codec-ref", codec->name);
0780         ref = of_get_property(ldev->sound, propname, NULL);
0781         if (!ref) {
0782             printk(KERN_INFO "snd-aoa-fabric-layout: "
0783                 "required property %s not present\n", propname);
0784             return -ENODEV;
0785         }
0786         if (*ref != codec->node->phandle) {
0787             printk(KERN_INFO "snd-aoa-fabric-layout: "
0788                 "%s doesn't match!\n", propname);
0789             return -ENODEV;
0790         }
0791     } else {
0792         if (layouts_list_items != 1) {
0793             printk(KERN_INFO "snd-aoa-fabric-layout: "
0794                 "more than one soundbus, but no references.\n");
0795             return -ENODEV;
0796         }
0797     }
0798     codec->soundbus_dev = ldev->sdev;
0799     codec->gpio = &ldev->gpio;
0800 
0801     cc = cci->connections;
0802     if (!cc)
0803         return -EINVAL;
0804 
0805     printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
0806 
0807     codec->connected = 0;
0808     codec->fabric_data = cc;
0809 
0810     while (cc->connected) {
0811         codec->connected |= 1<<cc->codec_bit;
0812         cc++;
0813     }
0814 
0815     return 0;
0816 }
0817 
0818 static int layout_found_codec(struct aoa_codec *codec)
0819 {
0820     struct layout_dev *ldev;
0821     int i;
0822 
0823     list_for_each_entry(ldev, &layouts_list, list) {
0824         for (i=0; i<MAX_CODECS_PER_BUS; i++) {
0825             if (!ldev->layout->codecs[i].name)
0826                 continue;
0827             if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
0828                 if (check_codec(codec,
0829                         ldev,
0830                         &ldev->layout->codecs[i]) == 0)
0831                     return 0;
0832             }
0833         }
0834     }
0835     return -ENODEV;
0836 }
0837 
0838 static void layout_remove_codec(struct aoa_codec *codec)
0839 {
0840     int i;
0841     /* here remove the codec from the layout dev's
0842      * codec reference */
0843 
0844     codec->soundbus_dev = NULL;
0845     codec->gpio = NULL;
0846     for (i=0; i<MAX_CODECS_PER_BUS; i++) {
0847     }
0848 }
0849 
0850 static void layout_notify(void *data)
0851 {
0852     struct layout_dev_ptr *dptr = data;
0853     struct layout_dev *ldev;
0854     int v, update;
0855     struct snd_kcontrol *detected, *c;
0856     struct snd_card *card = aoa_get_card();
0857 
0858     ldev = dptr->ptr;
0859     if (data == &ldev->selfptr_headphone) {
0860         v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
0861         detected = ldev->headphone_detected_ctrl;
0862         update = ldev->switch_on_headphone;
0863         if (update) {
0864             ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
0865             ldev->gpio.methods->set_headphone(&ldev->gpio, v);
0866             ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
0867         }
0868     } else if (data == &ldev->selfptr_lineout) {
0869         v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
0870         detected = ldev->lineout_detected_ctrl;
0871         update = ldev->switch_on_lineout;
0872         if (update) {
0873             ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
0874             ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
0875             ldev->gpio.methods->set_lineout(&ldev->gpio, v);
0876         }
0877     } else
0878         return;
0879 
0880     if (detected)
0881         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
0882     if (update) {
0883         c = ldev->headphone_ctrl;
0884         if (c)
0885             snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
0886         c = ldev->speaker_ctrl;
0887         if (c)
0888             snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
0889         c = ldev->lineout_ctrl;
0890         if (c)
0891             snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
0892     }
0893 }
0894 
0895 static void layout_attached_codec(struct aoa_codec *codec)
0896 {
0897     struct codec_connection *cc;
0898     struct snd_kcontrol *ctl;
0899     int headphones, lineout;
0900     struct layout_dev *ldev = layout_device;
0901 
0902     /* need to add this codec to our codec array! */
0903 
0904     cc = codec->fabric_data;
0905 
0906     headphones = codec->gpio->methods->get_detect(codec->gpio,
0907                               AOA_NOTIFY_HEADPHONE);
0908     lineout = codec->gpio->methods->get_detect(codec->gpio,
0909                            AOA_NOTIFY_LINE_OUT);
0910 
0911     if (codec->gpio->methods->set_master) {
0912         ctl = snd_ctl_new1(&master_ctl, codec->gpio);
0913         ldev->master_ctrl = ctl;
0914         aoa_snd_ctl_add(ctl);
0915     }
0916     while (cc->connected) {
0917         if (cc->connected & CC_SPEAKERS) {
0918             if (headphones <= 0 && lineout <= 0)
0919                 ldev->gpio.methods->set_speakers(codec->gpio, 1);
0920             ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
0921             ldev->speaker_ctrl = ctl;
0922             aoa_snd_ctl_add(ctl);
0923         }
0924         if (cc->connected & CC_HEADPHONE) {
0925             if (headphones == 1)
0926                 ldev->gpio.methods->set_headphone(codec->gpio, 1);
0927             ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
0928             ldev->headphone_ctrl = ctl;
0929             aoa_snd_ctl_add(ctl);
0930             ldev->have_headphone_detect =
0931                 !ldev->gpio.methods
0932                     ->set_notify(&ldev->gpio,
0933                              AOA_NOTIFY_HEADPHONE,
0934                              layout_notify,
0935                              &ldev->selfptr_headphone);
0936             if (ldev->have_headphone_detect) {
0937                 ctl = snd_ctl_new1(&headphone_detect_choice,
0938                            ldev);
0939                 aoa_snd_ctl_add(ctl);
0940                 ctl = snd_ctl_new1(&headphone_detected,
0941                            ldev);
0942                 ldev->headphone_detected_ctrl = ctl;
0943                 aoa_snd_ctl_add(ctl);
0944             }
0945         }
0946         if (cc->connected & CC_LINEOUT) {
0947             if (lineout == 1)
0948                 ldev->gpio.methods->set_lineout(codec->gpio, 1);
0949             ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
0950             if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
0951                 strscpy(ctl->id.name,
0952                     "Headphone Switch", sizeof(ctl->id.name));
0953             ldev->lineout_ctrl = ctl;
0954             aoa_snd_ctl_add(ctl);
0955             ldev->have_lineout_detect =
0956                 !ldev->gpio.methods
0957                     ->set_notify(&ldev->gpio,
0958                              AOA_NOTIFY_LINE_OUT,
0959                              layout_notify,
0960                              &ldev->selfptr_lineout);
0961             if (ldev->have_lineout_detect) {
0962                 ctl = snd_ctl_new1(&lineout_detect_choice,
0963                            ldev);
0964                 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
0965                     strscpy(ctl->id.name,
0966                         "Headphone Detect Autoswitch",
0967                         sizeof(ctl->id.name));
0968                 aoa_snd_ctl_add(ctl);
0969                 ctl = snd_ctl_new1(&lineout_detected,
0970                            ldev);
0971                 if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
0972                     strscpy(ctl->id.name,
0973                         "Headphone Detected",
0974                         sizeof(ctl->id.name));
0975                 ldev->lineout_detected_ctrl = ctl;
0976                 aoa_snd_ctl_add(ctl);
0977             }
0978         }
0979         cc++;
0980     }
0981     /* now update initial state */
0982     if (ldev->have_headphone_detect)
0983         layout_notify(&ldev->selfptr_headphone);
0984     if (ldev->have_lineout_detect)
0985         layout_notify(&ldev->selfptr_lineout);
0986 }
0987 
0988 static struct aoa_fabric layout_fabric = {
0989     .name = "SoundByLayout",
0990     .owner = THIS_MODULE,
0991     .found_codec = layout_found_codec,
0992     .remove_codec = layout_remove_codec,
0993     .attached_codec = layout_attached_codec,
0994 };
0995 
0996 static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
0997 {
0998     struct device_node *sound = NULL;
0999     const unsigned int *id;
1000     struct layout *layout = NULL;
1001     struct layout_dev *ldev = NULL;
1002     int err;
1003 
1004     /* hm, currently we can only have one ... */
1005     if (layout_device)
1006         return -ENODEV;
1007 
1008     /* by breaking out we keep a reference */
1009     for_each_child_of_node(sdev->ofdev.dev.of_node, sound) {
1010         if (of_node_is_type(sound, "soundchip"))
1011             break;
1012     }
1013     if (!sound)
1014         return -ENODEV;
1015 
1016     id = of_get_property(sound, "layout-id", NULL);
1017     if (id) {
1018         layout = find_layout_by_id(*id);
1019     } else {
1020         id = of_get_property(sound, "device-id", NULL);
1021         if (id)
1022             layout = find_layout_by_device(*id);
1023     }
1024 
1025     if (!layout) {
1026         printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
1027         goto outnodev;
1028     }
1029 
1030     ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
1031     if (!ldev)
1032         goto outnodev;
1033 
1034     layout_device = ldev;
1035     ldev->sdev = sdev;
1036     ldev->sound = sound;
1037     ldev->layout = layout;
1038     ldev->gpio.node = sound->parent;
1039     switch (layout->layout_id) {
1040     case 0:  /* anything with device_id, not layout_id */
1041     case 41: /* that unknown machine no one seems to have */
1042     case 51: /* PowerBook5,4 */
1043     case 58: /* Mac Mini */
1044         ldev->gpio.methods = ftr_gpio_methods;
1045         printk(KERN_DEBUG
1046                "snd-aoa-fabric-layout: Using direct GPIOs\n");
1047         break;
1048     default:
1049         ldev->gpio.methods = pmf_gpio_methods;
1050         printk(KERN_DEBUG
1051                "snd-aoa-fabric-layout: Using PMF GPIOs\n");
1052     }
1053     ldev->selfptr_headphone.ptr = ldev;
1054     ldev->selfptr_lineout.ptr = ldev;
1055     dev_set_drvdata(&sdev->ofdev.dev, ldev);
1056     list_add(&ldev->list, &layouts_list);
1057     layouts_list_items++;
1058 
1059     /* assign these before registering ourselves, so
1060      * callbacks that are done during registration
1061      * already have the values */
1062     sdev->pcmid = ldev->layout->pcmid;
1063     if (ldev->layout->busname) {
1064         sdev->pcmname = ldev->layout->busname;
1065     } else {
1066         sdev->pcmname = "Master";
1067     }
1068 
1069     ldev->gpio.methods->init(&ldev->gpio);
1070 
1071     err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
1072     if (err && err != -EALREADY) {
1073         printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
1074                  " another fabric is active!\n");
1075         goto outlistdel;
1076     }
1077 
1078     use_layout(layout);
1079     ldev->switch_on_headphone = 1;
1080     ldev->switch_on_lineout = 1;
1081     return 0;
1082  outlistdel:
1083     /* we won't be using these then... */
1084     ldev->gpio.methods->exit(&ldev->gpio);
1085     /* reset if we didn't use it */
1086     sdev->pcmname = NULL;
1087     sdev->pcmid = -1;
1088     list_del(&ldev->list);
1089     layouts_list_items--;
1090     kfree(ldev);
1091  outnodev:
1092     of_node_put(sound);
1093     layout_device = NULL;
1094     return -ENODEV;
1095 }
1096 
1097 static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
1098 {
1099     struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
1100     int i;
1101 
1102     for (i=0; i<MAX_CODECS_PER_BUS; i++) {
1103         if (ldev->codecs[i]) {
1104             aoa_fabric_unlink_codec(ldev->codecs[i]);
1105         }
1106         ldev->codecs[i] = NULL;
1107     }
1108     list_del(&ldev->list);
1109     layouts_list_items--;
1110     of_node_put(ldev->sound);
1111 
1112     ldev->gpio.methods->set_notify(&ldev->gpio,
1113                        AOA_NOTIFY_HEADPHONE,
1114                        NULL,
1115                        NULL);
1116     ldev->gpio.methods->set_notify(&ldev->gpio,
1117                        AOA_NOTIFY_LINE_OUT,
1118                        NULL,
1119                        NULL);
1120 
1121     ldev->gpio.methods->exit(&ldev->gpio);
1122     layout_device = NULL;
1123     kfree(ldev);
1124     sdev->pcmid = -1;
1125     sdev->pcmname = NULL;
1126     return 0;
1127 }
1128 
1129 #ifdef CONFIG_PM_SLEEP
1130 static int aoa_fabric_layout_suspend(struct device *dev)
1131 {
1132     struct layout_dev *ldev = dev_get_drvdata(dev);
1133 
1134     if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
1135         ldev->gpio.methods->all_amps_off(&ldev->gpio);
1136 
1137     return 0;
1138 }
1139 
1140 static int aoa_fabric_layout_resume(struct device *dev)
1141 {
1142     struct layout_dev *ldev = dev_get_drvdata(dev);
1143 
1144     if (ldev->gpio.methods && ldev->gpio.methods->all_amps_restore)
1145         ldev->gpio.methods->all_amps_restore(&ldev->gpio);
1146 
1147     return 0;
1148 }
1149 
1150 static SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
1151     aoa_fabric_layout_suspend, aoa_fabric_layout_resume);
1152 
1153 #endif
1154 
1155 static struct soundbus_driver aoa_soundbus_driver = {
1156     .name = "snd_aoa_soundbus_drv",
1157     .owner = THIS_MODULE,
1158     .probe = aoa_fabric_layout_probe,
1159     .remove = aoa_fabric_layout_remove,
1160     .driver = {
1161         .owner = THIS_MODULE,
1162 #ifdef CONFIG_PM_SLEEP
1163         .pm = &aoa_fabric_layout_pm_ops,
1164 #endif
1165     }
1166 };
1167 
1168 static int __init aoa_fabric_layout_init(void)
1169 {
1170     return soundbus_register_driver(&aoa_soundbus_driver);
1171 }
1172 
1173 static void __exit aoa_fabric_layout_exit(void)
1174 {
1175     soundbus_unregister_driver(&aoa_soundbus_driver);
1176     aoa_fabric_unregister(&layout_fabric);
1177 }
1178 
1179 module_init(aoa_fabric_layout_init);
1180 module_exit(aoa_fabric_layout_exit);