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