Commit 0562f7882d968463119bb63d47ef4bdaba7d6631
Committed by
Mark Brown
1 parent
7750752a22
Exists in
master
and in
7 other branches
ASoC: don't register AC97 devices twice
With generic AC97 ASoC glue driver (codec/ac97.c), we get following warning when the device is registered (slightly stripped the backtrace): kobject (c5a863e8): tried to init an initialized object, something is seriously wrong. [<c00254fc>] (unwind_backtrace+0x0/0xec) [<c014fad0>] (kobject_init+0x38/0x70) [<c0171e94>] (device_initialize+0x20/0x70) [<c017267c>] (device_register+0xc/0x18) [<bf20db70>] (snd_soc_instantiate_cards+0x924/0xacc [snd_soc_core]) [<bf20e0d0>] (snd_soc_register_platform+0x16c/0x198 [snd_soc_core]) [<c0175304>] (platform_drv_probe+0x18/0x1c) [<c0174454>] (driver_probe_device+0xb0/0x16c) [<c017456c>] (__driver_attach+0x5c/0x7c) [<c0173cec>] (bus_for_each_dev+0x48/0x78) [<c0173600>] (bus_add_driver+0x98/0x214) [<c0174834>] (driver_register+0xa4/0x130) [<c001f410>] (do_one_initcall+0xd0/0x1a4) [<c0062ddc>] (sys_init_module+0x12b0/0x1454) This happens because the generic AC97 glue driver creates its codec->ac97 via calling snd_ac97_mixer(). snd_ac97_mixer() provides own version of snd_device.register which handles the device registration when snd_card_register() is called. To avoid registering the AC97 device twice, we add a new flag to the snd_soc_codec: ac97_created which tells whether the AC97 device was created by SoC subsystem. Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 2 changed files with 19 additions and 0 deletions Inline Diff
include/sound/soc.h
1 | /* | 1 | /* |
2 | * linux/sound/soc.h -- ALSA SoC Layer | 2 | * linux/sound/soc.h -- ALSA SoC Layer |
3 | * | 3 | * |
4 | * Author: Liam Girdwood | 4 | * Author: Liam Girdwood |
5 | * Created: Aug 11th 2005 | 5 | * Created: Aug 11th 2005 |
6 | * Copyright: Wolfson Microelectronics. PLC. | 6 | * Copyright: Wolfson Microelectronics. PLC. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef __LINUX_SND_SOC_H | 13 | #ifndef __LINUX_SND_SOC_H |
14 | #define __LINUX_SND_SOC_H | 14 | #define __LINUX_SND_SOC_H |
15 | 15 | ||
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/notifier.h> | 18 | #include <linux/notifier.h> |
19 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/control.h> | 24 | #include <sound/control.h> |
25 | #include <sound/ac97_codec.h> | 25 | #include <sound/ac97_codec.h> |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Convenience kcontrol builders | 28 | * Convenience kcontrol builders |
29 | */ | 29 | */ |
30 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ | 30 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ |
31 | ((unsigned long)&(struct soc_mixer_control) \ | 31 | ((unsigned long)&(struct soc_mixer_control) \ |
32 | {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ | 32 | {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ |
33 | .platform_max = xmax, .invert = xinvert}) | 33 | .platform_max = xmax, .invert = xinvert}) |
34 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ | 34 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ |
35 | ((unsigned long)&(struct soc_mixer_control) \ | 35 | ((unsigned long)&(struct soc_mixer_control) \ |
36 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) | 36 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) |
37 | #define SOC_SINGLE(xname, reg, shift, max, invert) \ | 37 | #define SOC_SINGLE(xname, reg, shift, max, invert) \ |
38 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 38 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
39 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 39 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
40 | .put = snd_soc_put_volsw, \ | 40 | .put = snd_soc_put_volsw, \ |
41 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 41 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } |
42 | #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ | 42 | #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ |
43 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 43 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
44 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 44 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
45 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 45 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
46 | .tlv.p = (tlv_array), \ | 46 | .tlv.p = (tlv_array), \ |
47 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 47 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
48 | .put = snd_soc_put_volsw, \ | 48 | .put = snd_soc_put_volsw, \ |
49 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 49 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } |
50 | #define SOC_DOUBLE(xname, xreg, shift_left, shift_right, xmax, xinvert) \ | 50 | #define SOC_DOUBLE(xname, xreg, shift_left, shift_right, xmax, xinvert) \ |
51 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 51 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
52 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 52 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
53 | .put = snd_soc_put_volsw, \ | 53 | .put = snd_soc_put_volsw, \ |
54 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 54 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
55 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ | 55 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ |
56 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 56 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
57 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ | 57 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ |
58 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 58 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
59 | .info = snd_soc_info_volsw_2r, \ | 59 | .info = snd_soc_info_volsw_2r, \ |
60 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ | 60 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ |
61 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 61 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
62 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ | 62 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ |
63 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 63 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
64 | #define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \ | 64 | #define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \ |
65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
66 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 66 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
67 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 67 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
68 | .tlv.p = (tlv_array), \ | 68 | .tlv.p = (tlv_array), \ |
69 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 69 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
70 | .put = snd_soc_put_volsw, \ | 70 | .put = snd_soc_put_volsw, \ |
71 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 71 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
72 | {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ | 72 | {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ |
73 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 73 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
74 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ | 74 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ |
75 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 75 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
76 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 76 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
77 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 77 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
78 | .tlv.p = (tlv_array), \ | 78 | .tlv.p = (tlv_array), \ |
79 | .info = snd_soc_info_volsw_2r, \ | 79 | .info = snd_soc_info_volsw_2r, \ |
80 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ | 80 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ |
81 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 81 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
82 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ | 82 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ |
83 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 83 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
84 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | 84 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ |
85 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 85 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
86 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 86 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
87 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 87 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
88 | .tlv.p = (tlv_array), \ | 88 | .tlv.p = (tlv_array), \ |
89 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ | 89 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ |
90 | .put = snd_soc_put_volsw_s8, \ | 90 | .put = snd_soc_put_volsw_s8, \ |
91 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 91 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
92 | {.reg = xreg, .min = xmin, .max = xmax, \ | 92 | {.reg = xreg, .min = xmin, .max = xmax, \ |
93 | .platform_max = xmax} } | 93 | .platform_max = xmax} } |
94 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ | 94 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ |
95 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 95 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
96 | .max = xmax, .texts = xtexts } | 96 | .max = xmax, .texts = xtexts } |
97 | #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \ | 97 | #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \ |
98 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) | 98 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) |
99 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ | 99 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ |
100 | { .max = xmax, .texts = xtexts } | 100 | { .max = xmax, .texts = xtexts } |
101 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \ | 101 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \ |
102 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 102 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
103 | .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues} | 103 | .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues} |
104 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \ | 104 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \ |
105 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues) | 105 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues) |
106 | #define SOC_ENUM(xname, xenum) \ | 106 | #define SOC_ENUM(xname, xenum) \ |
107 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 107 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ |
108 | .info = snd_soc_info_enum_double, \ | 108 | .info = snd_soc_info_enum_double, \ |
109 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ | 109 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ |
110 | .private_value = (unsigned long)&xenum } | 110 | .private_value = (unsigned long)&xenum } |
111 | #define SOC_VALUE_ENUM(xname, xenum) \ | 111 | #define SOC_VALUE_ENUM(xname, xenum) \ |
112 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 112 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ |
113 | .info = snd_soc_info_enum_double, \ | 113 | .info = snd_soc_info_enum_double, \ |
114 | .get = snd_soc_get_value_enum_double, \ | 114 | .get = snd_soc_get_value_enum_double, \ |
115 | .put = snd_soc_put_value_enum_double, \ | 115 | .put = snd_soc_put_value_enum_double, \ |
116 | .private_value = (unsigned long)&xenum } | 116 | .private_value = (unsigned long)&xenum } |
117 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ | 117 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ |
118 | xhandler_get, xhandler_put) \ | 118 | xhandler_get, xhandler_put) \ |
119 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 119 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
120 | .info = snd_soc_info_volsw, \ | 120 | .info = snd_soc_info_volsw, \ |
121 | .get = xhandler_get, .put = xhandler_put, \ | 121 | .get = xhandler_get, .put = xhandler_put, \ |
122 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | 122 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } |
123 | #define SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert,\ | 123 | #define SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert,\ |
124 | xhandler_get, xhandler_put) \ | 124 | xhandler_get, xhandler_put) \ |
125 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 125 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
126 | .info = snd_soc_info_volsw, \ | 126 | .info = snd_soc_info_volsw, \ |
127 | .get = xhandler_get, .put = xhandler_put, \ | 127 | .get = xhandler_get, .put = xhandler_put, \ |
128 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 128 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
129 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ | 129 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ |
130 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 130 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
131 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ | 131 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ |
132 | xhandler_get, xhandler_put, tlv_array) \ | 132 | xhandler_get, xhandler_put, tlv_array) \ |
133 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 133 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
134 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 134 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
135 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 135 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
136 | .tlv.p = (tlv_array), \ | 136 | .tlv.p = (tlv_array), \ |
137 | .info = snd_soc_info_volsw, \ | 137 | .info = snd_soc_info_volsw, \ |
138 | .get = xhandler_get, .put = xhandler_put, \ | 138 | .get = xhandler_get, .put = xhandler_put, \ |
139 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | 139 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } |
140 | #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ | 140 | #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ |
141 | xhandler_get, xhandler_put, tlv_array) \ | 141 | xhandler_get, xhandler_put, tlv_array) \ |
142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
143 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 143 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
144 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 144 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
145 | .tlv.p = (tlv_array), \ | 145 | .tlv.p = (tlv_array), \ |
146 | .info = snd_soc_info_volsw, \ | 146 | .info = snd_soc_info_volsw, \ |
147 | .get = xhandler_get, .put = xhandler_put, \ | 147 | .get = xhandler_get, .put = xhandler_put, \ |
148 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 148 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
149 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ | 149 | {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ |
150 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 150 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
151 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ | 151 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ |
152 | xhandler_get, xhandler_put, tlv_array) \ | 152 | xhandler_get, xhandler_put, tlv_array) \ |
153 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 153 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
154 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 154 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
155 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 155 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
156 | .tlv.p = (tlv_array), \ | 156 | .tlv.p = (tlv_array), \ |
157 | .info = snd_soc_info_volsw_2r, \ | 157 | .info = snd_soc_info_volsw_2r, \ |
158 | .get = xhandler_get, .put = xhandler_put, \ | 158 | .get = xhandler_get, .put = xhandler_put, \ |
159 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 159 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
160 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ | 160 | {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ |
161 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 161 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
162 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ | 162 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ |
163 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 163 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
164 | .info = snd_soc_info_bool_ext, \ | 164 | .info = snd_soc_info_bool_ext, \ |
165 | .get = xhandler_get, .put = xhandler_put, \ | 165 | .get = xhandler_get, .put = xhandler_put, \ |
166 | .private_value = xdata } | 166 | .private_value = xdata } |
167 | #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ | 167 | #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ |
168 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 168 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
169 | .info = snd_soc_info_enum_ext, \ | 169 | .info = snd_soc_info_enum_ext, \ |
170 | .get = xhandler_get, .put = xhandler_put, \ | 170 | .get = xhandler_get, .put = xhandler_put, \ |
171 | .private_value = (unsigned long)&xenum } | 171 | .private_value = (unsigned long)&xenum } |
172 | 172 | ||
173 | #define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\ | 173 | #define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\ |
174 | xmin, xmax, tlv_array) \ | 174 | xmin, xmax, tlv_array) \ |
175 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 175 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
176 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 176 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
177 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 177 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
178 | .tlv.p = (tlv_array), \ | 178 | .tlv.p = (tlv_array), \ |
179 | .info = snd_soc_info_volsw_2r_sx, \ | 179 | .info = snd_soc_info_volsw_2r_sx, \ |
180 | .get = snd_soc_get_volsw_2r_sx, \ | 180 | .get = snd_soc_get_volsw_2r_sx, \ |
181 | .put = snd_soc_put_volsw_2r_sx, \ | 181 | .put = snd_soc_put_volsw_2r_sx, \ |
182 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 182 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
183 | {.reg = xreg_left, \ | 183 | {.reg = xreg_left, \ |
184 | .rreg = xreg_right, .shift = xshift, \ | 184 | .rreg = xreg_right, .shift = xshift, \ |
185 | .min = xmin, .max = xmax} } | 185 | .min = xmin, .max = xmax} } |
186 | 186 | ||
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Simplified versions of above macros, declaring a struct and calculating | 189 | * Simplified versions of above macros, declaring a struct and calculating |
190 | * ARRAY_SIZE internally | 190 | * ARRAY_SIZE internally |
191 | */ | 191 | */ |
192 | #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ | 192 | #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ |
193 | struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ | 193 | struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ |
194 | ARRAY_SIZE(xtexts), xtexts) | 194 | ARRAY_SIZE(xtexts), xtexts) |
195 | #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ | 195 | #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ |
196 | SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) | 196 | SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) |
197 | #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ | 197 | #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ |
198 | struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) | 198 | struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) |
199 | #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ | 199 | #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ |
200 | struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ | 200 | struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ |
201 | ARRAY_SIZE(xtexts), xtexts, xvalues) | 201 | ARRAY_SIZE(xtexts), xtexts, xvalues) |
202 | #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ | 202 | #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ |
203 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) | 203 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) |
204 | 204 | ||
205 | /* | 205 | /* |
206 | * Bias levels | 206 | * Bias levels |
207 | * | 207 | * |
208 | * @ON: Bias is fully on for audio playback and capture operations. | 208 | * @ON: Bias is fully on for audio playback and capture operations. |
209 | * @PREPARE: Prepare for audio operations. Called before DAPM switching for | 209 | * @PREPARE: Prepare for audio operations. Called before DAPM switching for |
210 | * stream start and stop operations. | 210 | * stream start and stop operations. |
211 | * @STANDBY: Low power standby state when no playback/capture operations are | 211 | * @STANDBY: Low power standby state when no playback/capture operations are |
212 | * in progress. NOTE: The transition time between STANDBY and ON | 212 | * in progress. NOTE: The transition time between STANDBY and ON |
213 | * should be as fast as possible and no longer than 10ms. | 213 | * should be as fast as possible and no longer than 10ms. |
214 | * @OFF: Power Off. No restrictions on transition times. | 214 | * @OFF: Power Off. No restrictions on transition times. |
215 | */ | 215 | */ |
216 | enum snd_soc_bias_level { | 216 | enum snd_soc_bias_level { |
217 | SND_SOC_BIAS_OFF, | 217 | SND_SOC_BIAS_OFF, |
218 | SND_SOC_BIAS_STANDBY, | 218 | SND_SOC_BIAS_STANDBY, |
219 | SND_SOC_BIAS_PREPARE, | 219 | SND_SOC_BIAS_PREPARE, |
220 | SND_SOC_BIAS_ON, | 220 | SND_SOC_BIAS_ON, |
221 | }; | 221 | }; |
222 | 222 | ||
223 | struct snd_jack; | 223 | struct snd_jack; |
224 | struct snd_soc_card; | 224 | struct snd_soc_card; |
225 | struct snd_soc_device; | 225 | struct snd_soc_device; |
226 | struct snd_soc_pcm_stream; | 226 | struct snd_soc_pcm_stream; |
227 | struct snd_soc_ops; | 227 | struct snd_soc_ops; |
228 | struct snd_soc_dai_mode; | 228 | struct snd_soc_dai_mode; |
229 | struct snd_soc_pcm_runtime; | 229 | struct snd_soc_pcm_runtime; |
230 | struct snd_soc_dai; | 230 | struct snd_soc_dai; |
231 | struct snd_soc_dai_driver; | 231 | struct snd_soc_dai_driver; |
232 | struct snd_soc_platform; | 232 | struct snd_soc_platform; |
233 | struct snd_soc_dai_link; | 233 | struct snd_soc_dai_link; |
234 | struct snd_soc_platform_driver; | 234 | struct snd_soc_platform_driver; |
235 | struct snd_soc_codec; | 235 | struct snd_soc_codec; |
236 | struct snd_soc_codec_driver; | 236 | struct snd_soc_codec_driver; |
237 | struct soc_enum; | 237 | struct soc_enum; |
238 | struct snd_soc_ac97_ops; | 238 | struct snd_soc_ac97_ops; |
239 | struct snd_soc_jack; | 239 | struct snd_soc_jack; |
240 | struct snd_soc_jack_pin; | 240 | struct snd_soc_jack_pin; |
241 | 241 | ||
242 | #ifdef CONFIG_GPIOLIB | 242 | #ifdef CONFIG_GPIOLIB |
243 | struct snd_soc_jack_gpio; | 243 | struct snd_soc_jack_gpio; |
244 | #endif | 244 | #endif |
245 | 245 | ||
246 | typedef int (*hw_write_t)(void *,const char* ,int); | 246 | typedef int (*hw_write_t)(void *,const char* ,int); |
247 | 247 | ||
248 | extern struct snd_ac97_bus_ops soc_ac97_ops; | 248 | extern struct snd_ac97_bus_ops soc_ac97_ops; |
249 | 249 | ||
250 | enum snd_soc_control_type { | 250 | enum snd_soc_control_type { |
251 | SND_SOC_CUSTOM, | 251 | SND_SOC_CUSTOM, |
252 | SND_SOC_I2C, | 252 | SND_SOC_I2C, |
253 | SND_SOC_SPI, | 253 | SND_SOC_SPI, |
254 | }; | 254 | }; |
255 | 255 | ||
256 | int snd_soc_register_platform(struct device *dev, | 256 | int snd_soc_register_platform(struct device *dev, |
257 | struct snd_soc_platform_driver *platform_drv); | 257 | struct snd_soc_platform_driver *platform_drv); |
258 | void snd_soc_unregister_platform(struct device *dev); | 258 | void snd_soc_unregister_platform(struct device *dev); |
259 | int snd_soc_register_codec(struct device *dev, | 259 | int snd_soc_register_codec(struct device *dev, |
260 | struct snd_soc_codec_driver *codec_drv, | 260 | struct snd_soc_codec_driver *codec_drv, |
261 | struct snd_soc_dai_driver *dai_drv, int num_dai); | 261 | struct snd_soc_dai_driver *dai_drv, int num_dai); |
262 | void snd_soc_unregister_codec(struct device *dev); | 262 | void snd_soc_unregister_codec(struct device *dev); |
263 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg); | 263 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg); |
264 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | 264 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, |
265 | int addr_bits, int data_bits, | 265 | int addr_bits, int data_bits, |
266 | enum snd_soc_control_type control); | 266 | enum snd_soc_control_type control); |
267 | 267 | ||
268 | /* Utility functions to get clock rates from various things */ | 268 | /* Utility functions to get clock rates from various things */ |
269 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); | 269 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); |
270 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); | 270 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); |
271 | int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); | 271 | int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); |
272 | int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); | 272 | int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); |
273 | 273 | ||
274 | /* set runtime hw params */ | 274 | /* set runtime hw params */ |
275 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | 275 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, |
276 | const struct snd_pcm_hardware *hw); | 276 | const struct snd_pcm_hardware *hw); |
277 | 277 | ||
278 | /* Jack reporting */ | 278 | /* Jack reporting */ |
279 | int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, | 279 | int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, |
280 | struct snd_soc_jack *jack); | 280 | struct snd_soc_jack *jack); |
281 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask); | 281 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask); |
282 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, | 282 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, |
283 | struct snd_soc_jack_pin *pins); | 283 | struct snd_soc_jack_pin *pins); |
284 | void snd_soc_jack_notifier_register(struct snd_soc_jack *jack, | 284 | void snd_soc_jack_notifier_register(struct snd_soc_jack *jack, |
285 | struct notifier_block *nb); | 285 | struct notifier_block *nb); |
286 | void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack, | 286 | void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack, |
287 | struct notifier_block *nb); | 287 | struct notifier_block *nb); |
288 | #ifdef CONFIG_GPIOLIB | 288 | #ifdef CONFIG_GPIOLIB |
289 | int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | 289 | int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, |
290 | struct snd_soc_jack_gpio *gpios); | 290 | struct snd_soc_jack_gpio *gpios); |
291 | void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, | 291 | void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, |
292 | struct snd_soc_jack_gpio *gpios); | 292 | struct snd_soc_jack_gpio *gpios); |
293 | #endif | 293 | #endif |
294 | 294 | ||
295 | /* codec register bit access */ | 295 | /* codec register bit access */ |
296 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 296 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
297 | unsigned int mask, unsigned int value); | 297 | unsigned int mask, unsigned int value); |
298 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, | 298 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, |
299 | unsigned short reg, unsigned int mask, | 299 | unsigned short reg, unsigned int mask, |
300 | unsigned int value); | 300 | unsigned int value); |
301 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | 301 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, |
302 | unsigned int mask, unsigned int value); | 302 | unsigned int mask, unsigned int value); |
303 | 303 | ||
304 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | 304 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, |
305 | struct snd_ac97_bus_ops *ops, int num); | 305 | struct snd_ac97_bus_ops *ops, int num); |
306 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); | 306 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); |
307 | 307 | ||
308 | /* | 308 | /* |
309 | *Controls | 309 | *Controls |
310 | */ | 310 | */ |
311 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | 311 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, |
312 | void *data, char *long_name); | 312 | void *data, char *long_name); |
313 | int snd_soc_add_controls(struct snd_soc_codec *codec, | 313 | int snd_soc_add_controls(struct snd_soc_codec *codec, |
314 | const struct snd_kcontrol_new *controls, int num_controls); | 314 | const struct snd_kcontrol_new *controls, int num_controls); |
315 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | 315 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, |
316 | struct snd_ctl_elem_info *uinfo); | 316 | struct snd_ctl_elem_info *uinfo); |
317 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | 317 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, |
318 | struct snd_ctl_elem_info *uinfo); | 318 | struct snd_ctl_elem_info *uinfo); |
319 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | 319 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, |
320 | struct snd_ctl_elem_value *ucontrol); | 320 | struct snd_ctl_elem_value *ucontrol); |
321 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | 321 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, |
322 | struct snd_ctl_elem_value *ucontrol); | 322 | struct snd_ctl_elem_value *ucontrol); |
323 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | 323 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, |
324 | struct snd_ctl_elem_value *ucontrol); | 324 | struct snd_ctl_elem_value *ucontrol); |
325 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | 325 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, |
326 | struct snd_ctl_elem_value *ucontrol); | 326 | struct snd_ctl_elem_value *ucontrol); |
327 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 327 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
328 | struct snd_ctl_elem_info *uinfo); | 328 | struct snd_ctl_elem_info *uinfo); |
329 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | 329 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, |
330 | struct snd_ctl_elem_info *uinfo); | 330 | struct snd_ctl_elem_info *uinfo); |
331 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info | 331 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info |
332 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | 332 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, |
333 | struct snd_ctl_elem_value *ucontrol); | 333 | struct snd_ctl_elem_value *ucontrol); |
334 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | 334 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, |
335 | struct snd_ctl_elem_value *ucontrol); | 335 | struct snd_ctl_elem_value *ucontrol); |
336 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | 336 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, |
337 | struct snd_ctl_elem_info *uinfo); | 337 | struct snd_ctl_elem_info *uinfo); |
338 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | 338 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, |
339 | struct snd_ctl_elem_value *ucontrol); | 339 | struct snd_ctl_elem_value *ucontrol); |
340 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | 340 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, |
341 | struct snd_ctl_elem_value *ucontrol); | 341 | struct snd_ctl_elem_value *ucontrol); |
342 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | 342 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, |
343 | struct snd_ctl_elem_info *uinfo); | 343 | struct snd_ctl_elem_info *uinfo); |
344 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | 344 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, |
345 | struct snd_ctl_elem_value *ucontrol); | 345 | struct snd_ctl_elem_value *ucontrol); |
346 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | 346 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, |
347 | struct snd_ctl_elem_value *ucontrol); | 347 | struct snd_ctl_elem_value *ucontrol); |
348 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | 348 | int snd_soc_limit_volume(struct snd_soc_codec *codec, |
349 | const char *name, int max); | 349 | const char *name, int max); |
350 | int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, | 350 | int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, |
351 | struct snd_ctl_elem_info *uinfo); | 351 | struct snd_ctl_elem_info *uinfo); |
352 | int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, | 352 | int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, |
353 | struct snd_ctl_elem_value *ucontrol); | 353 | struct snd_ctl_elem_value *ucontrol); |
354 | int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, | 354 | int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, |
355 | struct snd_ctl_elem_value *ucontrol); | 355 | struct snd_ctl_elem_value *ucontrol); |
356 | 356 | ||
357 | /** | 357 | /** |
358 | * struct snd_soc_jack_pin - Describes a pin to update based on jack detection | 358 | * struct snd_soc_jack_pin - Describes a pin to update based on jack detection |
359 | * | 359 | * |
360 | * @pin: name of the pin to update | 360 | * @pin: name of the pin to update |
361 | * @mask: bits to check for in reported jack status | 361 | * @mask: bits to check for in reported jack status |
362 | * @invert: if non-zero then pin is enabled when status is not reported | 362 | * @invert: if non-zero then pin is enabled when status is not reported |
363 | */ | 363 | */ |
364 | struct snd_soc_jack_pin { | 364 | struct snd_soc_jack_pin { |
365 | struct list_head list; | 365 | struct list_head list; |
366 | const char *pin; | 366 | const char *pin; |
367 | int mask; | 367 | int mask; |
368 | bool invert; | 368 | bool invert; |
369 | }; | 369 | }; |
370 | 370 | ||
371 | /** | 371 | /** |
372 | * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection | 372 | * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection |
373 | * | 373 | * |
374 | * @gpio: gpio number | 374 | * @gpio: gpio number |
375 | * @name: gpio name | 375 | * @name: gpio name |
376 | * @report: value to report when jack detected | 376 | * @report: value to report when jack detected |
377 | * @invert: report presence in low state | 377 | * @invert: report presence in low state |
378 | * @debouce_time: debouce time in ms | 378 | * @debouce_time: debouce time in ms |
379 | */ | 379 | */ |
380 | #ifdef CONFIG_GPIOLIB | 380 | #ifdef CONFIG_GPIOLIB |
381 | struct snd_soc_jack_gpio { | 381 | struct snd_soc_jack_gpio { |
382 | unsigned int gpio; | 382 | unsigned int gpio; |
383 | const char *name; | 383 | const char *name; |
384 | int report; | 384 | int report; |
385 | int invert; | 385 | int invert; |
386 | int debounce_time; | 386 | int debounce_time; |
387 | struct snd_soc_jack *jack; | 387 | struct snd_soc_jack *jack; |
388 | struct delayed_work work; | 388 | struct delayed_work work; |
389 | 389 | ||
390 | int (*jack_status_check)(void); | 390 | int (*jack_status_check)(void); |
391 | }; | 391 | }; |
392 | #endif | 392 | #endif |
393 | 393 | ||
394 | struct snd_soc_jack { | 394 | struct snd_soc_jack { |
395 | struct snd_jack *jack; | 395 | struct snd_jack *jack; |
396 | struct snd_soc_codec *codec; | 396 | struct snd_soc_codec *codec; |
397 | struct list_head pins; | 397 | struct list_head pins; |
398 | int status; | 398 | int status; |
399 | struct blocking_notifier_head notifier; | 399 | struct blocking_notifier_head notifier; |
400 | }; | 400 | }; |
401 | 401 | ||
402 | /* SoC PCM stream information */ | 402 | /* SoC PCM stream information */ |
403 | struct snd_soc_pcm_stream { | 403 | struct snd_soc_pcm_stream { |
404 | const char *stream_name; | 404 | const char *stream_name; |
405 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ | 405 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ |
406 | unsigned int rates; /* SNDRV_PCM_RATE_* */ | 406 | unsigned int rates; /* SNDRV_PCM_RATE_* */ |
407 | unsigned int rate_min; /* min rate */ | 407 | unsigned int rate_min; /* min rate */ |
408 | unsigned int rate_max; /* max rate */ | 408 | unsigned int rate_max; /* max rate */ |
409 | unsigned int channels_min; /* min channels */ | 409 | unsigned int channels_min; /* min channels */ |
410 | unsigned int channels_max; /* max channels */ | 410 | unsigned int channels_max; /* max channels */ |
411 | }; | 411 | }; |
412 | 412 | ||
413 | /* SoC audio ops */ | 413 | /* SoC audio ops */ |
414 | struct snd_soc_ops { | 414 | struct snd_soc_ops { |
415 | int (*startup)(struct snd_pcm_substream *); | 415 | int (*startup)(struct snd_pcm_substream *); |
416 | void (*shutdown)(struct snd_pcm_substream *); | 416 | void (*shutdown)(struct snd_pcm_substream *); |
417 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); | 417 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); |
418 | int (*hw_free)(struct snd_pcm_substream *); | 418 | int (*hw_free)(struct snd_pcm_substream *); |
419 | int (*prepare)(struct snd_pcm_substream *); | 419 | int (*prepare)(struct snd_pcm_substream *); |
420 | int (*trigger)(struct snd_pcm_substream *, int); | 420 | int (*trigger)(struct snd_pcm_substream *, int); |
421 | }; | 421 | }; |
422 | 422 | ||
423 | /* SoC Audio Codec device */ | 423 | /* SoC Audio Codec device */ |
424 | struct snd_soc_codec { | 424 | struct snd_soc_codec { |
425 | const char *name; | 425 | const char *name; |
426 | int id; | 426 | int id; |
427 | struct device *dev; | 427 | struct device *dev; |
428 | struct snd_soc_codec_driver *driver; | 428 | struct snd_soc_codec_driver *driver; |
429 | 429 | ||
430 | struct mutex mutex; | 430 | struct mutex mutex; |
431 | struct snd_soc_card *card; | 431 | struct snd_soc_card *card; |
432 | struct list_head list; | 432 | struct list_head list; |
433 | struct list_head card_list; | 433 | struct list_head card_list; |
434 | int num_dai; | 434 | int num_dai; |
435 | 435 | ||
436 | /* runtime */ | 436 | /* runtime */ |
437 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ | 437 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ |
438 | unsigned int active; | 438 | unsigned int active; |
439 | unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ | 439 | unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ |
440 | unsigned int cache_only:1; /* Suppress writes to hardware */ | 440 | unsigned int cache_only:1; /* Suppress writes to hardware */ |
441 | unsigned int cache_sync:1; /* Cache needs to be synced to hardware */ | 441 | unsigned int cache_sync:1; /* Cache needs to be synced to hardware */ |
442 | unsigned int suspended:1; /* Codec is in suspend PM state */ | 442 | unsigned int suspended:1; /* Codec is in suspend PM state */ |
443 | unsigned int probed:1; /* Codec has been probed */ | 443 | unsigned int probed:1; /* Codec has been probed */ |
444 | unsigned int ac97_registered:1; /* Codec has been AC97 registered */ | 444 | unsigned int ac97_registered:1; /* Codec has been AC97 registered */ |
445 | unsigned int ac97_created:1; /* Codec has been created by SoC */ | ||
445 | unsigned int sysfs_registered:1; /* codec has been sysfs registered */ | 446 | unsigned int sysfs_registered:1; /* codec has been sysfs registered */ |
446 | 447 | ||
447 | /* codec IO */ | 448 | /* codec IO */ |
448 | void *control_data; /* codec control (i2c/3wire) data */ | 449 | void *control_data; /* codec control (i2c/3wire) data */ |
449 | hw_write_t hw_write; | 450 | hw_write_t hw_write; |
450 | unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); | 451 | unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); |
451 | void *reg_cache; | 452 | void *reg_cache; |
452 | 453 | ||
453 | /* dapm */ | 454 | /* dapm */ |
454 | u32 pop_time; | 455 | u32 pop_time; |
455 | struct list_head dapm_widgets; | 456 | struct list_head dapm_widgets; |
456 | struct list_head dapm_paths; | 457 | struct list_head dapm_paths; |
457 | enum snd_soc_bias_level bias_level; | 458 | enum snd_soc_bias_level bias_level; |
458 | enum snd_soc_bias_level suspend_bias_level; | 459 | enum snd_soc_bias_level suspend_bias_level; |
459 | struct delayed_work delayed_work; | 460 | struct delayed_work delayed_work; |
460 | 461 | ||
461 | #ifdef CONFIG_DEBUG_FS | 462 | #ifdef CONFIG_DEBUG_FS |
462 | struct dentry *debugfs_codec_root; | 463 | struct dentry *debugfs_codec_root; |
463 | struct dentry *debugfs_reg; | 464 | struct dentry *debugfs_reg; |
464 | struct dentry *debugfs_pop_time; | 465 | struct dentry *debugfs_pop_time; |
465 | struct dentry *debugfs_dapm; | 466 | struct dentry *debugfs_dapm; |
466 | #endif | 467 | #endif |
467 | }; | 468 | }; |
468 | 469 | ||
469 | /* codec driver */ | 470 | /* codec driver */ |
470 | struct snd_soc_codec_driver { | 471 | struct snd_soc_codec_driver { |
471 | 472 | ||
472 | /* driver ops */ | 473 | /* driver ops */ |
473 | int (*probe)(struct snd_soc_codec *); | 474 | int (*probe)(struct snd_soc_codec *); |
474 | int (*remove)(struct snd_soc_codec *); | 475 | int (*remove)(struct snd_soc_codec *); |
475 | int (*suspend)(struct snd_soc_codec *, | 476 | int (*suspend)(struct snd_soc_codec *, |
476 | pm_message_t state); | 477 | pm_message_t state); |
477 | int (*resume)(struct snd_soc_codec *); | 478 | int (*resume)(struct snd_soc_codec *); |
478 | 479 | ||
479 | /* codec IO */ | 480 | /* codec IO */ |
480 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | 481 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
481 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); | 482 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); |
482 | int (*display_register)(struct snd_soc_codec *, char *, | 483 | int (*display_register)(struct snd_soc_codec *, char *, |
483 | size_t, unsigned int); | 484 | size_t, unsigned int); |
484 | int (*volatile_register)(unsigned int); | 485 | int (*volatile_register)(unsigned int); |
485 | int (*readable_register)(unsigned int); | 486 | int (*readable_register)(unsigned int); |
486 | short reg_cache_size; | 487 | short reg_cache_size; |
487 | short reg_cache_step; | 488 | short reg_cache_step; |
488 | short reg_word_size; | 489 | short reg_word_size; |
489 | const void *reg_cache_default; | 490 | const void *reg_cache_default; |
490 | 491 | ||
491 | /* codec bias level */ | 492 | /* codec bias level */ |
492 | int (*set_bias_level)(struct snd_soc_codec *, | 493 | int (*set_bias_level)(struct snd_soc_codec *, |
493 | enum snd_soc_bias_level level); | 494 | enum snd_soc_bias_level level); |
494 | }; | 495 | }; |
495 | 496 | ||
496 | /* SoC platform interface */ | 497 | /* SoC platform interface */ |
497 | struct snd_soc_platform_driver { | 498 | struct snd_soc_platform_driver { |
498 | 499 | ||
499 | int (*probe)(struct snd_soc_platform *); | 500 | int (*probe)(struct snd_soc_platform *); |
500 | int (*remove)(struct snd_soc_platform *); | 501 | int (*remove)(struct snd_soc_platform *); |
501 | int (*suspend)(struct snd_soc_dai *dai); | 502 | int (*suspend)(struct snd_soc_dai *dai); |
502 | int (*resume)(struct snd_soc_dai *dai); | 503 | int (*resume)(struct snd_soc_dai *dai); |
503 | 504 | ||
504 | /* pcm creation and destruction */ | 505 | /* pcm creation and destruction */ |
505 | int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, | 506 | int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, |
506 | struct snd_pcm *); | 507 | struct snd_pcm *); |
507 | void (*pcm_free)(struct snd_pcm *); | 508 | void (*pcm_free)(struct snd_pcm *); |
508 | 509 | ||
509 | /* | 510 | /* |
510 | * For platform caused delay reporting. | 511 | * For platform caused delay reporting. |
511 | * Optional. | 512 | * Optional. |
512 | */ | 513 | */ |
513 | snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, | 514 | snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, |
514 | struct snd_soc_dai *); | 515 | struct snd_soc_dai *); |
515 | 516 | ||
516 | /* platform stream ops */ | 517 | /* platform stream ops */ |
517 | struct snd_pcm_ops *ops; | 518 | struct snd_pcm_ops *ops; |
518 | }; | 519 | }; |
519 | 520 | ||
520 | struct snd_soc_platform { | 521 | struct snd_soc_platform { |
521 | const char *name; | 522 | const char *name; |
522 | int id; | 523 | int id; |
523 | struct device *dev; | 524 | struct device *dev; |
524 | struct snd_soc_platform_driver *driver; | 525 | struct snd_soc_platform_driver *driver; |
525 | 526 | ||
526 | unsigned int suspended:1; /* platform is suspended */ | 527 | unsigned int suspended:1; /* platform is suspended */ |
527 | unsigned int probed:1; | 528 | unsigned int probed:1; |
528 | 529 | ||
529 | struct snd_soc_card *card; | 530 | struct snd_soc_card *card; |
530 | struct list_head list; | 531 | struct list_head list; |
531 | struct list_head card_list; | 532 | struct list_head card_list; |
532 | }; | 533 | }; |
533 | 534 | ||
534 | struct snd_soc_dai_link { | 535 | struct snd_soc_dai_link { |
535 | /* config - must be set by machine driver */ | 536 | /* config - must be set by machine driver */ |
536 | const char *name; /* Codec name */ | 537 | const char *name; /* Codec name */ |
537 | const char *stream_name; /* Stream name */ | 538 | const char *stream_name; /* Stream name */ |
538 | const char *codec_name; /* for multi-codec */ | 539 | const char *codec_name; /* for multi-codec */ |
539 | const char *platform_name; /* for multi-platform */ | 540 | const char *platform_name; /* for multi-platform */ |
540 | const char *cpu_dai_name; | 541 | const char *cpu_dai_name; |
541 | const char *codec_dai_name; | 542 | const char *codec_dai_name; |
542 | 543 | ||
543 | /* Keep DAI active over suspend */ | 544 | /* Keep DAI active over suspend */ |
544 | unsigned int ignore_suspend:1; | 545 | unsigned int ignore_suspend:1; |
545 | 546 | ||
546 | /* Symmetry requirements */ | 547 | /* Symmetry requirements */ |
547 | unsigned int symmetric_rates:1; | 548 | unsigned int symmetric_rates:1; |
548 | 549 | ||
549 | /* codec/machine specific init - e.g. add machine controls */ | 550 | /* codec/machine specific init - e.g. add machine controls */ |
550 | int (*init)(struct snd_soc_pcm_runtime *rtd); | 551 | int (*init)(struct snd_soc_pcm_runtime *rtd); |
551 | 552 | ||
552 | /* machine stream operations */ | 553 | /* machine stream operations */ |
553 | struct snd_soc_ops *ops; | 554 | struct snd_soc_ops *ops; |
554 | }; | 555 | }; |
555 | 556 | ||
556 | /* SoC card */ | 557 | /* SoC card */ |
557 | struct snd_soc_card { | 558 | struct snd_soc_card { |
558 | const char *name; | 559 | const char *name; |
559 | struct device *dev; | 560 | struct device *dev; |
560 | struct snd_card *snd_card; | 561 | struct snd_card *snd_card; |
561 | struct module *owner; | 562 | struct module *owner; |
562 | 563 | ||
563 | struct list_head list; | 564 | struct list_head list; |
564 | struct mutex mutex; | 565 | struct mutex mutex; |
565 | 566 | ||
566 | bool instantiated; | 567 | bool instantiated; |
567 | 568 | ||
568 | int (*probe)(struct platform_device *pdev); | 569 | int (*probe)(struct platform_device *pdev); |
569 | int (*remove)(struct platform_device *pdev); | 570 | int (*remove)(struct platform_device *pdev); |
570 | 571 | ||
571 | /* the pre and post PM functions are used to do any PM work before and | 572 | /* the pre and post PM functions are used to do any PM work before and |
572 | * after the codec and DAI's do any PM work. */ | 573 | * after the codec and DAI's do any PM work. */ |
573 | int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); | 574 | int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); |
574 | int (*suspend_post)(struct platform_device *pdev, pm_message_t state); | 575 | int (*suspend_post)(struct platform_device *pdev, pm_message_t state); |
575 | int (*resume_pre)(struct platform_device *pdev); | 576 | int (*resume_pre)(struct platform_device *pdev); |
576 | int (*resume_post)(struct platform_device *pdev); | 577 | int (*resume_post)(struct platform_device *pdev); |
577 | 578 | ||
578 | /* callbacks */ | 579 | /* callbacks */ |
579 | int (*set_bias_level)(struct snd_soc_card *, | 580 | int (*set_bias_level)(struct snd_soc_card *, |
580 | enum snd_soc_bias_level level); | 581 | enum snd_soc_bias_level level); |
581 | 582 | ||
582 | long pmdown_time; | 583 | long pmdown_time; |
583 | 584 | ||
584 | /* CPU <--> Codec DAI links */ | 585 | /* CPU <--> Codec DAI links */ |
585 | struct snd_soc_dai_link *dai_link; | 586 | struct snd_soc_dai_link *dai_link; |
586 | int num_links; | 587 | int num_links; |
587 | struct snd_soc_pcm_runtime *rtd; | 588 | struct snd_soc_pcm_runtime *rtd; |
588 | int num_rtd; | 589 | int num_rtd; |
589 | 590 | ||
590 | struct work_struct deferred_resume_work; | 591 | struct work_struct deferred_resume_work; |
591 | 592 | ||
592 | /* lists of probed devices belonging to this card */ | 593 | /* lists of probed devices belonging to this card */ |
593 | struct list_head codec_dev_list; | 594 | struct list_head codec_dev_list; |
594 | struct list_head platform_dev_list; | 595 | struct list_head platform_dev_list; |
595 | struct list_head dai_dev_list; | 596 | struct list_head dai_dev_list; |
596 | }; | 597 | }; |
597 | 598 | ||
598 | /* SoC machine DAI configuration, glues a codec and cpu DAI together */ | 599 | /* SoC machine DAI configuration, glues a codec and cpu DAI together */ |
599 | struct snd_soc_pcm_runtime { | 600 | struct snd_soc_pcm_runtime { |
600 | struct device dev; | 601 | struct device dev; |
601 | struct snd_soc_card *card; | 602 | struct snd_soc_card *card; |
602 | struct snd_soc_dai_link *dai_link; | 603 | struct snd_soc_dai_link *dai_link; |
603 | 604 | ||
604 | unsigned int complete:1; | 605 | unsigned int complete:1; |
605 | unsigned int dev_registered:1; | 606 | unsigned int dev_registered:1; |
606 | 607 | ||
607 | /* Symmetry data - only valid if symmetry is being enforced */ | 608 | /* Symmetry data - only valid if symmetry is being enforced */ |
608 | unsigned int rate; | 609 | unsigned int rate; |
609 | long pmdown_time; | 610 | long pmdown_time; |
610 | 611 | ||
611 | /* runtime devices */ | 612 | /* runtime devices */ |
612 | struct snd_pcm *pcm; | 613 | struct snd_pcm *pcm; |
613 | struct snd_soc_codec *codec; | 614 | struct snd_soc_codec *codec; |
614 | struct snd_soc_platform *platform; | 615 | struct snd_soc_platform *platform; |
615 | struct snd_soc_dai *codec_dai; | 616 | struct snd_soc_dai *codec_dai; |
616 | struct snd_soc_dai *cpu_dai; | 617 | struct snd_soc_dai *cpu_dai; |
617 | 618 | ||
618 | struct delayed_work delayed_work; | 619 | struct delayed_work delayed_work; |
619 | }; | 620 | }; |
620 | 621 | ||
621 | /* mixer control */ | 622 | /* mixer control */ |
622 | struct soc_mixer_control { | 623 | struct soc_mixer_control { |
623 | int min, max, platform_max; | 624 | int min, max, platform_max; |
624 | unsigned int reg, rreg, shift, rshift, invert; | 625 | unsigned int reg, rreg, shift, rshift, invert; |
625 | }; | 626 | }; |
626 | 627 | ||
627 | /* enumerated kcontrol */ | 628 | /* enumerated kcontrol */ |
628 | struct soc_enum { | 629 | struct soc_enum { |
629 | unsigned short reg; | 630 | unsigned short reg; |
630 | unsigned short reg2; | 631 | unsigned short reg2; |
631 | unsigned char shift_l; | 632 | unsigned char shift_l; |
632 | unsigned char shift_r; | 633 | unsigned char shift_r; |
633 | unsigned int max; | 634 | unsigned int max; |
634 | unsigned int mask; | 635 | unsigned int mask; |
635 | const char **texts; | 636 | const char **texts; |
636 | const unsigned int *values; | 637 | const unsigned int *values; |
637 | void *dapm; | 638 | void *dapm; |
638 | }; | 639 | }; |
639 | 640 | ||
640 | /* codec IO */ | 641 | /* codec IO */ |
641 | static inline unsigned int snd_soc_read(struct snd_soc_codec *codec, | 642 | static inline unsigned int snd_soc_read(struct snd_soc_codec *codec, |
642 | unsigned int reg) | 643 | unsigned int reg) |
643 | { | 644 | { |
644 | return codec->driver->read(codec, reg); | 645 | return codec->driver->read(codec, reg); |
645 | } | 646 | } |
646 | 647 | ||
647 | static inline unsigned int snd_soc_write(struct snd_soc_codec *codec, | 648 | static inline unsigned int snd_soc_write(struct snd_soc_codec *codec, |
648 | unsigned int reg, unsigned int val) | 649 | unsigned int reg, unsigned int val) |
649 | { | 650 | { |
650 | return codec->driver->write(codec, reg, val); | 651 | return codec->driver->write(codec, reg, val); |
651 | } | 652 | } |
652 | 653 | ||
653 | /* device driver data */ | 654 | /* device driver data */ |
654 | 655 | ||
655 | static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec, | 656 | static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec, |
656 | void *data) | 657 | void *data) |
657 | { | 658 | { |
658 | dev_set_drvdata(codec->dev, data); | 659 | dev_set_drvdata(codec->dev, data); |
659 | } | 660 | } |
660 | 661 | ||
661 | static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec) | 662 | static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec) |
662 | { | 663 | { |
663 | return dev_get_drvdata(codec->dev); | 664 | return dev_get_drvdata(codec->dev); |
664 | } | 665 | } |
665 | 666 | ||
666 | static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform, | 667 | static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform, |
667 | void *data) | 668 | void *data) |
668 | { | 669 | { |
669 | dev_set_drvdata(platform->dev, data); | 670 | dev_set_drvdata(platform->dev, data); |
670 | } | 671 | } |
671 | 672 | ||
672 | static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform) | 673 | static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform) |
673 | { | 674 | { |
674 | return dev_get_drvdata(platform->dev); | 675 | return dev_get_drvdata(platform->dev); |
675 | } | 676 | } |
676 | 677 | ||
677 | static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd, | 678 | static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd, |
678 | void *data) | 679 | void *data) |
679 | { | 680 | { |
680 | dev_set_drvdata(&rtd->dev, data); | 681 | dev_set_drvdata(&rtd->dev, data); |
681 | } | 682 | } |
682 | 683 | ||
683 | static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd) | 684 | static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd) |
684 | { | 685 | { |
685 | return dev_get_drvdata(&rtd->dev); | 686 | return dev_get_drvdata(&rtd->dev); |
686 | } | 687 | } |
687 | 688 | ||
688 | #include <sound/soc-dai.h> | 689 | #include <sound/soc-dai.h> |
689 | 690 | ||
690 | #endif | 691 | #endif |
691 | 692 |
sound/soc/soc-core.c
1 | /* | 1 | /* |
2 | * soc-core.c -- ALSA SoC Audio Layer | 2 | * soc-core.c -- ALSA SoC Audio Layer |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * Copyright (C) 2010 Slimlogic Ltd. | 6 | * Copyright (C) 2010 Slimlogic Ltd. |
7 | * Copyright (C) 2010 Texas Instruments Inc. | 7 | * Copyright (C) 2010 Texas Instruments Inc. |
8 | * | 8 | * |
9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | 9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
10 | * with code, comments and ideas from :- | 10 | * with code, comments and ideas from :- |
11 | * Richard Purdie <richard@openedhand.com> | 11 | * Richard Purdie <richard@openedhand.com> |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify it | 13 | * This program is free software; you can redistribute it and/or modify it |
14 | * under the terms of the GNU General Public License as published by the | 14 | * under the terms of the GNU General Public License as published by the |
15 | * Free Software Foundation; either version 2 of the License, or (at your | 15 | * Free Software Foundation; either version 2 of the License, or (at your |
16 | * option) any later version. | 16 | * option) any later version. |
17 | * | 17 | * |
18 | * TODO: | 18 | * TODO: |
19 | * o Add hw rules to enforce rates, etc. | 19 | * o Add hw rules to enforce rates, etc. |
20 | * o More testing with other codecs/machines. | 20 | * o More testing with other codecs/machines. |
21 | * o Add more codecs and platforms to ensure good API coverage. | 21 | * o Add more codecs and platforms to ensure good API coverage. |
22 | * o Support TDM on PCM and I2S | 22 | * o Support TDM on PCM and I2S |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/pm.h> | 29 | #include <linux/pm.h> |
30 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
31 | #include <linux/debugfs.h> | 31 | #include <linux/debugfs.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <sound/ac97_codec.h> | 34 | #include <sound/ac97_codec.h> |
35 | #include <sound/core.h> | 35 | #include <sound/core.h> |
36 | #include <sound/pcm.h> | 36 | #include <sound/pcm.h> |
37 | #include <sound/pcm_params.h> | 37 | #include <sound/pcm_params.h> |
38 | #include <sound/soc.h> | 38 | #include <sound/soc.h> |
39 | #include <sound/soc-dapm.h> | 39 | #include <sound/soc-dapm.h> |
40 | #include <sound/initval.h> | 40 | #include <sound/initval.h> |
41 | 41 | ||
42 | #define NAME_SIZE 32 | 42 | #define NAME_SIZE 32 |
43 | 43 | ||
44 | static DEFINE_MUTEX(pcm_mutex); | 44 | static DEFINE_MUTEX(pcm_mutex); |
45 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | 45 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); |
46 | 46 | ||
47 | #ifdef CONFIG_DEBUG_FS | 47 | #ifdef CONFIG_DEBUG_FS |
48 | static struct dentry *debugfs_root; | 48 | static struct dentry *debugfs_root; |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | static DEFINE_MUTEX(client_mutex); | 51 | static DEFINE_MUTEX(client_mutex); |
52 | static LIST_HEAD(card_list); | 52 | static LIST_HEAD(card_list); |
53 | static LIST_HEAD(dai_list); | 53 | static LIST_HEAD(dai_list); |
54 | static LIST_HEAD(platform_list); | 54 | static LIST_HEAD(platform_list); |
55 | static LIST_HEAD(codec_list); | 55 | static LIST_HEAD(codec_list); |
56 | 56 | ||
57 | static int snd_soc_register_card(struct snd_soc_card *card); | 57 | static int snd_soc_register_card(struct snd_soc_card *card); |
58 | static int snd_soc_unregister_card(struct snd_soc_card *card); | 58 | static int snd_soc_unregister_card(struct snd_soc_card *card); |
59 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); | 59 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * This is a timeout to do a DAPM powerdown after a stream is closed(). | 62 | * This is a timeout to do a DAPM powerdown after a stream is closed(). |
63 | * It can be used to eliminate pops between different playback streams, e.g. | 63 | * It can be used to eliminate pops between different playback streams, e.g. |
64 | * between two audio tracks. | 64 | * between two audio tracks. |
65 | */ | 65 | */ |
66 | static int pmdown_time = 5000; | 66 | static int pmdown_time = 5000; |
67 | module_param(pmdown_time, int, 0); | 67 | module_param(pmdown_time, int, 0); |
68 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | 68 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * This function forces any delayed work to be queued and run. | 71 | * This function forces any delayed work to be queued and run. |
72 | */ | 72 | */ |
73 | static int run_delayed_work(struct delayed_work *dwork) | 73 | static int run_delayed_work(struct delayed_work *dwork) |
74 | { | 74 | { |
75 | int ret; | 75 | int ret; |
76 | 76 | ||
77 | /* cancel any work waiting to be queued. */ | 77 | /* cancel any work waiting to be queued. */ |
78 | ret = cancel_delayed_work(dwork); | 78 | ret = cancel_delayed_work(dwork); |
79 | 79 | ||
80 | /* if there was any work waiting then we run it now and | 80 | /* if there was any work waiting then we run it now and |
81 | * wait for it's completion */ | 81 | * wait for it's completion */ |
82 | if (ret) { | 82 | if (ret) { |
83 | schedule_delayed_work(dwork, 0); | 83 | schedule_delayed_work(dwork, 0); |
84 | flush_scheduled_work(); | 84 | flush_scheduled_work(); |
85 | } | 85 | } |
86 | return ret; | 86 | return ret; |
87 | } | 87 | } |
88 | 88 | ||
89 | /* codec register dump */ | 89 | /* codec register dump */ |
90 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | 90 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) |
91 | { | 91 | { |
92 | int ret, i, step = 1, count = 0; | 92 | int ret, i, step = 1, count = 0; |
93 | 93 | ||
94 | if (!codec->driver->reg_cache_size) | 94 | if (!codec->driver->reg_cache_size) |
95 | return 0; | 95 | return 0; |
96 | 96 | ||
97 | if (codec->driver->reg_cache_step) | 97 | if (codec->driver->reg_cache_step) |
98 | step = codec->driver->reg_cache_step; | 98 | step = codec->driver->reg_cache_step; |
99 | 99 | ||
100 | count += sprintf(buf, "%s registers\n", codec->name); | 100 | count += sprintf(buf, "%s registers\n", codec->name); |
101 | for (i = 0; i < codec->driver->reg_cache_size; i += step) { | 101 | for (i = 0; i < codec->driver->reg_cache_size; i += step) { |
102 | if (codec->driver->readable_register && !codec->driver->readable_register(i)) | 102 | if (codec->driver->readable_register && !codec->driver->readable_register(i)) |
103 | continue; | 103 | continue; |
104 | 104 | ||
105 | count += sprintf(buf + count, "%2x: ", i); | 105 | count += sprintf(buf + count, "%2x: ", i); |
106 | if (count >= PAGE_SIZE - 1) | 106 | if (count >= PAGE_SIZE - 1) |
107 | break; | 107 | break; |
108 | 108 | ||
109 | if (codec->driver->display_register) { | 109 | if (codec->driver->display_register) { |
110 | count += codec->driver->display_register(codec, buf + count, | 110 | count += codec->driver->display_register(codec, buf + count, |
111 | PAGE_SIZE - count, i); | 111 | PAGE_SIZE - count, i); |
112 | } else { | 112 | } else { |
113 | /* If the read fails it's almost certainly due to | 113 | /* If the read fails it's almost certainly due to |
114 | * the register being volatile and the device being | 114 | * the register being volatile and the device being |
115 | * powered off. | 115 | * powered off. |
116 | */ | 116 | */ |
117 | ret = codec->driver->read(codec, i); | 117 | ret = codec->driver->read(codec, i); |
118 | if (ret >= 0) | 118 | if (ret >= 0) |
119 | count += snprintf(buf + count, | 119 | count += snprintf(buf + count, |
120 | PAGE_SIZE - count, | 120 | PAGE_SIZE - count, |
121 | "%4x", ret); | 121 | "%4x", ret); |
122 | else | 122 | else |
123 | count += snprintf(buf + count, | 123 | count += snprintf(buf + count, |
124 | PAGE_SIZE - count, | 124 | PAGE_SIZE - count, |
125 | "<no data: %d>", ret); | 125 | "<no data: %d>", ret); |
126 | } | 126 | } |
127 | 127 | ||
128 | if (count >= PAGE_SIZE - 1) | 128 | if (count >= PAGE_SIZE - 1) |
129 | break; | 129 | break; |
130 | 130 | ||
131 | count += snprintf(buf + count, PAGE_SIZE - count, "\n"); | 131 | count += snprintf(buf + count, PAGE_SIZE - count, "\n"); |
132 | if (count >= PAGE_SIZE - 1) | 132 | if (count >= PAGE_SIZE - 1) |
133 | break; | 133 | break; |
134 | } | 134 | } |
135 | 135 | ||
136 | /* Truncate count; min() would cause a warning */ | 136 | /* Truncate count; min() would cause a warning */ |
137 | if (count >= PAGE_SIZE) | 137 | if (count >= PAGE_SIZE) |
138 | count = PAGE_SIZE - 1; | 138 | count = PAGE_SIZE - 1; |
139 | 139 | ||
140 | return count; | 140 | return count; |
141 | } | 141 | } |
142 | static ssize_t codec_reg_show(struct device *dev, | 142 | static ssize_t codec_reg_show(struct device *dev, |
143 | struct device_attribute *attr, char *buf) | 143 | struct device_attribute *attr, char *buf) |
144 | { | 144 | { |
145 | struct snd_soc_pcm_runtime *rtd = | 145 | struct snd_soc_pcm_runtime *rtd = |
146 | container_of(dev, struct snd_soc_pcm_runtime, dev); | 146 | container_of(dev, struct snd_soc_pcm_runtime, dev); |
147 | 147 | ||
148 | return soc_codec_reg_show(rtd->codec, buf); | 148 | return soc_codec_reg_show(rtd->codec, buf); |
149 | } | 149 | } |
150 | 150 | ||
151 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); | 151 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); |
152 | 152 | ||
153 | static ssize_t pmdown_time_show(struct device *dev, | 153 | static ssize_t pmdown_time_show(struct device *dev, |
154 | struct device_attribute *attr, char *buf) | 154 | struct device_attribute *attr, char *buf) |
155 | { | 155 | { |
156 | struct snd_soc_pcm_runtime *rtd = | 156 | struct snd_soc_pcm_runtime *rtd = |
157 | container_of(dev, struct snd_soc_pcm_runtime, dev); | 157 | container_of(dev, struct snd_soc_pcm_runtime, dev); |
158 | 158 | ||
159 | return sprintf(buf, "%ld\n", rtd->pmdown_time); | 159 | return sprintf(buf, "%ld\n", rtd->pmdown_time); |
160 | } | 160 | } |
161 | 161 | ||
162 | static ssize_t pmdown_time_set(struct device *dev, | 162 | static ssize_t pmdown_time_set(struct device *dev, |
163 | struct device_attribute *attr, | 163 | struct device_attribute *attr, |
164 | const char *buf, size_t count) | 164 | const char *buf, size_t count) |
165 | { | 165 | { |
166 | struct snd_soc_pcm_runtime *rtd = | 166 | struct snd_soc_pcm_runtime *rtd = |
167 | container_of(dev, struct snd_soc_pcm_runtime, dev); | 167 | container_of(dev, struct snd_soc_pcm_runtime, dev); |
168 | 168 | ||
169 | strict_strtol(buf, 10, &rtd->pmdown_time); | 169 | strict_strtol(buf, 10, &rtd->pmdown_time); |
170 | 170 | ||
171 | return count; | 171 | return count; |
172 | } | 172 | } |
173 | 173 | ||
174 | static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); | 174 | static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); |
175 | 175 | ||
176 | #ifdef CONFIG_DEBUG_FS | 176 | #ifdef CONFIG_DEBUG_FS |
177 | static int codec_reg_open_file(struct inode *inode, struct file *file) | 177 | static int codec_reg_open_file(struct inode *inode, struct file *file) |
178 | { | 178 | { |
179 | file->private_data = inode->i_private; | 179 | file->private_data = inode->i_private; |
180 | return 0; | 180 | return 0; |
181 | } | 181 | } |
182 | 182 | ||
183 | static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, | 183 | static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, |
184 | size_t count, loff_t *ppos) | 184 | size_t count, loff_t *ppos) |
185 | { | 185 | { |
186 | ssize_t ret; | 186 | ssize_t ret; |
187 | struct snd_soc_codec *codec = file->private_data; | 187 | struct snd_soc_codec *codec = file->private_data; |
188 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 188 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
189 | if (!buf) | 189 | if (!buf) |
190 | return -ENOMEM; | 190 | return -ENOMEM; |
191 | ret = soc_codec_reg_show(codec, buf); | 191 | ret = soc_codec_reg_show(codec, buf); |
192 | if (ret >= 0) | 192 | if (ret >= 0) |
193 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | 193 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); |
194 | kfree(buf); | 194 | kfree(buf); |
195 | return ret; | 195 | return ret; |
196 | } | 196 | } |
197 | 197 | ||
198 | static ssize_t codec_reg_write_file(struct file *file, | 198 | static ssize_t codec_reg_write_file(struct file *file, |
199 | const char __user *user_buf, size_t count, loff_t *ppos) | 199 | const char __user *user_buf, size_t count, loff_t *ppos) |
200 | { | 200 | { |
201 | char buf[32]; | 201 | char buf[32]; |
202 | int buf_size; | 202 | int buf_size; |
203 | char *start = buf; | 203 | char *start = buf; |
204 | unsigned long reg, value; | 204 | unsigned long reg, value; |
205 | int step = 1; | 205 | int step = 1; |
206 | struct snd_soc_codec *codec = file->private_data; | 206 | struct snd_soc_codec *codec = file->private_data; |
207 | 207 | ||
208 | buf_size = min(count, (sizeof(buf)-1)); | 208 | buf_size = min(count, (sizeof(buf)-1)); |
209 | if (copy_from_user(buf, user_buf, buf_size)) | 209 | if (copy_from_user(buf, user_buf, buf_size)) |
210 | return -EFAULT; | 210 | return -EFAULT; |
211 | buf[buf_size] = 0; | 211 | buf[buf_size] = 0; |
212 | 212 | ||
213 | if (codec->driver->reg_cache_step) | 213 | if (codec->driver->reg_cache_step) |
214 | step = codec->driver->reg_cache_step; | 214 | step = codec->driver->reg_cache_step; |
215 | 215 | ||
216 | while (*start == ' ') | 216 | while (*start == ' ') |
217 | start++; | 217 | start++; |
218 | reg = simple_strtoul(start, &start, 16); | 218 | reg = simple_strtoul(start, &start, 16); |
219 | if ((reg >= codec->driver->reg_cache_size) || (reg % step)) | 219 | if ((reg >= codec->driver->reg_cache_size) || (reg % step)) |
220 | return -EINVAL; | 220 | return -EINVAL; |
221 | while (*start == ' ') | 221 | while (*start == ' ') |
222 | start++; | 222 | start++; |
223 | if (strict_strtoul(start, 16, &value)) | 223 | if (strict_strtoul(start, 16, &value)) |
224 | return -EINVAL; | 224 | return -EINVAL; |
225 | codec->driver->write(codec, reg, value); | 225 | codec->driver->write(codec, reg, value); |
226 | return buf_size; | 226 | return buf_size; |
227 | } | 227 | } |
228 | 228 | ||
229 | static const struct file_operations codec_reg_fops = { | 229 | static const struct file_operations codec_reg_fops = { |
230 | .open = codec_reg_open_file, | 230 | .open = codec_reg_open_file, |
231 | .read = codec_reg_read_file, | 231 | .read = codec_reg_read_file, |
232 | .write = codec_reg_write_file, | 232 | .write = codec_reg_write_file, |
233 | }; | 233 | }; |
234 | 234 | ||
235 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | 235 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) |
236 | { | 236 | { |
237 | codec->debugfs_codec_root = debugfs_create_dir(codec->name , | 237 | codec->debugfs_codec_root = debugfs_create_dir(codec->name , |
238 | debugfs_root); | 238 | debugfs_root); |
239 | if (!codec->debugfs_codec_root) { | 239 | if (!codec->debugfs_codec_root) { |
240 | printk(KERN_WARNING | 240 | printk(KERN_WARNING |
241 | "ASoC: Failed to create codec debugfs directory\n"); | 241 | "ASoC: Failed to create codec debugfs directory\n"); |
242 | return; | 242 | return; |
243 | } | 243 | } |
244 | 244 | ||
245 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 245 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
246 | codec->debugfs_codec_root, | 246 | codec->debugfs_codec_root, |
247 | codec, &codec_reg_fops); | 247 | codec, &codec_reg_fops); |
248 | if (!codec->debugfs_reg) | 248 | if (!codec->debugfs_reg) |
249 | printk(KERN_WARNING | 249 | printk(KERN_WARNING |
250 | "ASoC: Failed to create codec register debugfs file\n"); | 250 | "ASoC: Failed to create codec register debugfs file\n"); |
251 | 251 | ||
252 | codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, | 252 | codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, |
253 | codec->debugfs_codec_root, | 253 | codec->debugfs_codec_root, |
254 | &codec->pop_time); | 254 | &codec->pop_time); |
255 | if (!codec->debugfs_pop_time) | 255 | if (!codec->debugfs_pop_time) |
256 | printk(KERN_WARNING | 256 | printk(KERN_WARNING |
257 | "Failed to create pop time debugfs file\n"); | 257 | "Failed to create pop time debugfs file\n"); |
258 | 258 | ||
259 | codec->debugfs_dapm = debugfs_create_dir("dapm", | 259 | codec->debugfs_dapm = debugfs_create_dir("dapm", |
260 | codec->debugfs_codec_root); | 260 | codec->debugfs_codec_root); |
261 | if (!codec->debugfs_dapm) | 261 | if (!codec->debugfs_dapm) |
262 | printk(KERN_WARNING | 262 | printk(KERN_WARNING |
263 | "Failed to create DAPM debugfs directory\n"); | 263 | "Failed to create DAPM debugfs directory\n"); |
264 | 264 | ||
265 | snd_soc_dapm_debugfs_init(codec); | 265 | snd_soc_dapm_debugfs_init(codec); |
266 | } | 266 | } |
267 | 267 | ||
268 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | 268 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) |
269 | { | 269 | { |
270 | debugfs_remove_recursive(codec->debugfs_codec_root); | 270 | debugfs_remove_recursive(codec->debugfs_codec_root); |
271 | } | 271 | } |
272 | 272 | ||
273 | static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, | 273 | static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, |
274 | size_t count, loff_t *ppos) | 274 | size_t count, loff_t *ppos) |
275 | { | 275 | { |
276 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 276 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
277 | ssize_t ret = 0; | 277 | ssize_t ret = 0; |
278 | struct snd_soc_codec *codec; | 278 | struct snd_soc_codec *codec; |
279 | 279 | ||
280 | if (!buf) | 280 | if (!buf) |
281 | return -ENOMEM; | 281 | return -ENOMEM; |
282 | 282 | ||
283 | list_for_each_entry(codec, &codec_list, list) | 283 | list_for_each_entry(codec, &codec_list, list) |
284 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", | 284 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
285 | codec->name); | 285 | codec->name); |
286 | 286 | ||
287 | if (ret >= 0) | 287 | if (ret >= 0) |
288 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | 288 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); |
289 | 289 | ||
290 | kfree(buf); | 290 | kfree(buf); |
291 | 291 | ||
292 | return ret; | 292 | return ret; |
293 | } | 293 | } |
294 | 294 | ||
295 | static const struct file_operations codec_list_fops = { | 295 | static const struct file_operations codec_list_fops = { |
296 | .read = codec_list_read_file, | 296 | .read = codec_list_read_file, |
297 | .llseek = default_llseek,/* read accesses f_pos */ | 297 | .llseek = default_llseek,/* read accesses f_pos */ |
298 | }; | 298 | }; |
299 | 299 | ||
300 | static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, | 300 | static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, |
301 | size_t count, loff_t *ppos) | 301 | size_t count, loff_t *ppos) |
302 | { | 302 | { |
303 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 303 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
304 | ssize_t ret = 0; | 304 | ssize_t ret = 0; |
305 | struct snd_soc_dai *dai; | 305 | struct snd_soc_dai *dai; |
306 | 306 | ||
307 | if (!buf) | 307 | if (!buf) |
308 | return -ENOMEM; | 308 | return -ENOMEM; |
309 | 309 | ||
310 | list_for_each_entry(dai, &dai_list, list) | 310 | list_for_each_entry(dai, &dai_list, list) |
311 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); | 311 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); |
312 | 312 | ||
313 | if (ret >= 0) | 313 | if (ret >= 0) |
314 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | 314 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); |
315 | 315 | ||
316 | kfree(buf); | 316 | kfree(buf); |
317 | 317 | ||
318 | return ret; | 318 | return ret; |
319 | } | 319 | } |
320 | 320 | ||
321 | static const struct file_operations dai_list_fops = { | 321 | static const struct file_operations dai_list_fops = { |
322 | .read = dai_list_read_file, | 322 | .read = dai_list_read_file, |
323 | .llseek = default_llseek,/* read accesses f_pos */ | 323 | .llseek = default_llseek,/* read accesses f_pos */ |
324 | }; | 324 | }; |
325 | 325 | ||
326 | static ssize_t platform_list_read_file(struct file *file, | 326 | static ssize_t platform_list_read_file(struct file *file, |
327 | char __user *user_buf, | 327 | char __user *user_buf, |
328 | size_t count, loff_t *ppos) | 328 | size_t count, loff_t *ppos) |
329 | { | 329 | { |
330 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 330 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
331 | ssize_t ret = 0; | 331 | ssize_t ret = 0; |
332 | struct snd_soc_platform *platform; | 332 | struct snd_soc_platform *platform; |
333 | 333 | ||
334 | if (!buf) | 334 | if (!buf) |
335 | return -ENOMEM; | 335 | return -ENOMEM; |
336 | 336 | ||
337 | list_for_each_entry(platform, &platform_list, list) | 337 | list_for_each_entry(platform, &platform_list, list) |
338 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", | 338 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
339 | platform->name); | 339 | platform->name); |
340 | 340 | ||
341 | if (ret >= 0) | 341 | if (ret >= 0) |
342 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | 342 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); |
343 | 343 | ||
344 | kfree(buf); | 344 | kfree(buf); |
345 | 345 | ||
346 | return ret; | 346 | return ret; |
347 | } | 347 | } |
348 | 348 | ||
349 | static const struct file_operations platform_list_fops = { | 349 | static const struct file_operations platform_list_fops = { |
350 | .read = platform_list_read_file, | 350 | .read = platform_list_read_file, |
351 | .llseek = default_llseek,/* read accesses f_pos */ | 351 | .llseek = default_llseek,/* read accesses f_pos */ |
352 | }; | 352 | }; |
353 | 353 | ||
354 | #else | 354 | #else |
355 | 355 | ||
356 | static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) | 356 | static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) |
357 | { | 357 | { |
358 | } | 358 | } |
359 | 359 | ||
360 | static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | 360 | static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) |
361 | { | 361 | { |
362 | } | 362 | } |
363 | #endif | 363 | #endif |
364 | 364 | ||
365 | #ifdef CONFIG_SND_SOC_AC97_BUS | 365 | #ifdef CONFIG_SND_SOC_AC97_BUS |
366 | /* unregister ac97 codec */ | 366 | /* unregister ac97 codec */ |
367 | static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) | 367 | static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) |
368 | { | 368 | { |
369 | if (codec->ac97->dev.bus) | 369 | if (codec->ac97->dev.bus) |
370 | device_unregister(&codec->ac97->dev); | 370 | device_unregister(&codec->ac97->dev); |
371 | return 0; | 371 | return 0; |
372 | } | 372 | } |
373 | 373 | ||
374 | /* stop no dev release warning */ | 374 | /* stop no dev release warning */ |
375 | static void soc_ac97_device_release(struct device *dev){} | 375 | static void soc_ac97_device_release(struct device *dev){} |
376 | 376 | ||
377 | /* register ac97 codec to bus */ | 377 | /* register ac97 codec to bus */ |
378 | static int soc_ac97_dev_register(struct snd_soc_codec *codec) | 378 | static int soc_ac97_dev_register(struct snd_soc_codec *codec) |
379 | { | 379 | { |
380 | int err; | 380 | int err; |
381 | 381 | ||
382 | codec->ac97->dev.bus = &ac97_bus_type; | 382 | codec->ac97->dev.bus = &ac97_bus_type; |
383 | codec->ac97->dev.parent = codec->card->dev; | 383 | codec->ac97->dev.parent = codec->card->dev; |
384 | codec->ac97->dev.release = soc_ac97_device_release; | 384 | codec->ac97->dev.release = soc_ac97_device_release; |
385 | 385 | ||
386 | dev_set_name(&codec->ac97->dev, "%d-%d:%s", | 386 | dev_set_name(&codec->ac97->dev, "%d-%d:%s", |
387 | codec->card->snd_card->number, 0, codec->name); | 387 | codec->card->snd_card->number, 0, codec->name); |
388 | err = device_register(&codec->ac97->dev); | 388 | err = device_register(&codec->ac97->dev); |
389 | if (err < 0) { | 389 | if (err < 0) { |
390 | snd_printk(KERN_ERR "Can't register ac97 bus\n"); | 390 | snd_printk(KERN_ERR "Can't register ac97 bus\n"); |
391 | codec->ac97->dev.bus = NULL; | 391 | codec->ac97->dev.bus = NULL; |
392 | return err; | 392 | return err; |
393 | } | 393 | } |
394 | return 0; | 394 | return 0; |
395 | } | 395 | } |
396 | #endif | 396 | #endif |
397 | 397 | ||
398 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) | 398 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) |
399 | { | 399 | { |
400 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 400 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
401 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 401 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
402 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 402 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
403 | int ret; | 403 | int ret; |
404 | 404 | ||
405 | if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates || | 405 | if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates || |
406 | rtd->dai_link->symmetric_rates) { | 406 | rtd->dai_link->symmetric_rates) { |
407 | dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", | 407 | dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", |
408 | rtd->rate); | 408 | rtd->rate); |
409 | 409 | ||
410 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, | 410 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, |
411 | SNDRV_PCM_HW_PARAM_RATE, | 411 | SNDRV_PCM_HW_PARAM_RATE, |
412 | rtd->rate, | 412 | rtd->rate, |
413 | rtd->rate); | 413 | rtd->rate); |
414 | if (ret < 0) { | 414 | if (ret < 0) { |
415 | dev_err(&rtd->dev, | 415 | dev_err(&rtd->dev, |
416 | "Unable to apply rate symmetry constraint: %d\n", ret); | 416 | "Unable to apply rate symmetry constraint: %d\n", ret); |
417 | return ret; | 417 | return ret; |
418 | } | 418 | } |
419 | } | 419 | } |
420 | 420 | ||
421 | return 0; | 421 | return 0; |
422 | } | 422 | } |
423 | 423 | ||
424 | /* | 424 | /* |
425 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | 425 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is |
426 | * then initialized and any private data can be allocated. This also calls | 426 | * then initialized and any private data can be allocated. This also calls |
427 | * startup for the cpu DAI, platform, machine and codec DAI. | 427 | * startup for the cpu DAI, platform, machine and codec DAI. |
428 | */ | 428 | */ |
429 | static int soc_pcm_open(struct snd_pcm_substream *substream) | 429 | static int soc_pcm_open(struct snd_pcm_substream *substream) |
430 | { | 430 | { |
431 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 431 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
432 | struct snd_pcm_runtime *runtime = substream->runtime; | 432 | struct snd_pcm_runtime *runtime = substream->runtime; |
433 | struct snd_soc_platform *platform = rtd->platform; | 433 | struct snd_soc_platform *platform = rtd->platform; |
434 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 434 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
435 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 435 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
436 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 436 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; |
437 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | 437 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; |
438 | int ret = 0; | 438 | int ret = 0; |
439 | 439 | ||
440 | mutex_lock(&pcm_mutex); | 440 | mutex_lock(&pcm_mutex); |
441 | 441 | ||
442 | /* startup the audio subsystem */ | 442 | /* startup the audio subsystem */ |
443 | if (cpu_dai->driver->ops->startup) { | 443 | if (cpu_dai->driver->ops->startup) { |
444 | ret = cpu_dai->driver->ops->startup(substream, cpu_dai); | 444 | ret = cpu_dai->driver->ops->startup(substream, cpu_dai); |
445 | if (ret < 0) { | 445 | if (ret < 0) { |
446 | printk(KERN_ERR "asoc: can't open interface %s\n", | 446 | printk(KERN_ERR "asoc: can't open interface %s\n", |
447 | cpu_dai->name); | 447 | cpu_dai->name); |
448 | goto out; | 448 | goto out; |
449 | } | 449 | } |
450 | } | 450 | } |
451 | 451 | ||
452 | if (platform->driver->ops->open) { | 452 | if (platform->driver->ops->open) { |
453 | ret = platform->driver->ops->open(substream); | 453 | ret = platform->driver->ops->open(substream); |
454 | if (ret < 0) { | 454 | if (ret < 0) { |
455 | printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); | 455 | printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); |
456 | goto platform_err; | 456 | goto platform_err; |
457 | } | 457 | } |
458 | } | 458 | } |
459 | 459 | ||
460 | if (codec_dai->driver->ops->startup) { | 460 | if (codec_dai->driver->ops->startup) { |
461 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | 461 | ret = codec_dai->driver->ops->startup(substream, codec_dai); |
462 | if (ret < 0) { | 462 | if (ret < 0) { |
463 | printk(KERN_ERR "asoc: can't open codec %s\n", | 463 | printk(KERN_ERR "asoc: can't open codec %s\n", |
464 | codec_dai->name); | 464 | codec_dai->name); |
465 | goto codec_dai_err; | 465 | goto codec_dai_err; |
466 | } | 466 | } |
467 | } | 467 | } |
468 | 468 | ||
469 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | 469 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { |
470 | ret = rtd->dai_link->ops->startup(substream); | 470 | ret = rtd->dai_link->ops->startup(substream); |
471 | if (ret < 0) { | 471 | if (ret < 0) { |
472 | printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); | 472 | printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); |
473 | goto machine_err; | 473 | goto machine_err; |
474 | } | 474 | } |
475 | } | 475 | } |
476 | 476 | ||
477 | /* Check that the codec and cpu DAI's are compatible */ | 477 | /* Check that the codec and cpu DAI's are compatible */ |
478 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 478 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
479 | runtime->hw.rate_min = | 479 | runtime->hw.rate_min = |
480 | max(codec_dai_drv->playback.rate_min, | 480 | max(codec_dai_drv->playback.rate_min, |
481 | cpu_dai_drv->playback.rate_min); | 481 | cpu_dai_drv->playback.rate_min); |
482 | runtime->hw.rate_max = | 482 | runtime->hw.rate_max = |
483 | min(codec_dai_drv->playback.rate_max, | 483 | min(codec_dai_drv->playback.rate_max, |
484 | cpu_dai_drv->playback.rate_max); | 484 | cpu_dai_drv->playback.rate_max); |
485 | runtime->hw.channels_min = | 485 | runtime->hw.channels_min = |
486 | max(codec_dai_drv->playback.channels_min, | 486 | max(codec_dai_drv->playback.channels_min, |
487 | cpu_dai_drv->playback.channels_min); | 487 | cpu_dai_drv->playback.channels_min); |
488 | runtime->hw.channels_max = | 488 | runtime->hw.channels_max = |
489 | min(codec_dai_drv->playback.channels_max, | 489 | min(codec_dai_drv->playback.channels_max, |
490 | cpu_dai_drv->playback.channels_max); | 490 | cpu_dai_drv->playback.channels_max); |
491 | runtime->hw.formats = | 491 | runtime->hw.formats = |
492 | codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats; | 492 | codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats; |
493 | runtime->hw.rates = | 493 | runtime->hw.rates = |
494 | codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates; | 494 | codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates; |
495 | if (codec_dai_drv->playback.rates | 495 | if (codec_dai_drv->playback.rates |
496 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 496 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
497 | runtime->hw.rates |= cpu_dai_drv->playback.rates; | 497 | runtime->hw.rates |= cpu_dai_drv->playback.rates; |
498 | if (cpu_dai_drv->playback.rates | 498 | if (cpu_dai_drv->playback.rates |
499 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 499 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
500 | runtime->hw.rates |= codec_dai_drv->playback.rates; | 500 | runtime->hw.rates |= codec_dai_drv->playback.rates; |
501 | } else { | 501 | } else { |
502 | runtime->hw.rate_min = | 502 | runtime->hw.rate_min = |
503 | max(codec_dai_drv->capture.rate_min, | 503 | max(codec_dai_drv->capture.rate_min, |
504 | cpu_dai_drv->capture.rate_min); | 504 | cpu_dai_drv->capture.rate_min); |
505 | runtime->hw.rate_max = | 505 | runtime->hw.rate_max = |
506 | min(codec_dai_drv->capture.rate_max, | 506 | min(codec_dai_drv->capture.rate_max, |
507 | cpu_dai_drv->capture.rate_max); | 507 | cpu_dai_drv->capture.rate_max); |
508 | runtime->hw.channels_min = | 508 | runtime->hw.channels_min = |
509 | max(codec_dai_drv->capture.channels_min, | 509 | max(codec_dai_drv->capture.channels_min, |
510 | cpu_dai_drv->capture.channels_min); | 510 | cpu_dai_drv->capture.channels_min); |
511 | runtime->hw.channels_max = | 511 | runtime->hw.channels_max = |
512 | min(codec_dai_drv->capture.channels_max, | 512 | min(codec_dai_drv->capture.channels_max, |
513 | cpu_dai_drv->capture.channels_max); | 513 | cpu_dai_drv->capture.channels_max); |
514 | runtime->hw.formats = | 514 | runtime->hw.formats = |
515 | codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats; | 515 | codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats; |
516 | runtime->hw.rates = | 516 | runtime->hw.rates = |
517 | codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates; | 517 | codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates; |
518 | if (codec_dai_drv->capture.rates | 518 | if (codec_dai_drv->capture.rates |
519 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 519 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
520 | runtime->hw.rates |= cpu_dai_drv->capture.rates; | 520 | runtime->hw.rates |= cpu_dai_drv->capture.rates; |
521 | if (cpu_dai_drv->capture.rates | 521 | if (cpu_dai_drv->capture.rates |
522 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 522 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
523 | runtime->hw.rates |= codec_dai_drv->capture.rates; | 523 | runtime->hw.rates |= codec_dai_drv->capture.rates; |
524 | } | 524 | } |
525 | 525 | ||
526 | snd_pcm_limit_hw_rates(runtime); | 526 | snd_pcm_limit_hw_rates(runtime); |
527 | if (!runtime->hw.rates) { | 527 | if (!runtime->hw.rates) { |
528 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | 528 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", |
529 | codec_dai->name, cpu_dai->name); | 529 | codec_dai->name, cpu_dai->name); |
530 | goto config_err; | 530 | goto config_err; |
531 | } | 531 | } |
532 | if (!runtime->hw.formats) { | 532 | if (!runtime->hw.formats) { |
533 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | 533 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", |
534 | codec_dai->name, cpu_dai->name); | 534 | codec_dai->name, cpu_dai->name); |
535 | goto config_err; | 535 | goto config_err; |
536 | } | 536 | } |
537 | if (!runtime->hw.channels_min || !runtime->hw.channels_max) { | 537 | if (!runtime->hw.channels_min || !runtime->hw.channels_max) { |
538 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | 538 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", |
539 | codec_dai->name, cpu_dai->name); | 539 | codec_dai->name, cpu_dai->name); |
540 | goto config_err; | 540 | goto config_err; |
541 | } | 541 | } |
542 | 542 | ||
543 | /* Symmetry only applies if we've already got an active stream. */ | 543 | /* Symmetry only applies if we've already got an active stream. */ |
544 | if (cpu_dai->active || codec_dai->active) { | 544 | if (cpu_dai->active || codec_dai->active) { |
545 | ret = soc_pcm_apply_symmetry(substream); | 545 | ret = soc_pcm_apply_symmetry(substream); |
546 | if (ret != 0) | 546 | if (ret != 0) |
547 | goto config_err; | 547 | goto config_err; |
548 | } | 548 | } |
549 | 549 | ||
550 | pr_debug("asoc: %s <-> %s info:\n", | 550 | pr_debug("asoc: %s <-> %s info:\n", |
551 | codec_dai->name, cpu_dai->name); | 551 | codec_dai->name, cpu_dai->name); |
552 | pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); | 552 | pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); |
553 | pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | 553 | pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, |
554 | runtime->hw.channels_max); | 554 | runtime->hw.channels_max); |
555 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | 555 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, |
556 | runtime->hw.rate_max); | 556 | runtime->hw.rate_max); |
557 | 557 | ||
558 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 558 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
559 | cpu_dai->playback_active++; | 559 | cpu_dai->playback_active++; |
560 | codec_dai->playback_active++; | 560 | codec_dai->playback_active++; |
561 | } else { | 561 | } else { |
562 | cpu_dai->capture_active++; | 562 | cpu_dai->capture_active++; |
563 | codec_dai->capture_active++; | 563 | codec_dai->capture_active++; |
564 | } | 564 | } |
565 | cpu_dai->active++; | 565 | cpu_dai->active++; |
566 | codec_dai->active++; | 566 | codec_dai->active++; |
567 | rtd->codec->active++; | 567 | rtd->codec->active++; |
568 | mutex_unlock(&pcm_mutex); | 568 | mutex_unlock(&pcm_mutex); |
569 | return 0; | 569 | return 0; |
570 | 570 | ||
571 | config_err: | 571 | config_err: |
572 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 572 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
573 | rtd->dai_link->ops->shutdown(substream); | 573 | rtd->dai_link->ops->shutdown(substream); |
574 | 574 | ||
575 | machine_err: | 575 | machine_err: |
576 | if (codec_dai->driver->ops->shutdown) | 576 | if (codec_dai->driver->ops->shutdown) |
577 | codec_dai->driver->ops->shutdown(substream, codec_dai); | 577 | codec_dai->driver->ops->shutdown(substream, codec_dai); |
578 | 578 | ||
579 | codec_dai_err: | 579 | codec_dai_err: |
580 | if (platform->driver->ops->close) | 580 | if (platform->driver->ops->close) |
581 | platform->driver->ops->close(substream); | 581 | platform->driver->ops->close(substream); |
582 | 582 | ||
583 | platform_err: | 583 | platform_err: |
584 | if (cpu_dai->driver->ops->shutdown) | 584 | if (cpu_dai->driver->ops->shutdown) |
585 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 585 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
586 | out: | 586 | out: |
587 | mutex_unlock(&pcm_mutex); | 587 | mutex_unlock(&pcm_mutex); |
588 | return ret; | 588 | return ret; |
589 | } | 589 | } |
590 | 590 | ||
591 | /* | 591 | /* |
592 | * Power down the audio subsystem pmdown_time msecs after close is called. | 592 | * Power down the audio subsystem pmdown_time msecs after close is called. |
593 | * This is to ensure there are no pops or clicks in between any music tracks | 593 | * This is to ensure there are no pops or clicks in between any music tracks |
594 | * due to DAPM power cycling. | 594 | * due to DAPM power cycling. |
595 | */ | 595 | */ |
596 | static void close_delayed_work(struct work_struct *work) | 596 | static void close_delayed_work(struct work_struct *work) |
597 | { | 597 | { |
598 | struct snd_soc_pcm_runtime *rtd = | 598 | struct snd_soc_pcm_runtime *rtd = |
599 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | 599 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
600 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 600 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
601 | 601 | ||
602 | mutex_lock(&pcm_mutex); | 602 | mutex_lock(&pcm_mutex); |
603 | 603 | ||
604 | pr_debug("pop wq checking: %s status: %s waiting: %s\n", | 604 | pr_debug("pop wq checking: %s status: %s waiting: %s\n", |
605 | codec_dai->driver->playback.stream_name, | 605 | codec_dai->driver->playback.stream_name, |
606 | codec_dai->playback_active ? "active" : "inactive", | 606 | codec_dai->playback_active ? "active" : "inactive", |
607 | codec_dai->pop_wait ? "yes" : "no"); | 607 | codec_dai->pop_wait ? "yes" : "no"); |
608 | 608 | ||
609 | /* are we waiting on this codec DAI stream */ | 609 | /* are we waiting on this codec DAI stream */ |
610 | if (codec_dai->pop_wait == 1) { | 610 | if (codec_dai->pop_wait == 1) { |
611 | codec_dai->pop_wait = 0; | 611 | codec_dai->pop_wait = 0; |
612 | snd_soc_dapm_stream_event(rtd, | 612 | snd_soc_dapm_stream_event(rtd, |
613 | codec_dai->driver->playback.stream_name, | 613 | codec_dai->driver->playback.stream_name, |
614 | SND_SOC_DAPM_STREAM_STOP); | 614 | SND_SOC_DAPM_STREAM_STOP); |
615 | } | 615 | } |
616 | 616 | ||
617 | mutex_unlock(&pcm_mutex); | 617 | mutex_unlock(&pcm_mutex); |
618 | } | 618 | } |
619 | 619 | ||
620 | /* | 620 | /* |
621 | * Called by ALSA when a PCM substream is closed. Private data can be | 621 | * Called by ALSA when a PCM substream is closed. Private data can be |
622 | * freed here. The cpu DAI, codec DAI, machine and platform are also | 622 | * freed here. The cpu DAI, codec DAI, machine and platform are also |
623 | * shutdown. | 623 | * shutdown. |
624 | */ | 624 | */ |
625 | static int soc_codec_close(struct snd_pcm_substream *substream) | 625 | static int soc_codec_close(struct snd_pcm_substream *substream) |
626 | { | 626 | { |
627 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 627 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
628 | struct snd_soc_platform *platform = rtd->platform; | 628 | struct snd_soc_platform *platform = rtd->platform; |
629 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 629 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
630 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 630 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
631 | struct snd_soc_codec *codec = rtd->codec; | 631 | struct snd_soc_codec *codec = rtd->codec; |
632 | 632 | ||
633 | mutex_lock(&pcm_mutex); | 633 | mutex_lock(&pcm_mutex); |
634 | 634 | ||
635 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 635 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
636 | cpu_dai->playback_active--; | 636 | cpu_dai->playback_active--; |
637 | codec_dai->playback_active--; | 637 | codec_dai->playback_active--; |
638 | } else { | 638 | } else { |
639 | cpu_dai->capture_active--; | 639 | cpu_dai->capture_active--; |
640 | codec_dai->capture_active--; | 640 | codec_dai->capture_active--; |
641 | } | 641 | } |
642 | 642 | ||
643 | cpu_dai->active--; | 643 | cpu_dai->active--; |
644 | codec_dai->active--; | 644 | codec_dai->active--; |
645 | codec->active--; | 645 | codec->active--; |
646 | 646 | ||
647 | /* Muting the DAC suppresses artifacts caused during digital | 647 | /* Muting the DAC suppresses artifacts caused during digital |
648 | * shutdown, for example from stopping clocks. | 648 | * shutdown, for example from stopping clocks. |
649 | */ | 649 | */ |
650 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 650 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
651 | snd_soc_dai_digital_mute(codec_dai, 1); | 651 | snd_soc_dai_digital_mute(codec_dai, 1); |
652 | 652 | ||
653 | if (cpu_dai->driver->ops->shutdown) | 653 | if (cpu_dai->driver->ops->shutdown) |
654 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 654 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
655 | 655 | ||
656 | if (codec_dai->driver->ops->shutdown) | 656 | if (codec_dai->driver->ops->shutdown) |
657 | codec_dai->driver->ops->shutdown(substream, codec_dai); | 657 | codec_dai->driver->ops->shutdown(substream, codec_dai); |
658 | 658 | ||
659 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 659 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
660 | rtd->dai_link->ops->shutdown(substream); | 660 | rtd->dai_link->ops->shutdown(substream); |
661 | 661 | ||
662 | if (platform->driver->ops->close) | 662 | if (platform->driver->ops->close) |
663 | platform->driver->ops->close(substream); | 663 | platform->driver->ops->close(substream); |
664 | cpu_dai->runtime = NULL; | 664 | cpu_dai->runtime = NULL; |
665 | 665 | ||
666 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 666 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
667 | /* start delayed pop wq here for playback streams */ | 667 | /* start delayed pop wq here for playback streams */ |
668 | codec_dai->pop_wait = 1; | 668 | codec_dai->pop_wait = 1; |
669 | schedule_delayed_work(&rtd->delayed_work, | 669 | schedule_delayed_work(&rtd->delayed_work, |
670 | msecs_to_jiffies(rtd->pmdown_time)); | 670 | msecs_to_jiffies(rtd->pmdown_time)); |
671 | } else { | 671 | } else { |
672 | /* capture streams can be powered down now */ | 672 | /* capture streams can be powered down now */ |
673 | snd_soc_dapm_stream_event(rtd, | 673 | snd_soc_dapm_stream_event(rtd, |
674 | codec_dai->driver->capture.stream_name, | 674 | codec_dai->driver->capture.stream_name, |
675 | SND_SOC_DAPM_STREAM_STOP); | 675 | SND_SOC_DAPM_STREAM_STOP); |
676 | } | 676 | } |
677 | 677 | ||
678 | mutex_unlock(&pcm_mutex); | 678 | mutex_unlock(&pcm_mutex); |
679 | return 0; | 679 | return 0; |
680 | } | 680 | } |
681 | 681 | ||
682 | /* | 682 | /* |
683 | * Called by ALSA when the PCM substream is prepared, can set format, sample | 683 | * Called by ALSA when the PCM substream is prepared, can set format, sample |
684 | * rate, etc. This function is non atomic and can be called multiple times, | 684 | * rate, etc. This function is non atomic and can be called multiple times, |
685 | * it can refer to the runtime info. | 685 | * it can refer to the runtime info. |
686 | */ | 686 | */ |
687 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) | 687 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) |
688 | { | 688 | { |
689 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 689 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
690 | struct snd_soc_platform *platform = rtd->platform; | 690 | struct snd_soc_platform *platform = rtd->platform; |
691 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 691 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
692 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 692 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
693 | int ret = 0; | 693 | int ret = 0; |
694 | 694 | ||
695 | mutex_lock(&pcm_mutex); | 695 | mutex_lock(&pcm_mutex); |
696 | 696 | ||
697 | if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { | 697 | if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { |
698 | ret = rtd->dai_link->ops->prepare(substream); | 698 | ret = rtd->dai_link->ops->prepare(substream); |
699 | if (ret < 0) { | 699 | if (ret < 0) { |
700 | printk(KERN_ERR "asoc: machine prepare error\n"); | 700 | printk(KERN_ERR "asoc: machine prepare error\n"); |
701 | goto out; | 701 | goto out; |
702 | } | 702 | } |
703 | } | 703 | } |
704 | 704 | ||
705 | if (platform->driver->ops->prepare) { | 705 | if (platform->driver->ops->prepare) { |
706 | ret = platform->driver->ops->prepare(substream); | 706 | ret = platform->driver->ops->prepare(substream); |
707 | if (ret < 0) { | 707 | if (ret < 0) { |
708 | printk(KERN_ERR "asoc: platform prepare error\n"); | 708 | printk(KERN_ERR "asoc: platform prepare error\n"); |
709 | goto out; | 709 | goto out; |
710 | } | 710 | } |
711 | } | 711 | } |
712 | 712 | ||
713 | if (codec_dai->driver->ops->prepare) { | 713 | if (codec_dai->driver->ops->prepare) { |
714 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | 714 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); |
715 | if (ret < 0) { | 715 | if (ret < 0) { |
716 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | 716 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); |
717 | goto out; | 717 | goto out; |
718 | } | 718 | } |
719 | } | 719 | } |
720 | 720 | ||
721 | if (cpu_dai->driver->ops->prepare) { | 721 | if (cpu_dai->driver->ops->prepare) { |
722 | ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); | 722 | ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); |
723 | if (ret < 0) { | 723 | if (ret < 0) { |
724 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); | 724 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); |
725 | goto out; | 725 | goto out; |
726 | } | 726 | } |
727 | } | 727 | } |
728 | 728 | ||
729 | /* cancel any delayed stream shutdown that is pending */ | 729 | /* cancel any delayed stream shutdown that is pending */ |
730 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 730 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
731 | codec_dai->pop_wait) { | 731 | codec_dai->pop_wait) { |
732 | codec_dai->pop_wait = 0; | 732 | codec_dai->pop_wait = 0; |
733 | cancel_delayed_work(&rtd->delayed_work); | 733 | cancel_delayed_work(&rtd->delayed_work); |
734 | } | 734 | } |
735 | 735 | ||
736 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 736 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
737 | snd_soc_dapm_stream_event(rtd, | 737 | snd_soc_dapm_stream_event(rtd, |
738 | codec_dai->driver->playback.stream_name, | 738 | codec_dai->driver->playback.stream_name, |
739 | SND_SOC_DAPM_STREAM_START); | 739 | SND_SOC_DAPM_STREAM_START); |
740 | else | 740 | else |
741 | snd_soc_dapm_stream_event(rtd, | 741 | snd_soc_dapm_stream_event(rtd, |
742 | codec_dai->driver->capture.stream_name, | 742 | codec_dai->driver->capture.stream_name, |
743 | SND_SOC_DAPM_STREAM_START); | 743 | SND_SOC_DAPM_STREAM_START); |
744 | 744 | ||
745 | snd_soc_dai_digital_mute(codec_dai, 0); | 745 | snd_soc_dai_digital_mute(codec_dai, 0); |
746 | 746 | ||
747 | out: | 747 | out: |
748 | mutex_unlock(&pcm_mutex); | 748 | mutex_unlock(&pcm_mutex); |
749 | return ret; | 749 | return ret; |
750 | } | 750 | } |
751 | 751 | ||
752 | /* | 752 | /* |
753 | * Called by ALSA when the hardware params are set by application. This | 753 | * Called by ALSA when the hardware params are set by application. This |
754 | * function can also be called multiple times and can allocate buffers | 754 | * function can also be called multiple times and can allocate buffers |
755 | * (using snd_pcm_lib_* ). It's non-atomic. | 755 | * (using snd_pcm_lib_* ). It's non-atomic. |
756 | */ | 756 | */ |
757 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | 757 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, |
758 | struct snd_pcm_hw_params *params) | 758 | struct snd_pcm_hw_params *params) |
759 | { | 759 | { |
760 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 760 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
761 | struct snd_soc_platform *platform = rtd->platform; | 761 | struct snd_soc_platform *platform = rtd->platform; |
762 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 762 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
763 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 763 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
764 | int ret = 0; | 764 | int ret = 0; |
765 | 765 | ||
766 | mutex_lock(&pcm_mutex); | 766 | mutex_lock(&pcm_mutex); |
767 | 767 | ||
768 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { | 768 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { |
769 | ret = rtd->dai_link->ops->hw_params(substream, params); | 769 | ret = rtd->dai_link->ops->hw_params(substream, params); |
770 | if (ret < 0) { | 770 | if (ret < 0) { |
771 | printk(KERN_ERR "asoc: machine hw_params failed\n"); | 771 | printk(KERN_ERR "asoc: machine hw_params failed\n"); |
772 | goto out; | 772 | goto out; |
773 | } | 773 | } |
774 | } | 774 | } |
775 | 775 | ||
776 | if (codec_dai->driver->ops->hw_params) { | 776 | if (codec_dai->driver->ops->hw_params) { |
777 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | 777 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); |
778 | if (ret < 0) { | 778 | if (ret < 0) { |
779 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | 779 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", |
780 | codec_dai->name); | 780 | codec_dai->name); |
781 | goto codec_err; | 781 | goto codec_err; |
782 | } | 782 | } |
783 | } | 783 | } |
784 | 784 | ||
785 | if (cpu_dai->driver->ops->hw_params) { | 785 | if (cpu_dai->driver->ops->hw_params) { |
786 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); | 786 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); |
787 | if (ret < 0) { | 787 | if (ret < 0) { |
788 | printk(KERN_ERR "asoc: interface %s hw params failed\n", | 788 | printk(KERN_ERR "asoc: interface %s hw params failed\n", |
789 | cpu_dai->name); | 789 | cpu_dai->name); |
790 | goto interface_err; | 790 | goto interface_err; |
791 | } | 791 | } |
792 | } | 792 | } |
793 | 793 | ||
794 | if (platform->driver->ops->hw_params) { | 794 | if (platform->driver->ops->hw_params) { |
795 | ret = platform->driver->ops->hw_params(substream, params); | 795 | ret = platform->driver->ops->hw_params(substream, params); |
796 | if (ret < 0) { | 796 | if (ret < 0) { |
797 | printk(KERN_ERR "asoc: platform %s hw params failed\n", | 797 | printk(KERN_ERR "asoc: platform %s hw params failed\n", |
798 | platform->name); | 798 | platform->name); |
799 | goto platform_err; | 799 | goto platform_err; |
800 | } | 800 | } |
801 | } | 801 | } |
802 | 802 | ||
803 | rtd->rate = params_rate(params); | 803 | rtd->rate = params_rate(params); |
804 | 804 | ||
805 | out: | 805 | out: |
806 | mutex_unlock(&pcm_mutex); | 806 | mutex_unlock(&pcm_mutex); |
807 | return ret; | 807 | return ret; |
808 | 808 | ||
809 | platform_err: | 809 | platform_err: |
810 | if (cpu_dai->driver->ops->hw_free) | 810 | if (cpu_dai->driver->ops->hw_free) |
811 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 811 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
812 | 812 | ||
813 | interface_err: | 813 | interface_err: |
814 | if (codec_dai->driver->ops->hw_free) | 814 | if (codec_dai->driver->ops->hw_free) |
815 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 815 | codec_dai->driver->ops->hw_free(substream, codec_dai); |
816 | 816 | ||
817 | codec_err: | 817 | codec_err: |
818 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 818 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
819 | rtd->dai_link->ops->hw_free(substream); | 819 | rtd->dai_link->ops->hw_free(substream); |
820 | 820 | ||
821 | mutex_unlock(&pcm_mutex); | 821 | mutex_unlock(&pcm_mutex); |
822 | return ret; | 822 | return ret; |
823 | } | 823 | } |
824 | 824 | ||
825 | /* | 825 | /* |
826 | * Free's resources allocated by hw_params, can be called multiple times | 826 | * Free's resources allocated by hw_params, can be called multiple times |
827 | */ | 827 | */ |
828 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | 828 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) |
829 | { | 829 | { |
830 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 830 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
831 | struct snd_soc_platform *platform = rtd->platform; | 831 | struct snd_soc_platform *platform = rtd->platform; |
832 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 832 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
833 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 833 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
834 | struct snd_soc_codec *codec = rtd->codec; | 834 | struct snd_soc_codec *codec = rtd->codec; |
835 | 835 | ||
836 | mutex_lock(&pcm_mutex); | 836 | mutex_lock(&pcm_mutex); |
837 | 837 | ||
838 | /* apply codec digital mute */ | 838 | /* apply codec digital mute */ |
839 | if (!codec->active) | 839 | if (!codec->active) |
840 | snd_soc_dai_digital_mute(codec_dai, 1); | 840 | snd_soc_dai_digital_mute(codec_dai, 1); |
841 | 841 | ||
842 | /* free any machine hw params */ | 842 | /* free any machine hw params */ |
843 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 843 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
844 | rtd->dai_link->ops->hw_free(substream); | 844 | rtd->dai_link->ops->hw_free(substream); |
845 | 845 | ||
846 | /* free any DMA resources */ | 846 | /* free any DMA resources */ |
847 | if (platform->driver->ops->hw_free) | 847 | if (platform->driver->ops->hw_free) |
848 | platform->driver->ops->hw_free(substream); | 848 | platform->driver->ops->hw_free(substream); |
849 | 849 | ||
850 | /* now free hw params for the DAI's */ | 850 | /* now free hw params for the DAI's */ |
851 | if (codec_dai->driver->ops->hw_free) | 851 | if (codec_dai->driver->ops->hw_free) |
852 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 852 | codec_dai->driver->ops->hw_free(substream, codec_dai); |
853 | 853 | ||
854 | if (cpu_dai->driver->ops->hw_free) | 854 | if (cpu_dai->driver->ops->hw_free) |
855 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 855 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
856 | 856 | ||
857 | mutex_unlock(&pcm_mutex); | 857 | mutex_unlock(&pcm_mutex); |
858 | return 0; | 858 | return 0; |
859 | } | 859 | } |
860 | 860 | ||
861 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 861 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
862 | { | 862 | { |
863 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 863 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
864 | struct snd_soc_platform *platform = rtd->platform; | 864 | struct snd_soc_platform *platform = rtd->platform; |
865 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 865 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
866 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 866 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
867 | int ret; | 867 | int ret; |
868 | 868 | ||
869 | if (codec_dai->driver->ops->trigger) { | 869 | if (codec_dai->driver->ops->trigger) { |
870 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | 870 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); |
871 | if (ret < 0) | 871 | if (ret < 0) |
872 | return ret; | 872 | return ret; |
873 | } | 873 | } |
874 | 874 | ||
875 | if (platform->driver->ops->trigger) { | 875 | if (platform->driver->ops->trigger) { |
876 | ret = platform->driver->ops->trigger(substream, cmd); | 876 | ret = platform->driver->ops->trigger(substream, cmd); |
877 | if (ret < 0) | 877 | if (ret < 0) |
878 | return ret; | 878 | return ret; |
879 | } | 879 | } |
880 | 880 | ||
881 | if (cpu_dai->driver->ops->trigger) { | 881 | if (cpu_dai->driver->ops->trigger) { |
882 | ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); | 882 | ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); |
883 | if (ret < 0) | 883 | if (ret < 0) |
884 | return ret; | 884 | return ret; |
885 | } | 885 | } |
886 | return 0; | 886 | return 0; |
887 | } | 887 | } |
888 | 888 | ||
889 | /* | 889 | /* |
890 | * soc level wrapper for pointer callback | 890 | * soc level wrapper for pointer callback |
891 | * If cpu_dai, codec_dai, platform driver has the delay callback, than | 891 | * If cpu_dai, codec_dai, platform driver has the delay callback, than |
892 | * the runtime->delay will be updated accordingly. | 892 | * the runtime->delay will be updated accordingly. |
893 | */ | 893 | */ |
894 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | 894 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) |
895 | { | 895 | { |
896 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 896 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
897 | struct snd_soc_platform *platform = rtd->platform; | 897 | struct snd_soc_platform *platform = rtd->platform; |
898 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 898 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
899 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 899 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
900 | struct snd_pcm_runtime *runtime = substream->runtime; | 900 | struct snd_pcm_runtime *runtime = substream->runtime; |
901 | snd_pcm_uframes_t offset = 0; | 901 | snd_pcm_uframes_t offset = 0; |
902 | snd_pcm_sframes_t delay = 0; | 902 | snd_pcm_sframes_t delay = 0; |
903 | 903 | ||
904 | if (platform->driver->ops->pointer) | 904 | if (platform->driver->ops->pointer) |
905 | offset = platform->driver->ops->pointer(substream); | 905 | offset = platform->driver->ops->pointer(substream); |
906 | 906 | ||
907 | if (cpu_dai->driver->ops->delay) | 907 | if (cpu_dai->driver->ops->delay) |
908 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | 908 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); |
909 | 909 | ||
910 | if (codec_dai->driver->ops->delay) | 910 | if (codec_dai->driver->ops->delay) |
911 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | 911 | delay += codec_dai->driver->ops->delay(substream, codec_dai); |
912 | 912 | ||
913 | if (platform->driver->delay) | 913 | if (platform->driver->delay) |
914 | delay += platform->driver->delay(substream, codec_dai); | 914 | delay += platform->driver->delay(substream, codec_dai); |
915 | 915 | ||
916 | runtime->delay = delay; | 916 | runtime->delay = delay; |
917 | 917 | ||
918 | return offset; | 918 | return offset; |
919 | } | 919 | } |
920 | 920 | ||
921 | /* ASoC PCM operations */ | 921 | /* ASoC PCM operations */ |
922 | static struct snd_pcm_ops soc_pcm_ops = { | 922 | static struct snd_pcm_ops soc_pcm_ops = { |
923 | .open = soc_pcm_open, | 923 | .open = soc_pcm_open, |
924 | .close = soc_codec_close, | 924 | .close = soc_codec_close, |
925 | .hw_params = soc_pcm_hw_params, | 925 | .hw_params = soc_pcm_hw_params, |
926 | .hw_free = soc_pcm_hw_free, | 926 | .hw_free = soc_pcm_hw_free, |
927 | .prepare = soc_pcm_prepare, | 927 | .prepare = soc_pcm_prepare, |
928 | .trigger = soc_pcm_trigger, | 928 | .trigger = soc_pcm_trigger, |
929 | .pointer = soc_pcm_pointer, | 929 | .pointer = soc_pcm_pointer, |
930 | }; | 930 | }; |
931 | 931 | ||
932 | #ifdef CONFIG_PM | 932 | #ifdef CONFIG_PM |
933 | /* powers down audio subsystem for suspend */ | 933 | /* powers down audio subsystem for suspend */ |
934 | static int soc_suspend(struct device *dev) | 934 | static int soc_suspend(struct device *dev) |
935 | { | 935 | { |
936 | struct platform_device *pdev = to_platform_device(dev); | 936 | struct platform_device *pdev = to_platform_device(dev); |
937 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 937 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
938 | int i; | 938 | int i; |
939 | 939 | ||
940 | /* If the initialization of this soc device failed, there is no codec | 940 | /* If the initialization of this soc device failed, there is no codec |
941 | * associated with it. Just bail out in this case. | 941 | * associated with it. Just bail out in this case. |
942 | */ | 942 | */ |
943 | if (list_empty(&card->codec_dev_list)) | 943 | if (list_empty(&card->codec_dev_list)) |
944 | return 0; | 944 | return 0; |
945 | 945 | ||
946 | /* Due to the resume being scheduled into a workqueue we could | 946 | /* Due to the resume being scheduled into a workqueue we could |
947 | * suspend before that's finished - wait for it to complete. | 947 | * suspend before that's finished - wait for it to complete. |
948 | */ | 948 | */ |
949 | snd_power_lock(card->snd_card); | 949 | snd_power_lock(card->snd_card); |
950 | snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); | 950 | snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); |
951 | snd_power_unlock(card->snd_card); | 951 | snd_power_unlock(card->snd_card); |
952 | 952 | ||
953 | /* we're going to block userspace touching us until resume completes */ | 953 | /* we're going to block userspace touching us until resume completes */ |
954 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); | 954 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); |
955 | 955 | ||
956 | /* mute any active DAC's */ | 956 | /* mute any active DAC's */ |
957 | for (i = 0; i < card->num_rtd; i++) { | 957 | for (i = 0; i < card->num_rtd; i++) { |
958 | struct snd_soc_dai *dai = card->rtd[i].codec_dai; | 958 | struct snd_soc_dai *dai = card->rtd[i].codec_dai; |
959 | struct snd_soc_dai_driver *drv = dai->driver; | 959 | struct snd_soc_dai_driver *drv = dai->driver; |
960 | 960 | ||
961 | if (card->rtd[i].dai_link->ignore_suspend) | 961 | if (card->rtd[i].dai_link->ignore_suspend) |
962 | continue; | 962 | continue; |
963 | 963 | ||
964 | if (drv->ops->digital_mute && dai->playback_active) | 964 | if (drv->ops->digital_mute && dai->playback_active) |
965 | drv->ops->digital_mute(dai, 1); | 965 | drv->ops->digital_mute(dai, 1); |
966 | } | 966 | } |
967 | 967 | ||
968 | /* suspend all pcms */ | 968 | /* suspend all pcms */ |
969 | for (i = 0; i < card->num_rtd; i++) { | 969 | for (i = 0; i < card->num_rtd; i++) { |
970 | if (card->rtd[i].dai_link->ignore_suspend) | 970 | if (card->rtd[i].dai_link->ignore_suspend) |
971 | continue; | 971 | continue; |
972 | 972 | ||
973 | snd_pcm_suspend_all(card->rtd[i].pcm); | 973 | snd_pcm_suspend_all(card->rtd[i].pcm); |
974 | } | 974 | } |
975 | 975 | ||
976 | if (card->suspend_pre) | 976 | if (card->suspend_pre) |
977 | card->suspend_pre(pdev, PMSG_SUSPEND); | 977 | card->suspend_pre(pdev, PMSG_SUSPEND); |
978 | 978 | ||
979 | for (i = 0; i < card->num_rtd; i++) { | 979 | for (i = 0; i < card->num_rtd; i++) { |
980 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 980 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
981 | struct snd_soc_platform *platform = card->rtd[i].platform; | 981 | struct snd_soc_platform *platform = card->rtd[i].platform; |
982 | 982 | ||
983 | if (card->rtd[i].dai_link->ignore_suspend) | 983 | if (card->rtd[i].dai_link->ignore_suspend) |
984 | continue; | 984 | continue; |
985 | 985 | ||
986 | if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) | 986 | if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) |
987 | cpu_dai->driver->suspend(cpu_dai); | 987 | cpu_dai->driver->suspend(cpu_dai); |
988 | if (platform->driver->suspend && !platform->suspended) { | 988 | if (platform->driver->suspend && !platform->suspended) { |
989 | platform->driver->suspend(cpu_dai); | 989 | platform->driver->suspend(cpu_dai); |
990 | platform->suspended = 1; | 990 | platform->suspended = 1; |
991 | } | 991 | } |
992 | } | 992 | } |
993 | 993 | ||
994 | /* close any waiting streams and save state */ | 994 | /* close any waiting streams and save state */ |
995 | for (i = 0; i < card->num_rtd; i++) { | 995 | for (i = 0; i < card->num_rtd; i++) { |
996 | run_delayed_work(&card->rtd[i].delayed_work); | 996 | run_delayed_work(&card->rtd[i].delayed_work); |
997 | card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level; | 997 | card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level; |
998 | } | 998 | } |
999 | 999 | ||
1000 | for (i = 0; i < card->num_rtd; i++) { | 1000 | for (i = 0; i < card->num_rtd; i++) { |
1001 | struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; | 1001 | struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; |
1002 | 1002 | ||
1003 | if (card->rtd[i].dai_link->ignore_suspend) | 1003 | if (card->rtd[i].dai_link->ignore_suspend) |
1004 | continue; | 1004 | continue; |
1005 | 1005 | ||
1006 | if (driver->playback.stream_name != NULL) | 1006 | if (driver->playback.stream_name != NULL) |
1007 | snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, | 1007 | snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, |
1008 | SND_SOC_DAPM_STREAM_SUSPEND); | 1008 | SND_SOC_DAPM_STREAM_SUSPEND); |
1009 | 1009 | ||
1010 | if (driver->capture.stream_name != NULL) | 1010 | if (driver->capture.stream_name != NULL) |
1011 | snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, | 1011 | snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, |
1012 | SND_SOC_DAPM_STREAM_SUSPEND); | 1012 | SND_SOC_DAPM_STREAM_SUSPEND); |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | /* suspend all CODECs */ | 1015 | /* suspend all CODECs */ |
1016 | for (i = 0; i < card->num_rtd; i++) { | 1016 | for (i = 0; i < card->num_rtd; i++) { |
1017 | struct snd_soc_codec *codec = card->rtd[i].codec; | 1017 | struct snd_soc_codec *codec = card->rtd[i].codec; |
1018 | /* If there are paths active then the CODEC will be held with | 1018 | /* If there are paths active then the CODEC will be held with |
1019 | * bias _ON and should not be suspended. */ | 1019 | * bias _ON and should not be suspended. */ |
1020 | if (!codec->suspended && codec->driver->suspend) { | 1020 | if (!codec->suspended && codec->driver->suspend) { |
1021 | switch (codec->bias_level) { | 1021 | switch (codec->bias_level) { |
1022 | case SND_SOC_BIAS_STANDBY: | 1022 | case SND_SOC_BIAS_STANDBY: |
1023 | case SND_SOC_BIAS_OFF: | 1023 | case SND_SOC_BIAS_OFF: |
1024 | codec->driver->suspend(codec, PMSG_SUSPEND); | 1024 | codec->driver->suspend(codec, PMSG_SUSPEND); |
1025 | codec->suspended = 1; | 1025 | codec->suspended = 1; |
1026 | break; | 1026 | break; |
1027 | default: | 1027 | default: |
1028 | dev_dbg(codec->dev, "CODEC is on over suspend\n"); | 1028 | dev_dbg(codec->dev, "CODEC is on over suspend\n"); |
1029 | break; | 1029 | break; |
1030 | } | 1030 | } |
1031 | } | 1031 | } |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | for (i = 0; i < card->num_rtd; i++) { | 1034 | for (i = 0; i < card->num_rtd; i++) { |
1035 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 1035 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
1036 | 1036 | ||
1037 | if (card->rtd[i].dai_link->ignore_suspend) | 1037 | if (card->rtd[i].dai_link->ignore_suspend) |
1038 | continue; | 1038 | continue; |
1039 | 1039 | ||
1040 | if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) | 1040 | if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) |
1041 | cpu_dai->driver->suspend(cpu_dai); | 1041 | cpu_dai->driver->suspend(cpu_dai); |
1042 | } | 1042 | } |
1043 | 1043 | ||
1044 | if (card->suspend_post) | 1044 | if (card->suspend_post) |
1045 | card->suspend_post(pdev, PMSG_SUSPEND); | 1045 | card->suspend_post(pdev, PMSG_SUSPEND); |
1046 | 1046 | ||
1047 | return 0; | 1047 | return 0; |
1048 | } | 1048 | } |
1049 | 1049 | ||
1050 | /* deferred resume work, so resume can complete before we finished | 1050 | /* deferred resume work, so resume can complete before we finished |
1051 | * setting our codec back up, which can be very slow on I2C | 1051 | * setting our codec back up, which can be very slow on I2C |
1052 | */ | 1052 | */ |
1053 | static void soc_resume_deferred(struct work_struct *work) | 1053 | static void soc_resume_deferred(struct work_struct *work) |
1054 | { | 1054 | { |
1055 | struct snd_soc_card *card = | 1055 | struct snd_soc_card *card = |
1056 | container_of(work, struct snd_soc_card, deferred_resume_work); | 1056 | container_of(work, struct snd_soc_card, deferred_resume_work); |
1057 | struct platform_device *pdev = to_platform_device(card->dev); | 1057 | struct platform_device *pdev = to_platform_device(card->dev); |
1058 | int i; | 1058 | int i; |
1059 | 1059 | ||
1060 | /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, | 1060 | /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, |
1061 | * so userspace apps are blocked from touching us | 1061 | * so userspace apps are blocked from touching us |
1062 | */ | 1062 | */ |
1063 | 1063 | ||
1064 | dev_dbg(card->dev, "starting resume work\n"); | 1064 | dev_dbg(card->dev, "starting resume work\n"); |
1065 | 1065 | ||
1066 | /* Bring us up into D2 so that DAPM starts enabling things */ | 1066 | /* Bring us up into D2 so that DAPM starts enabling things */ |
1067 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); | 1067 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); |
1068 | 1068 | ||
1069 | if (card->resume_pre) | 1069 | if (card->resume_pre) |
1070 | card->resume_pre(pdev); | 1070 | card->resume_pre(pdev); |
1071 | 1071 | ||
1072 | /* resume AC97 DAIs */ | 1072 | /* resume AC97 DAIs */ |
1073 | for (i = 0; i < card->num_rtd; i++) { | 1073 | for (i = 0; i < card->num_rtd; i++) { |
1074 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 1074 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
1075 | 1075 | ||
1076 | if (card->rtd[i].dai_link->ignore_suspend) | 1076 | if (card->rtd[i].dai_link->ignore_suspend) |
1077 | continue; | 1077 | continue; |
1078 | 1078 | ||
1079 | if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) | 1079 | if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) |
1080 | cpu_dai->driver->resume(cpu_dai); | 1080 | cpu_dai->driver->resume(cpu_dai); |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | for (i = 0; i < card->num_rtd; i++) { | 1083 | for (i = 0; i < card->num_rtd; i++) { |
1084 | struct snd_soc_codec *codec = card->rtd[i].codec; | 1084 | struct snd_soc_codec *codec = card->rtd[i].codec; |
1085 | /* If the CODEC was idle over suspend then it will have been | 1085 | /* If the CODEC was idle over suspend then it will have been |
1086 | * left with bias OFF or STANDBY and suspended so we must now | 1086 | * left with bias OFF or STANDBY and suspended so we must now |
1087 | * resume. Otherwise the suspend was suppressed. | 1087 | * resume. Otherwise the suspend was suppressed. |
1088 | */ | 1088 | */ |
1089 | if (codec->driver->resume && codec->suspended) { | 1089 | if (codec->driver->resume && codec->suspended) { |
1090 | switch (codec->bias_level) { | 1090 | switch (codec->bias_level) { |
1091 | case SND_SOC_BIAS_STANDBY: | 1091 | case SND_SOC_BIAS_STANDBY: |
1092 | case SND_SOC_BIAS_OFF: | 1092 | case SND_SOC_BIAS_OFF: |
1093 | codec->driver->resume(codec); | 1093 | codec->driver->resume(codec); |
1094 | codec->suspended = 0; | 1094 | codec->suspended = 0; |
1095 | break; | 1095 | break; |
1096 | default: | 1096 | default: |
1097 | dev_dbg(codec->dev, "CODEC was on over suspend\n"); | 1097 | dev_dbg(codec->dev, "CODEC was on over suspend\n"); |
1098 | break; | 1098 | break; |
1099 | } | 1099 | } |
1100 | } | 1100 | } |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | for (i = 0; i < card->num_rtd; i++) { | 1103 | for (i = 0; i < card->num_rtd; i++) { |
1104 | struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; | 1104 | struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; |
1105 | 1105 | ||
1106 | if (card->rtd[i].dai_link->ignore_suspend) | 1106 | if (card->rtd[i].dai_link->ignore_suspend) |
1107 | continue; | 1107 | continue; |
1108 | 1108 | ||
1109 | if (driver->playback.stream_name != NULL) | 1109 | if (driver->playback.stream_name != NULL) |
1110 | snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, | 1110 | snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, |
1111 | SND_SOC_DAPM_STREAM_RESUME); | 1111 | SND_SOC_DAPM_STREAM_RESUME); |
1112 | 1112 | ||
1113 | if (driver->capture.stream_name != NULL) | 1113 | if (driver->capture.stream_name != NULL) |
1114 | snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, | 1114 | snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, |
1115 | SND_SOC_DAPM_STREAM_RESUME); | 1115 | SND_SOC_DAPM_STREAM_RESUME); |
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | /* unmute any active DACs */ | 1118 | /* unmute any active DACs */ |
1119 | for (i = 0; i < card->num_rtd; i++) { | 1119 | for (i = 0; i < card->num_rtd; i++) { |
1120 | struct snd_soc_dai *dai = card->rtd[i].codec_dai; | 1120 | struct snd_soc_dai *dai = card->rtd[i].codec_dai; |
1121 | struct snd_soc_dai_driver *drv = dai->driver; | 1121 | struct snd_soc_dai_driver *drv = dai->driver; |
1122 | 1122 | ||
1123 | if (card->rtd[i].dai_link->ignore_suspend) | 1123 | if (card->rtd[i].dai_link->ignore_suspend) |
1124 | continue; | 1124 | continue; |
1125 | 1125 | ||
1126 | if (drv->ops->digital_mute && dai->playback_active) | 1126 | if (drv->ops->digital_mute && dai->playback_active) |
1127 | drv->ops->digital_mute(dai, 0); | 1127 | drv->ops->digital_mute(dai, 0); |
1128 | } | 1128 | } |
1129 | 1129 | ||
1130 | for (i = 0; i < card->num_rtd; i++) { | 1130 | for (i = 0; i < card->num_rtd; i++) { |
1131 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 1131 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
1132 | struct snd_soc_platform *platform = card->rtd[i].platform; | 1132 | struct snd_soc_platform *platform = card->rtd[i].platform; |
1133 | 1133 | ||
1134 | if (card->rtd[i].dai_link->ignore_suspend) | 1134 | if (card->rtd[i].dai_link->ignore_suspend) |
1135 | continue; | 1135 | continue; |
1136 | 1136 | ||
1137 | if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) | 1137 | if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) |
1138 | cpu_dai->driver->resume(cpu_dai); | 1138 | cpu_dai->driver->resume(cpu_dai); |
1139 | if (platform->driver->resume && platform->suspended) { | 1139 | if (platform->driver->resume && platform->suspended) { |
1140 | platform->driver->resume(cpu_dai); | 1140 | platform->driver->resume(cpu_dai); |
1141 | platform->suspended = 0; | 1141 | platform->suspended = 0; |
1142 | } | 1142 | } |
1143 | } | 1143 | } |
1144 | 1144 | ||
1145 | if (card->resume_post) | 1145 | if (card->resume_post) |
1146 | card->resume_post(pdev); | 1146 | card->resume_post(pdev); |
1147 | 1147 | ||
1148 | dev_dbg(card->dev, "resume work completed\n"); | 1148 | dev_dbg(card->dev, "resume work completed\n"); |
1149 | 1149 | ||
1150 | /* userspace can access us now we are back as we were before */ | 1150 | /* userspace can access us now we are back as we were before */ |
1151 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); | 1151 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | /* powers up audio subsystem after a suspend */ | 1154 | /* powers up audio subsystem after a suspend */ |
1155 | static int soc_resume(struct device *dev) | 1155 | static int soc_resume(struct device *dev) |
1156 | { | 1156 | { |
1157 | struct platform_device *pdev = to_platform_device(dev); | 1157 | struct platform_device *pdev = to_platform_device(dev); |
1158 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 1158 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
1159 | int i; | 1159 | int i; |
1160 | 1160 | ||
1161 | /* AC97 devices might have other drivers hanging off them so | 1161 | /* AC97 devices might have other drivers hanging off them so |
1162 | * need to resume immediately. Other drivers don't have that | 1162 | * need to resume immediately. Other drivers don't have that |
1163 | * problem and may take a substantial amount of time to resume | 1163 | * problem and may take a substantial amount of time to resume |
1164 | * due to I/O costs and anti-pop so handle them out of line. | 1164 | * due to I/O costs and anti-pop so handle them out of line. |
1165 | */ | 1165 | */ |
1166 | for (i = 0; i < card->num_rtd; i++) { | 1166 | for (i = 0; i < card->num_rtd; i++) { |
1167 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 1167 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
1168 | if (cpu_dai->driver->ac97_control) { | 1168 | if (cpu_dai->driver->ac97_control) { |
1169 | dev_dbg(dev, "Resuming AC97 immediately\n"); | 1169 | dev_dbg(dev, "Resuming AC97 immediately\n"); |
1170 | soc_resume_deferred(&card->deferred_resume_work); | 1170 | soc_resume_deferred(&card->deferred_resume_work); |
1171 | } else { | 1171 | } else { |
1172 | dev_dbg(dev, "Scheduling resume work\n"); | 1172 | dev_dbg(dev, "Scheduling resume work\n"); |
1173 | if (!schedule_work(&card->deferred_resume_work)) | 1173 | if (!schedule_work(&card->deferred_resume_work)) |
1174 | dev_err(dev, "resume work item may be lost\n"); | 1174 | dev_err(dev, "resume work item may be lost\n"); |
1175 | } | 1175 | } |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | return 0; | 1178 | return 0; |
1179 | } | 1179 | } |
1180 | #else | 1180 | #else |
1181 | #define soc_suspend NULL | 1181 | #define soc_suspend NULL |
1182 | #define soc_resume NULL | 1182 | #define soc_resume NULL |
1183 | #endif | 1183 | #endif |
1184 | 1184 | ||
1185 | static struct snd_soc_dai_ops null_dai_ops = { | 1185 | static struct snd_soc_dai_ops null_dai_ops = { |
1186 | }; | 1186 | }; |
1187 | 1187 | ||
1188 | static int soc_bind_dai_link(struct snd_soc_card *card, int num) | 1188 | static int soc_bind_dai_link(struct snd_soc_card *card, int num) |
1189 | { | 1189 | { |
1190 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1190 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1191 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1191 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1192 | struct snd_soc_codec *codec; | 1192 | struct snd_soc_codec *codec; |
1193 | struct snd_soc_platform *platform; | 1193 | struct snd_soc_platform *platform; |
1194 | struct snd_soc_dai *codec_dai, *cpu_dai; | 1194 | struct snd_soc_dai *codec_dai, *cpu_dai; |
1195 | 1195 | ||
1196 | if (rtd->complete) | 1196 | if (rtd->complete) |
1197 | return 1; | 1197 | return 1; |
1198 | dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num); | 1198 | dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num); |
1199 | 1199 | ||
1200 | /* do we already have the CPU DAI for this link ? */ | 1200 | /* do we already have the CPU DAI for this link ? */ |
1201 | if (rtd->cpu_dai) { | 1201 | if (rtd->cpu_dai) { |
1202 | goto find_codec; | 1202 | goto find_codec; |
1203 | } | 1203 | } |
1204 | /* no, then find CPU DAI from registered DAIs*/ | 1204 | /* no, then find CPU DAI from registered DAIs*/ |
1205 | list_for_each_entry(cpu_dai, &dai_list, list) { | 1205 | list_for_each_entry(cpu_dai, &dai_list, list) { |
1206 | if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) { | 1206 | if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) { |
1207 | 1207 | ||
1208 | if (!try_module_get(cpu_dai->dev->driver->owner)) | 1208 | if (!try_module_get(cpu_dai->dev->driver->owner)) |
1209 | return -ENODEV; | 1209 | return -ENODEV; |
1210 | 1210 | ||
1211 | rtd->cpu_dai = cpu_dai; | 1211 | rtd->cpu_dai = cpu_dai; |
1212 | goto find_codec; | 1212 | goto find_codec; |
1213 | } | 1213 | } |
1214 | } | 1214 | } |
1215 | dev_dbg(card->dev, "CPU DAI %s not registered\n", | 1215 | dev_dbg(card->dev, "CPU DAI %s not registered\n", |
1216 | dai_link->cpu_dai_name); | 1216 | dai_link->cpu_dai_name); |
1217 | 1217 | ||
1218 | find_codec: | 1218 | find_codec: |
1219 | /* do we already have the CODEC for this link ? */ | 1219 | /* do we already have the CODEC for this link ? */ |
1220 | if (rtd->codec) { | 1220 | if (rtd->codec) { |
1221 | goto find_platform; | 1221 | goto find_platform; |
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | /* no, then find CODEC from registered CODECs*/ | 1224 | /* no, then find CODEC from registered CODECs*/ |
1225 | list_for_each_entry(codec, &codec_list, list) { | 1225 | list_for_each_entry(codec, &codec_list, list) { |
1226 | if (!strcmp(codec->name, dai_link->codec_name)) { | 1226 | if (!strcmp(codec->name, dai_link->codec_name)) { |
1227 | rtd->codec = codec; | 1227 | rtd->codec = codec; |
1228 | 1228 | ||
1229 | if (!try_module_get(codec->dev->driver->owner)) | 1229 | if (!try_module_get(codec->dev->driver->owner)) |
1230 | return -ENODEV; | 1230 | return -ENODEV; |
1231 | 1231 | ||
1232 | /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/ | 1232 | /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/ |
1233 | list_for_each_entry(codec_dai, &dai_list, list) { | 1233 | list_for_each_entry(codec_dai, &dai_list, list) { |
1234 | if (codec->dev == codec_dai->dev && | 1234 | if (codec->dev == codec_dai->dev && |
1235 | !strcmp(codec_dai->name, dai_link->codec_dai_name)) { | 1235 | !strcmp(codec_dai->name, dai_link->codec_dai_name)) { |
1236 | rtd->codec_dai = codec_dai; | 1236 | rtd->codec_dai = codec_dai; |
1237 | goto find_platform; | 1237 | goto find_platform; |
1238 | } | 1238 | } |
1239 | } | 1239 | } |
1240 | dev_dbg(card->dev, "CODEC DAI %s not registered\n", | 1240 | dev_dbg(card->dev, "CODEC DAI %s not registered\n", |
1241 | dai_link->codec_dai_name); | 1241 | dai_link->codec_dai_name); |
1242 | 1242 | ||
1243 | goto find_platform; | 1243 | goto find_platform; |
1244 | } | 1244 | } |
1245 | } | 1245 | } |
1246 | dev_dbg(card->dev, "CODEC %s not registered\n", | 1246 | dev_dbg(card->dev, "CODEC %s not registered\n", |
1247 | dai_link->codec_name); | 1247 | dai_link->codec_name); |
1248 | 1248 | ||
1249 | find_platform: | 1249 | find_platform: |
1250 | /* do we already have the CODEC DAI for this link ? */ | 1250 | /* do we already have the CODEC DAI for this link ? */ |
1251 | if (rtd->platform) { | 1251 | if (rtd->platform) { |
1252 | goto out; | 1252 | goto out; |
1253 | } | 1253 | } |
1254 | /* no, then find CPU DAI from registered DAIs*/ | 1254 | /* no, then find CPU DAI from registered DAIs*/ |
1255 | list_for_each_entry(platform, &platform_list, list) { | 1255 | list_for_each_entry(platform, &platform_list, list) { |
1256 | if (!strcmp(platform->name, dai_link->platform_name)) { | 1256 | if (!strcmp(platform->name, dai_link->platform_name)) { |
1257 | 1257 | ||
1258 | if (!try_module_get(platform->dev->driver->owner)) | 1258 | if (!try_module_get(platform->dev->driver->owner)) |
1259 | return -ENODEV; | 1259 | return -ENODEV; |
1260 | 1260 | ||
1261 | rtd->platform = platform; | 1261 | rtd->platform = platform; |
1262 | goto out; | 1262 | goto out; |
1263 | } | 1263 | } |
1264 | } | 1264 | } |
1265 | 1265 | ||
1266 | dev_dbg(card->dev, "platform %s not registered\n", | 1266 | dev_dbg(card->dev, "platform %s not registered\n", |
1267 | dai_link->platform_name); | 1267 | dai_link->platform_name); |
1268 | return 0; | 1268 | return 0; |
1269 | 1269 | ||
1270 | out: | 1270 | out: |
1271 | /* mark rtd as complete if we found all 4 of our client devices */ | 1271 | /* mark rtd as complete if we found all 4 of our client devices */ |
1272 | if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) { | 1272 | if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) { |
1273 | rtd->complete = 1; | 1273 | rtd->complete = 1; |
1274 | card->num_rtd++; | 1274 | card->num_rtd++; |
1275 | } | 1275 | } |
1276 | return 1; | 1276 | return 1; |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | static void soc_remove_dai_link(struct snd_soc_card *card, int num) | 1279 | static void soc_remove_dai_link(struct snd_soc_card *card, int num) |
1280 | { | 1280 | { |
1281 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1281 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1282 | struct snd_soc_codec *codec = rtd->codec; | 1282 | struct snd_soc_codec *codec = rtd->codec; |
1283 | struct snd_soc_platform *platform = rtd->platform; | 1283 | struct snd_soc_platform *platform = rtd->platform; |
1284 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; | 1284 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; |
1285 | int err; | 1285 | int err; |
1286 | 1286 | ||
1287 | /* unregister the rtd device */ | 1287 | /* unregister the rtd device */ |
1288 | if (rtd->dev_registered) { | 1288 | if (rtd->dev_registered) { |
1289 | device_remove_file(&rtd->dev, &dev_attr_pmdown_time); | 1289 | device_remove_file(&rtd->dev, &dev_attr_pmdown_time); |
1290 | device_unregister(&rtd->dev); | 1290 | device_unregister(&rtd->dev); |
1291 | rtd->dev_registered = 0; | 1291 | rtd->dev_registered = 0; |
1292 | } | 1292 | } |
1293 | 1293 | ||
1294 | /* remove the CODEC DAI */ | 1294 | /* remove the CODEC DAI */ |
1295 | if (codec_dai && codec_dai->probed) { | 1295 | if (codec_dai && codec_dai->probed) { |
1296 | if (codec_dai->driver->remove) { | 1296 | if (codec_dai->driver->remove) { |
1297 | err = codec_dai->driver->remove(codec_dai); | 1297 | err = codec_dai->driver->remove(codec_dai); |
1298 | if (err < 0) | 1298 | if (err < 0) |
1299 | printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name); | 1299 | printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name); |
1300 | } | 1300 | } |
1301 | codec_dai->probed = 0; | 1301 | codec_dai->probed = 0; |
1302 | list_del(&codec_dai->card_list); | 1302 | list_del(&codec_dai->card_list); |
1303 | } | 1303 | } |
1304 | 1304 | ||
1305 | /* remove the platform */ | 1305 | /* remove the platform */ |
1306 | if (platform && platform->probed) { | 1306 | if (platform && platform->probed) { |
1307 | if (platform->driver->remove) { | 1307 | if (platform->driver->remove) { |
1308 | err = platform->driver->remove(platform); | 1308 | err = platform->driver->remove(platform); |
1309 | if (err < 0) | 1309 | if (err < 0) |
1310 | printk(KERN_ERR "asoc: failed to remove %s\n", platform->name); | 1310 | printk(KERN_ERR "asoc: failed to remove %s\n", platform->name); |
1311 | } | 1311 | } |
1312 | platform->probed = 0; | 1312 | platform->probed = 0; |
1313 | list_del(&platform->card_list); | 1313 | list_del(&platform->card_list); |
1314 | module_put(platform->dev->driver->owner); | 1314 | module_put(platform->dev->driver->owner); |
1315 | } | 1315 | } |
1316 | 1316 | ||
1317 | /* remove the CODEC */ | 1317 | /* remove the CODEC */ |
1318 | if (codec && codec->probed) { | 1318 | if (codec && codec->probed) { |
1319 | if (codec->driver->remove) { | 1319 | if (codec->driver->remove) { |
1320 | err = codec->driver->remove(codec); | 1320 | err = codec->driver->remove(codec); |
1321 | if (err < 0) | 1321 | if (err < 0) |
1322 | printk(KERN_ERR "asoc: failed to remove %s\n", codec->name); | 1322 | printk(KERN_ERR "asoc: failed to remove %s\n", codec->name); |
1323 | } | 1323 | } |
1324 | 1324 | ||
1325 | /* Make sure all DAPM widgets are freed */ | 1325 | /* Make sure all DAPM widgets are freed */ |
1326 | snd_soc_dapm_free(codec); | 1326 | snd_soc_dapm_free(codec); |
1327 | 1327 | ||
1328 | soc_cleanup_codec_debugfs(codec); | 1328 | soc_cleanup_codec_debugfs(codec); |
1329 | device_remove_file(&rtd->dev, &dev_attr_codec_reg); | 1329 | device_remove_file(&rtd->dev, &dev_attr_codec_reg); |
1330 | codec->probed = 0; | 1330 | codec->probed = 0; |
1331 | list_del(&codec->card_list); | 1331 | list_del(&codec->card_list); |
1332 | module_put(codec->dev->driver->owner); | 1332 | module_put(codec->dev->driver->owner); |
1333 | } | 1333 | } |
1334 | 1334 | ||
1335 | /* remove the cpu_dai */ | 1335 | /* remove the cpu_dai */ |
1336 | if (cpu_dai && cpu_dai->probed) { | 1336 | if (cpu_dai && cpu_dai->probed) { |
1337 | if (cpu_dai->driver->remove) { | 1337 | if (cpu_dai->driver->remove) { |
1338 | err = cpu_dai->driver->remove(cpu_dai); | 1338 | err = cpu_dai->driver->remove(cpu_dai); |
1339 | if (err < 0) | 1339 | if (err < 0) |
1340 | printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name); | 1340 | printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name); |
1341 | } | 1341 | } |
1342 | cpu_dai->probed = 0; | 1342 | cpu_dai->probed = 0; |
1343 | list_del(&cpu_dai->card_list); | 1343 | list_del(&cpu_dai->card_list); |
1344 | module_put(cpu_dai->dev->driver->owner); | 1344 | module_put(cpu_dai->dev->driver->owner); |
1345 | } | 1345 | } |
1346 | } | 1346 | } |
1347 | 1347 | ||
1348 | static void rtd_release(struct device *dev) {} | 1348 | static void rtd_release(struct device *dev) {} |
1349 | 1349 | ||
1350 | static int soc_probe_dai_link(struct snd_soc_card *card, int num) | 1350 | static int soc_probe_dai_link(struct snd_soc_card *card, int num) |
1351 | { | 1351 | { |
1352 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1352 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1353 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1353 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1354 | struct snd_soc_codec *codec = rtd->codec; | 1354 | struct snd_soc_codec *codec = rtd->codec; |
1355 | struct snd_soc_platform *platform = rtd->platform; | 1355 | struct snd_soc_platform *platform = rtd->platform; |
1356 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; | 1356 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; |
1357 | int ret; | 1357 | int ret; |
1358 | 1358 | ||
1359 | dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); | 1359 | dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); |
1360 | 1360 | ||
1361 | /* config components */ | 1361 | /* config components */ |
1362 | codec_dai->codec = codec; | 1362 | codec_dai->codec = codec; |
1363 | codec->card = card; | 1363 | codec->card = card; |
1364 | cpu_dai->platform = platform; | 1364 | cpu_dai->platform = platform; |
1365 | rtd->card = card; | 1365 | rtd->card = card; |
1366 | rtd->dev.parent = card->dev; | 1366 | rtd->dev.parent = card->dev; |
1367 | codec_dai->card = card; | 1367 | codec_dai->card = card; |
1368 | cpu_dai->card = card; | 1368 | cpu_dai->card = card; |
1369 | 1369 | ||
1370 | /* set default power off timeout */ | 1370 | /* set default power off timeout */ |
1371 | rtd->pmdown_time = pmdown_time; | 1371 | rtd->pmdown_time = pmdown_time; |
1372 | 1372 | ||
1373 | /* probe the cpu_dai */ | 1373 | /* probe the cpu_dai */ |
1374 | if (!cpu_dai->probed) { | 1374 | if (!cpu_dai->probed) { |
1375 | if (cpu_dai->driver->probe) { | 1375 | if (cpu_dai->driver->probe) { |
1376 | ret = cpu_dai->driver->probe(cpu_dai); | 1376 | ret = cpu_dai->driver->probe(cpu_dai); |
1377 | if (ret < 0) { | 1377 | if (ret < 0) { |
1378 | printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n", | 1378 | printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n", |
1379 | cpu_dai->name); | 1379 | cpu_dai->name); |
1380 | return ret; | 1380 | return ret; |
1381 | } | 1381 | } |
1382 | } | 1382 | } |
1383 | cpu_dai->probed = 1; | 1383 | cpu_dai->probed = 1; |
1384 | /* mark cpu_dai as probed and add to card cpu_dai list */ | 1384 | /* mark cpu_dai as probed and add to card cpu_dai list */ |
1385 | list_add(&cpu_dai->card_list, &card->dai_dev_list); | 1385 | list_add(&cpu_dai->card_list, &card->dai_dev_list); |
1386 | } | 1386 | } |
1387 | 1387 | ||
1388 | /* probe the CODEC */ | 1388 | /* probe the CODEC */ |
1389 | if (!codec->probed) { | 1389 | if (!codec->probed) { |
1390 | if (codec->driver->probe) { | 1390 | if (codec->driver->probe) { |
1391 | ret = codec->driver->probe(codec); | 1391 | ret = codec->driver->probe(codec); |
1392 | if (ret < 0) { | 1392 | if (ret < 0) { |
1393 | printk(KERN_ERR "asoc: failed to probe CODEC %s\n", | 1393 | printk(KERN_ERR "asoc: failed to probe CODEC %s\n", |
1394 | codec->name); | 1394 | codec->name); |
1395 | return ret; | 1395 | return ret; |
1396 | } | 1396 | } |
1397 | } | 1397 | } |
1398 | 1398 | ||
1399 | soc_init_codec_debugfs(codec); | 1399 | soc_init_codec_debugfs(codec); |
1400 | 1400 | ||
1401 | /* mark codec as probed and add to card codec list */ | 1401 | /* mark codec as probed and add to card codec list */ |
1402 | codec->probed = 1; | 1402 | codec->probed = 1; |
1403 | list_add(&codec->card_list, &card->codec_dev_list); | 1403 | list_add(&codec->card_list, &card->codec_dev_list); |
1404 | } | 1404 | } |
1405 | 1405 | ||
1406 | /* probe the platform */ | 1406 | /* probe the platform */ |
1407 | if (!platform->probed) { | 1407 | if (!platform->probed) { |
1408 | if (platform->driver->probe) { | 1408 | if (platform->driver->probe) { |
1409 | ret = platform->driver->probe(platform); | 1409 | ret = platform->driver->probe(platform); |
1410 | if (ret < 0) { | 1410 | if (ret < 0) { |
1411 | printk(KERN_ERR "asoc: failed to probe platform %s\n", | 1411 | printk(KERN_ERR "asoc: failed to probe platform %s\n", |
1412 | platform->name); | 1412 | platform->name); |
1413 | return ret; | 1413 | return ret; |
1414 | } | 1414 | } |
1415 | } | 1415 | } |
1416 | /* mark platform as probed and add to card platform list */ | 1416 | /* mark platform as probed and add to card platform list */ |
1417 | platform->probed = 1; | 1417 | platform->probed = 1; |
1418 | list_add(&platform->card_list, &card->platform_dev_list); | 1418 | list_add(&platform->card_list, &card->platform_dev_list); |
1419 | } | 1419 | } |
1420 | 1420 | ||
1421 | /* probe the CODEC DAI */ | 1421 | /* probe the CODEC DAI */ |
1422 | if (!codec_dai->probed) { | 1422 | if (!codec_dai->probed) { |
1423 | if (codec_dai->driver->probe) { | 1423 | if (codec_dai->driver->probe) { |
1424 | ret = codec_dai->driver->probe(codec_dai); | 1424 | ret = codec_dai->driver->probe(codec_dai); |
1425 | if (ret < 0) { | 1425 | if (ret < 0) { |
1426 | printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n", | 1426 | printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n", |
1427 | codec_dai->name); | 1427 | codec_dai->name); |
1428 | return ret; | 1428 | return ret; |
1429 | } | 1429 | } |
1430 | } | 1430 | } |
1431 | 1431 | ||
1432 | /* mark cpu_dai as probed and add to card cpu_dai list */ | 1432 | /* mark cpu_dai as probed and add to card cpu_dai list */ |
1433 | codec_dai->probed = 1; | 1433 | codec_dai->probed = 1; |
1434 | list_add(&codec_dai->card_list, &card->dai_dev_list); | 1434 | list_add(&codec_dai->card_list, &card->dai_dev_list); |
1435 | } | 1435 | } |
1436 | 1436 | ||
1437 | /* DAPM dai link stream work */ | 1437 | /* DAPM dai link stream work */ |
1438 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); | 1438 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); |
1439 | 1439 | ||
1440 | /* now that all clients have probed, initialise the DAI link */ | 1440 | /* now that all clients have probed, initialise the DAI link */ |
1441 | if (dai_link->init) { | 1441 | if (dai_link->init) { |
1442 | ret = dai_link->init(rtd); | 1442 | ret = dai_link->init(rtd); |
1443 | if (ret < 0) { | 1443 | if (ret < 0) { |
1444 | printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name); | 1444 | printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name); |
1445 | return ret; | 1445 | return ret; |
1446 | } | 1446 | } |
1447 | } | 1447 | } |
1448 | 1448 | ||
1449 | /* Make sure all DAPM widgets are instantiated */ | 1449 | /* Make sure all DAPM widgets are instantiated */ |
1450 | snd_soc_dapm_new_widgets(codec); | 1450 | snd_soc_dapm_new_widgets(codec); |
1451 | snd_soc_dapm_sync(codec); | 1451 | snd_soc_dapm_sync(codec); |
1452 | 1452 | ||
1453 | /* register the rtd device */ | 1453 | /* register the rtd device */ |
1454 | rtd->dev.release = rtd_release; | 1454 | rtd->dev.release = rtd_release; |
1455 | rtd->dev.init_name = dai_link->name; | 1455 | rtd->dev.init_name = dai_link->name; |
1456 | ret = device_register(&rtd->dev); | 1456 | ret = device_register(&rtd->dev); |
1457 | if (ret < 0) { | 1457 | if (ret < 0) { |
1458 | printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret); | 1458 | printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret); |
1459 | return ret; | 1459 | return ret; |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | rtd->dev_registered = 1; | 1462 | rtd->dev_registered = 1; |
1463 | ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time); | 1463 | ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time); |
1464 | if (ret < 0) | 1464 | if (ret < 0) |
1465 | printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n"); | 1465 | printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n"); |
1466 | 1466 | ||
1467 | /* add DAPM sysfs entries for this codec */ | 1467 | /* add DAPM sysfs entries for this codec */ |
1468 | ret = snd_soc_dapm_sys_add(&rtd->dev); | 1468 | ret = snd_soc_dapm_sys_add(&rtd->dev); |
1469 | if (ret < 0) | 1469 | if (ret < 0) |
1470 | printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n"); | 1470 | printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n"); |
1471 | 1471 | ||
1472 | /* add codec sysfs entries */ | 1472 | /* add codec sysfs entries */ |
1473 | ret = device_create_file(&rtd->dev, &dev_attr_codec_reg); | 1473 | ret = device_create_file(&rtd->dev, &dev_attr_codec_reg); |
1474 | if (ret < 0) | 1474 | if (ret < 0) |
1475 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); | 1475 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); |
1476 | 1476 | ||
1477 | /* create the pcm */ | 1477 | /* create the pcm */ |
1478 | ret = soc_new_pcm(rtd, num); | 1478 | ret = soc_new_pcm(rtd, num); |
1479 | if (ret < 0) { | 1479 | if (ret < 0) { |
1480 | printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name); | 1480 | printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name); |
1481 | return ret; | 1481 | return ret; |
1482 | } | 1482 | } |
1483 | 1483 | ||
1484 | /* add platform data for AC97 devices */ | 1484 | /* add platform data for AC97 devices */ |
1485 | if (rtd->codec_dai->driver->ac97_control) | 1485 | if (rtd->codec_dai->driver->ac97_control) |
1486 | snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata); | 1486 | snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata); |
1487 | 1487 | ||
1488 | return 0; | 1488 | return 0; |
1489 | } | 1489 | } |
1490 | 1490 | ||
1491 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1491 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1492 | static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | 1492 | static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) |
1493 | { | 1493 | { |
1494 | int ret; | 1494 | int ret; |
1495 | 1495 | ||
1496 | /* Only instantiate AC97 if not already done by the adaptor | 1496 | /* Only instantiate AC97 if not already done by the adaptor |
1497 | * for the generic AC97 subsystem. | 1497 | * for the generic AC97 subsystem. |
1498 | */ | 1498 | */ |
1499 | if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) { | 1499 | if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) { |
1500 | /* | ||
1501 | * It is possible that the AC97 device is already registered to | ||
1502 | * the device subsystem. This happens when the device is created | ||
1503 | * via snd_ac97_mixer(). Currently only SoC codec that does so | ||
1504 | * is the generic AC97 glue but others migh emerge. | ||
1505 | * | ||
1506 | * In those cases we don't try to register the device again. | ||
1507 | */ | ||
1508 | if (!rtd->codec->ac97_created) | ||
1509 | return 0; | ||
1500 | 1510 | ||
1501 | ret = soc_ac97_dev_register(rtd->codec); | 1511 | ret = soc_ac97_dev_register(rtd->codec); |
1502 | if (ret < 0) { | 1512 | if (ret < 0) { |
1503 | printk(KERN_ERR "asoc: AC97 device register failed\n"); | 1513 | printk(KERN_ERR "asoc: AC97 device register failed\n"); |
1504 | return ret; | 1514 | return ret; |
1505 | } | 1515 | } |
1506 | 1516 | ||
1507 | rtd->codec->ac97_registered = 1; | 1517 | rtd->codec->ac97_registered = 1; |
1508 | } | 1518 | } |
1509 | return 0; | 1519 | return 0; |
1510 | } | 1520 | } |
1511 | 1521 | ||
1512 | static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec) | 1522 | static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec) |
1513 | { | 1523 | { |
1514 | if (codec->ac97_registered) { | 1524 | if (codec->ac97_registered) { |
1515 | soc_ac97_dev_unregister(codec); | 1525 | soc_ac97_dev_unregister(codec); |
1516 | codec->ac97_registered = 0; | 1526 | codec->ac97_registered = 0; |
1517 | } | 1527 | } |
1518 | } | 1528 | } |
1519 | #endif | 1529 | #endif |
1520 | 1530 | ||
1521 | static void snd_soc_instantiate_card(struct snd_soc_card *card) | 1531 | static void snd_soc_instantiate_card(struct snd_soc_card *card) |
1522 | { | 1532 | { |
1523 | struct platform_device *pdev = to_platform_device(card->dev); | 1533 | struct platform_device *pdev = to_platform_device(card->dev); |
1524 | int ret, i; | 1534 | int ret, i; |
1525 | 1535 | ||
1526 | mutex_lock(&card->mutex); | 1536 | mutex_lock(&card->mutex); |
1527 | 1537 | ||
1528 | if (card->instantiated) { | 1538 | if (card->instantiated) { |
1529 | mutex_unlock(&card->mutex); | 1539 | mutex_unlock(&card->mutex); |
1530 | return; | 1540 | return; |
1531 | } | 1541 | } |
1532 | 1542 | ||
1533 | /* bind DAIs */ | 1543 | /* bind DAIs */ |
1534 | for (i = 0; i < card->num_links; i++) | 1544 | for (i = 0; i < card->num_links; i++) |
1535 | soc_bind_dai_link(card, i); | 1545 | soc_bind_dai_link(card, i); |
1536 | 1546 | ||
1537 | /* bind completed ? */ | 1547 | /* bind completed ? */ |
1538 | if (card->num_rtd != card->num_links) { | 1548 | if (card->num_rtd != card->num_links) { |
1539 | mutex_unlock(&card->mutex); | 1549 | mutex_unlock(&card->mutex); |
1540 | return; | 1550 | return; |
1541 | } | 1551 | } |
1542 | 1552 | ||
1543 | /* card bind complete so register a sound card */ | 1553 | /* card bind complete so register a sound card */ |
1544 | ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, | 1554 | ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, |
1545 | card->owner, 0, &card->snd_card); | 1555 | card->owner, 0, &card->snd_card); |
1546 | if (ret < 0) { | 1556 | if (ret < 0) { |
1547 | printk(KERN_ERR "asoc: can't create sound card for card %s\n", | 1557 | printk(KERN_ERR "asoc: can't create sound card for card %s\n", |
1548 | card->name); | 1558 | card->name); |
1549 | mutex_unlock(&card->mutex); | 1559 | mutex_unlock(&card->mutex); |
1550 | return; | 1560 | return; |
1551 | } | 1561 | } |
1552 | card->snd_card->dev = card->dev; | 1562 | card->snd_card->dev = card->dev; |
1553 | 1563 | ||
1554 | #ifdef CONFIG_PM | 1564 | #ifdef CONFIG_PM |
1555 | /* deferred resume work */ | 1565 | /* deferred resume work */ |
1556 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); | 1566 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); |
1557 | #endif | 1567 | #endif |
1558 | 1568 | ||
1559 | /* initialise the sound card only once */ | 1569 | /* initialise the sound card only once */ |
1560 | if (card->probe) { | 1570 | if (card->probe) { |
1561 | ret = card->probe(pdev); | 1571 | ret = card->probe(pdev); |
1562 | if (ret < 0) | 1572 | if (ret < 0) |
1563 | goto card_probe_error; | 1573 | goto card_probe_error; |
1564 | } | 1574 | } |
1565 | 1575 | ||
1566 | for (i = 0; i < card->num_links; i++) { | 1576 | for (i = 0; i < card->num_links; i++) { |
1567 | ret = soc_probe_dai_link(card, i); | 1577 | ret = soc_probe_dai_link(card, i); |
1568 | if (ret < 0) { | 1578 | if (ret < 0) { |
1569 | pr_err("asoc: failed to instantiate card %s: %d\n", | 1579 | pr_err("asoc: failed to instantiate card %s: %d\n", |
1570 | card->name, ret); | 1580 | card->name, ret); |
1571 | goto probe_dai_err; | 1581 | goto probe_dai_err; |
1572 | } | 1582 | } |
1573 | } | 1583 | } |
1574 | 1584 | ||
1575 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), | 1585 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), |
1576 | "%s", card->name); | 1586 | "%s", card->name); |
1577 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), | 1587 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), |
1578 | "%s", card->name); | 1588 | "%s", card->name); |
1579 | 1589 | ||
1580 | ret = snd_card_register(card->snd_card); | 1590 | ret = snd_card_register(card->snd_card); |
1581 | if (ret < 0) { | 1591 | if (ret < 0) { |
1582 | printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); | 1592 | printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); |
1583 | goto probe_dai_err; | 1593 | goto probe_dai_err; |
1584 | } | 1594 | } |
1585 | 1595 | ||
1586 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1596 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1587 | /* register any AC97 codecs */ | 1597 | /* register any AC97 codecs */ |
1588 | for (i = 0; i < card->num_rtd; i++) { | 1598 | for (i = 0; i < card->num_rtd; i++) { |
1589 | ret = soc_register_ac97_dai_link(&card->rtd[i]); | 1599 | ret = soc_register_ac97_dai_link(&card->rtd[i]); |
1590 | if (ret < 0) { | 1600 | if (ret < 0) { |
1591 | printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); | 1601 | printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); |
1592 | goto probe_dai_err; | 1602 | goto probe_dai_err; |
1593 | } | 1603 | } |
1594 | } | 1604 | } |
1595 | #endif | 1605 | #endif |
1596 | 1606 | ||
1597 | card->instantiated = 1; | 1607 | card->instantiated = 1; |
1598 | mutex_unlock(&card->mutex); | 1608 | mutex_unlock(&card->mutex); |
1599 | return; | 1609 | return; |
1600 | 1610 | ||
1601 | probe_dai_err: | 1611 | probe_dai_err: |
1602 | for (i = 0; i < card->num_links; i++) | 1612 | for (i = 0; i < card->num_links; i++) |
1603 | soc_remove_dai_link(card, i); | 1613 | soc_remove_dai_link(card, i); |
1604 | 1614 | ||
1605 | card_probe_error: | 1615 | card_probe_error: |
1606 | if (card->remove) | 1616 | if (card->remove) |
1607 | card->remove(pdev); | 1617 | card->remove(pdev); |
1608 | 1618 | ||
1609 | snd_card_free(card->snd_card); | 1619 | snd_card_free(card->snd_card); |
1610 | 1620 | ||
1611 | mutex_unlock(&card->mutex); | 1621 | mutex_unlock(&card->mutex); |
1612 | } | 1622 | } |
1613 | 1623 | ||
1614 | /* | 1624 | /* |
1615 | * Attempt to initialise any uninitialised cards. Must be called with | 1625 | * Attempt to initialise any uninitialised cards. Must be called with |
1616 | * client_mutex. | 1626 | * client_mutex. |
1617 | */ | 1627 | */ |
1618 | static void snd_soc_instantiate_cards(void) | 1628 | static void snd_soc_instantiate_cards(void) |
1619 | { | 1629 | { |
1620 | struct snd_soc_card *card; | 1630 | struct snd_soc_card *card; |
1621 | list_for_each_entry(card, &card_list, list) | 1631 | list_for_each_entry(card, &card_list, list) |
1622 | snd_soc_instantiate_card(card); | 1632 | snd_soc_instantiate_card(card); |
1623 | } | 1633 | } |
1624 | 1634 | ||
1625 | /* probes a new socdev */ | 1635 | /* probes a new socdev */ |
1626 | static int soc_probe(struct platform_device *pdev) | 1636 | static int soc_probe(struct platform_device *pdev) |
1627 | { | 1637 | { |
1628 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 1638 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
1629 | int ret = 0; | 1639 | int ret = 0; |
1630 | 1640 | ||
1631 | /* Bodge while we unpick instantiation */ | 1641 | /* Bodge while we unpick instantiation */ |
1632 | card->dev = &pdev->dev; | 1642 | card->dev = &pdev->dev; |
1633 | INIT_LIST_HEAD(&card->dai_dev_list); | 1643 | INIT_LIST_HEAD(&card->dai_dev_list); |
1634 | INIT_LIST_HEAD(&card->codec_dev_list); | 1644 | INIT_LIST_HEAD(&card->codec_dev_list); |
1635 | INIT_LIST_HEAD(&card->platform_dev_list); | 1645 | INIT_LIST_HEAD(&card->platform_dev_list); |
1636 | 1646 | ||
1637 | ret = snd_soc_register_card(card); | 1647 | ret = snd_soc_register_card(card); |
1638 | if (ret != 0) { | 1648 | if (ret != 0) { |
1639 | dev_err(&pdev->dev, "Failed to register card\n"); | 1649 | dev_err(&pdev->dev, "Failed to register card\n"); |
1640 | return ret; | 1650 | return ret; |
1641 | } | 1651 | } |
1642 | 1652 | ||
1643 | return 0; | 1653 | return 0; |
1644 | } | 1654 | } |
1645 | 1655 | ||
1646 | /* removes a socdev */ | 1656 | /* removes a socdev */ |
1647 | static int soc_remove(struct platform_device *pdev) | 1657 | static int soc_remove(struct platform_device *pdev) |
1648 | { | 1658 | { |
1649 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 1659 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
1650 | int i; | 1660 | int i; |
1651 | 1661 | ||
1652 | if (card->instantiated) { | 1662 | if (card->instantiated) { |
1653 | 1663 | ||
1654 | /* make sure any delayed work runs */ | 1664 | /* make sure any delayed work runs */ |
1655 | for (i = 0; i < card->num_rtd; i++) { | 1665 | for (i = 0; i < card->num_rtd; i++) { |
1656 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | 1666 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
1657 | run_delayed_work(&rtd->delayed_work); | 1667 | run_delayed_work(&rtd->delayed_work); |
1658 | } | 1668 | } |
1659 | 1669 | ||
1660 | /* remove and free each DAI */ | 1670 | /* remove and free each DAI */ |
1661 | for (i = 0; i < card->num_rtd; i++) | 1671 | for (i = 0; i < card->num_rtd; i++) |
1662 | soc_remove_dai_link(card, i); | 1672 | soc_remove_dai_link(card, i); |
1663 | 1673 | ||
1664 | /* remove the card */ | 1674 | /* remove the card */ |
1665 | if (card->remove) | 1675 | if (card->remove) |
1666 | card->remove(pdev); | 1676 | card->remove(pdev); |
1667 | 1677 | ||
1668 | kfree(card->rtd); | 1678 | kfree(card->rtd); |
1669 | snd_card_free(card->snd_card); | 1679 | snd_card_free(card->snd_card); |
1670 | } | 1680 | } |
1671 | snd_soc_unregister_card(card); | 1681 | snd_soc_unregister_card(card); |
1672 | return 0; | 1682 | return 0; |
1673 | } | 1683 | } |
1674 | 1684 | ||
1675 | static int soc_poweroff(struct device *dev) | 1685 | static int soc_poweroff(struct device *dev) |
1676 | { | 1686 | { |
1677 | struct platform_device *pdev = to_platform_device(dev); | 1687 | struct platform_device *pdev = to_platform_device(dev); |
1678 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 1688 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
1679 | int i; | 1689 | int i; |
1680 | 1690 | ||
1681 | if (!card->instantiated) | 1691 | if (!card->instantiated) |
1682 | return 0; | 1692 | return 0; |
1683 | 1693 | ||
1684 | /* Flush out pmdown_time work - we actually do want to run it | 1694 | /* Flush out pmdown_time work - we actually do want to run it |
1685 | * now, we're shutting down so no imminent restart. */ | 1695 | * now, we're shutting down so no imminent restart. */ |
1686 | for (i = 0; i < card->num_rtd; i++) { | 1696 | for (i = 0; i < card->num_rtd; i++) { |
1687 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | 1697 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; |
1688 | run_delayed_work(&rtd->delayed_work); | 1698 | run_delayed_work(&rtd->delayed_work); |
1689 | } | 1699 | } |
1690 | 1700 | ||
1691 | snd_soc_dapm_shutdown(card); | 1701 | snd_soc_dapm_shutdown(card); |
1692 | 1702 | ||
1693 | return 0; | 1703 | return 0; |
1694 | } | 1704 | } |
1695 | 1705 | ||
1696 | static const struct dev_pm_ops soc_pm_ops = { | 1706 | static const struct dev_pm_ops soc_pm_ops = { |
1697 | .suspend = soc_suspend, | 1707 | .suspend = soc_suspend, |
1698 | .resume = soc_resume, | 1708 | .resume = soc_resume, |
1699 | .poweroff = soc_poweroff, | 1709 | .poweroff = soc_poweroff, |
1700 | }; | 1710 | }; |
1701 | 1711 | ||
1702 | /* ASoC platform driver */ | 1712 | /* ASoC platform driver */ |
1703 | static struct platform_driver soc_driver = { | 1713 | static struct platform_driver soc_driver = { |
1704 | .driver = { | 1714 | .driver = { |
1705 | .name = "soc-audio", | 1715 | .name = "soc-audio", |
1706 | .owner = THIS_MODULE, | 1716 | .owner = THIS_MODULE, |
1707 | .pm = &soc_pm_ops, | 1717 | .pm = &soc_pm_ops, |
1708 | }, | 1718 | }, |
1709 | .probe = soc_probe, | 1719 | .probe = soc_probe, |
1710 | .remove = soc_remove, | 1720 | .remove = soc_remove, |
1711 | }; | 1721 | }; |
1712 | 1722 | ||
1713 | /* create a new pcm */ | 1723 | /* create a new pcm */ |
1714 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 1724 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
1715 | { | 1725 | { |
1716 | struct snd_soc_codec *codec = rtd->codec; | 1726 | struct snd_soc_codec *codec = rtd->codec; |
1717 | struct snd_soc_platform *platform = rtd->platform; | 1727 | struct snd_soc_platform *platform = rtd->platform; |
1718 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1728 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
1719 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1729 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1720 | struct snd_pcm *pcm; | 1730 | struct snd_pcm *pcm; |
1721 | char new_name[64]; | 1731 | char new_name[64]; |
1722 | int ret = 0, playback = 0, capture = 0; | 1732 | int ret = 0, playback = 0, capture = 0; |
1723 | 1733 | ||
1724 | /* check client and interface hw capabilities */ | 1734 | /* check client and interface hw capabilities */ |
1725 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 1735 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
1726 | rtd->dai_link->stream_name, codec_dai->name, num); | 1736 | rtd->dai_link->stream_name, codec_dai->name, num); |
1727 | 1737 | ||
1728 | if (codec_dai->driver->playback.channels_min) | 1738 | if (codec_dai->driver->playback.channels_min) |
1729 | playback = 1; | 1739 | playback = 1; |
1730 | if (codec_dai->driver->capture.channels_min) | 1740 | if (codec_dai->driver->capture.channels_min) |
1731 | capture = 1; | 1741 | capture = 1; |
1732 | 1742 | ||
1733 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); | 1743 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); |
1734 | ret = snd_pcm_new(rtd->card->snd_card, new_name, | 1744 | ret = snd_pcm_new(rtd->card->snd_card, new_name, |
1735 | num, playback, capture, &pcm); | 1745 | num, playback, capture, &pcm); |
1736 | if (ret < 0) { | 1746 | if (ret < 0) { |
1737 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | 1747 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); |
1738 | return ret; | 1748 | return ret; |
1739 | } | 1749 | } |
1740 | 1750 | ||
1741 | rtd->pcm = pcm; | 1751 | rtd->pcm = pcm; |
1742 | pcm->private_data = rtd; | 1752 | pcm->private_data = rtd; |
1743 | soc_pcm_ops.mmap = platform->driver->ops->mmap; | 1753 | soc_pcm_ops.mmap = platform->driver->ops->mmap; |
1744 | soc_pcm_ops.pointer = platform->driver->ops->pointer; | 1754 | soc_pcm_ops.pointer = platform->driver->ops->pointer; |
1745 | soc_pcm_ops.ioctl = platform->driver->ops->ioctl; | 1755 | soc_pcm_ops.ioctl = platform->driver->ops->ioctl; |
1746 | soc_pcm_ops.copy = platform->driver->ops->copy; | 1756 | soc_pcm_ops.copy = platform->driver->ops->copy; |
1747 | soc_pcm_ops.silence = platform->driver->ops->silence; | 1757 | soc_pcm_ops.silence = platform->driver->ops->silence; |
1748 | soc_pcm_ops.ack = platform->driver->ops->ack; | 1758 | soc_pcm_ops.ack = platform->driver->ops->ack; |
1749 | soc_pcm_ops.page = platform->driver->ops->page; | 1759 | soc_pcm_ops.page = platform->driver->ops->page; |
1750 | 1760 | ||
1751 | if (playback) | 1761 | if (playback) |
1752 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); | 1762 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); |
1753 | 1763 | ||
1754 | if (capture) | 1764 | if (capture) |
1755 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); | 1765 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); |
1756 | 1766 | ||
1757 | ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm); | 1767 | ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm); |
1758 | if (ret < 0) { | 1768 | if (ret < 0) { |
1759 | printk(KERN_ERR "asoc: platform pcm constructor failed\n"); | 1769 | printk(KERN_ERR "asoc: platform pcm constructor failed\n"); |
1760 | return ret; | 1770 | return ret; |
1761 | } | 1771 | } |
1762 | 1772 | ||
1763 | pcm->private_free = platform->driver->pcm_free; | 1773 | pcm->private_free = platform->driver->pcm_free; |
1764 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | 1774 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, |
1765 | cpu_dai->name); | 1775 | cpu_dai->name); |
1766 | return ret; | 1776 | return ret; |
1767 | } | 1777 | } |
1768 | 1778 | ||
1769 | /** | 1779 | /** |
1770 | * snd_soc_codec_volatile_register: Report if a register is volatile. | 1780 | * snd_soc_codec_volatile_register: Report if a register is volatile. |
1771 | * | 1781 | * |
1772 | * @codec: CODEC to query. | 1782 | * @codec: CODEC to query. |
1773 | * @reg: Register to query. | 1783 | * @reg: Register to query. |
1774 | * | 1784 | * |
1775 | * Boolean function indiciating if a CODEC register is volatile. | 1785 | * Boolean function indiciating if a CODEC register is volatile. |
1776 | */ | 1786 | */ |
1777 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg) | 1787 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg) |
1778 | { | 1788 | { |
1779 | if (codec->driver->volatile_register) | 1789 | if (codec->driver->volatile_register) |
1780 | return codec->driver->volatile_register(reg); | 1790 | return codec->driver->volatile_register(reg); |
1781 | else | 1791 | else |
1782 | return 0; | 1792 | return 0; |
1783 | } | 1793 | } |
1784 | EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); | 1794 | EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); |
1785 | 1795 | ||
1786 | /** | 1796 | /** |
1787 | * snd_soc_new_ac97_codec - initailise AC97 device | 1797 | * snd_soc_new_ac97_codec - initailise AC97 device |
1788 | * @codec: audio codec | 1798 | * @codec: audio codec |
1789 | * @ops: AC97 bus operations | 1799 | * @ops: AC97 bus operations |
1790 | * @num: AC97 codec number | 1800 | * @num: AC97 codec number |
1791 | * | 1801 | * |
1792 | * Initialises AC97 codec resources for use by ad-hoc devices only. | 1802 | * Initialises AC97 codec resources for use by ad-hoc devices only. |
1793 | */ | 1803 | */ |
1794 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | 1804 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, |
1795 | struct snd_ac97_bus_ops *ops, int num) | 1805 | struct snd_ac97_bus_ops *ops, int num) |
1796 | { | 1806 | { |
1797 | mutex_lock(&codec->mutex); | 1807 | mutex_lock(&codec->mutex); |
1798 | 1808 | ||
1799 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | 1809 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); |
1800 | if (codec->ac97 == NULL) { | 1810 | if (codec->ac97 == NULL) { |
1801 | mutex_unlock(&codec->mutex); | 1811 | mutex_unlock(&codec->mutex); |
1802 | return -ENOMEM; | 1812 | return -ENOMEM; |
1803 | } | 1813 | } |
1804 | 1814 | ||
1805 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); | 1815 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); |
1806 | if (codec->ac97->bus == NULL) { | 1816 | if (codec->ac97->bus == NULL) { |
1807 | kfree(codec->ac97); | 1817 | kfree(codec->ac97); |
1808 | codec->ac97 = NULL; | 1818 | codec->ac97 = NULL; |
1809 | mutex_unlock(&codec->mutex); | 1819 | mutex_unlock(&codec->mutex); |
1810 | return -ENOMEM; | 1820 | return -ENOMEM; |
1811 | } | 1821 | } |
1812 | 1822 | ||
1813 | codec->ac97->bus->ops = ops; | 1823 | codec->ac97->bus->ops = ops; |
1814 | codec->ac97->num = num; | 1824 | codec->ac97->num = num; |
1825 | |||
1826 | /* | ||
1827 | * Mark the AC97 device to be created by us. This way we ensure that the | ||
1828 | * device will be registered with the device subsystem later on. | ||
1829 | */ | ||
1830 | codec->ac97_created = 1; | ||
1831 | |||
1815 | mutex_unlock(&codec->mutex); | 1832 | mutex_unlock(&codec->mutex); |
1816 | return 0; | 1833 | return 0; |
1817 | } | 1834 | } |
1818 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | 1835 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); |
1819 | 1836 | ||
1820 | /** | 1837 | /** |
1821 | * snd_soc_free_ac97_codec - free AC97 codec device | 1838 | * snd_soc_free_ac97_codec - free AC97 codec device |
1822 | * @codec: audio codec | 1839 | * @codec: audio codec |
1823 | * | 1840 | * |
1824 | * Frees AC97 codec device resources. | 1841 | * Frees AC97 codec device resources. |
1825 | */ | 1842 | */ |
1826 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | 1843 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) |
1827 | { | 1844 | { |
1828 | mutex_lock(&codec->mutex); | 1845 | mutex_lock(&codec->mutex); |
1829 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1846 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1830 | soc_unregister_ac97_dai_link(codec); | 1847 | soc_unregister_ac97_dai_link(codec); |
1831 | #endif | 1848 | #endif |
1832 | kfree(codec->ac97->bus); | 1849 | kfree(codec->ac97->bus); |
1833 | kfree(codec->ac97); | 1850 | kfree(codec->ac97); |
1834 | codec->ac97 = NULL; | 1851 | codec->ac97 = NULL; |
1852 | codec->ac97_created = 0; | ||
1835 | mutex_unlock(&codec->mutex); | 1853 | mutex_unlock(&codec->mutex); |
1836 | } | 1854 | } |
1837 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | 1855 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); |
1838 | 1856 | ||
1839 | /** | 1857 | /** |
1840 | * snd_soc_update_bits - update codec register bits | 1858 | * snd_soc_update_bits - update codec register bits |
1841 | * @codec: audio codec | 1859 | * @codec: audio codec |
1842 | * @reg: codec register | 1860 | * @reg: codec register |
1843 | * @mask: register mask | 1861 | * @mask: register mask |
1844 | * @value: new value | 1862 | * @value: new value |
1845 | * | 1863 | * |
1846 | * Writes new register value. | 1864 | * Writes new register value. |
1847 | * | 1865 | * |
1848 | * Returns 1 for change else 0. | 1866 | * Returns 1 for change else 0. |
1849 | */ | 1867 | */ |
1850 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 1868 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
1851 | unsigned int mask, unsigned int value) | 1869 | unsigned int mask, unsigned int value) |
1852 | { | 1870 | { |
1853 | int change; | 1871 | int change; |
1854 | unsigned int old, new; | 1872 | unsigned int old, new; |
1855 | 1873 | ||
1856 | old = snd_soc_read(codec, reg); | 1874 | old = snd_soc_read(codec, reg); |
1857 | new = (old & ~mask) | value; | 1875 | new = (old & ~mask) | value; |
1858 | change = old != new; | 1876 | change = old != new; |
1859 | if (change) | 1877 | if (change) |
1860 | snd_soc_write(codec, reg, new); | 1878 | snd_soc_write(codec, reg, new); |
1861 | 1879 | ||
1862 | return change; | 1880 | return change; |
1863 | } | 1881 | } |
1864 | EXPORT_SYMBOL_GPL(snd_soc_update_bits); | 1882 | EXPORT_SYMBOL_GPL(snd_soc_update_bits); |
1865 | 1883 | ||
1866 | /** | 1884 | /** |
1867 | * snd_soc_update_bits_locked - update codec register bits | 1885 | * snd_soc_update_bits_locked - update codec register bits |
1868 | * @codec: audio codec | 1886 | * @codec: audio codec |
1869 | * @reg: codec register | 1887 | * @reg: codec register |
1870 | * @mask: register mask | 1888 | * @mask: register mask |
1871 | * @value: new value | 1889 | * @value: new value |
1872 | * | 1890 | * |
1873 | * Writes new register value, and takes the codec mutex. | 1891 | * Writes new register value, and takes the codec mutex. |
1874 | * | 1892 | * |
1875 | * Returns 1 for change else 0. | 1893 | * Returns 1 for change else 0. |
1876 | */ | 1894 | */ |
1877 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, | 1895 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, |
1878 | unsigned short reg, unsigned int mask, | 1896 | unsigned short reg, unsigned int mask, |
1879 | unsigned int value) | 1897 | unsigned int value) |
1880 | { | 1898 | { |
1881 | int change; | 1899 | int change; |
1882 | 1900 | ||
1883 | mutex_lock(&codec->mutex); | 1901 | mutex_lock(&codec->mutex); |
1884 | change = snd_soc_update_bits(codec, reg, mask, value); | 1902 | change = snd_soc_update_bits(codec, reg, mask, value); |
1885 | mutex_unlock(&codec->mutex); | 1903 | mutex_unlock(&codec->mutex); |
1886 | 1904 | ||
1887 | return change; | 1905 | return change; |
1888 | } | 1906 | } |
1889 | EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked); | 1907 | EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked); |
1890 | 1908 | ||
1891 | /** | 1909 | /** |
1892 | * snd_soc_test_bits - test register for change | 1910 | * snd_soc_test_bits - test register for change |
1893 | * @codec: audio codec | 1911 | * @codec: audio codec |
1894 | * @reg: codec register | 1912 | * @reg: codec register |
1895 | * @mask: register mask | 1913 | * @mask: register mask |
1896 | * @value: new value | 1914 | * @value: new value |
1897 | * | 1915 | * |
1898 | * Tests a register with a new value and checks if the new value is | 1916 | * Tests a register with a new value and checks if the new value is |
1899 | * different from the old value. | 1917 | * different from the old value. |
1900 | * | 1918 | * |
1901 | * Returns 1 for change else 0. | 1919 | * Returns 1 for change else 0. |
1902 | */ | 1920 | */ |
1903 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | 1921 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, |
1904 | unsigned int mask, unsigned int value) | 1922 | unsigned int mask, unsigned int value) |
1905 | { | 1923 | { |
1906 | int change; | 1924 | int change; |
1907 | unsigned int old, new; | 1925 | unsigned int old, new; |
1908 | 1926 | ||
1909 | old = snd_soc_read(codec, reg); | 1927 | old = snd_soc_read(codec, reg); |
1910 | new = (old & ~mask) | value; | 1928 | new = (old & ~mask) | value; |
1911 | change = old != new; | 1929 | change = old != new; |
1912 | 1930 | ||
1913 | return change; | 1931 | return change; |
1914 | } | 1932 | } |
1915 | EXPORT_SYMBOL_GPL(snd_soc_test_bits); | 1933 | EXPORT_SYMBOL_GPL(snd_soc_test_bits); |
1916 | 1934 | ||
1917 | /** | 1935 | /** |
1918 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters | 1936 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters |
1919 | * @substream: the pcm substream | 1937 | * @substream: the pcm substream |
1920 | * @hw: the hardware parameters | 1938 | * @hw: the hardware parameters |
1921 | * | 1939 | * |
1922 | * Sets the substream runtime hardware parameters. | 1940 | * Sets the substream runtime hardware parameters. |
1923 | */ | 1941 | */ |
1924 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | 1942 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, |
1925 | const struct snd_pcm_hardware *hw) | 1943 | const struct snd_pcm_hardware *hw) |
1926 | { | 1944 | { |
1927 | struct snd_pcm_runtime *runtime = substream->runtime; | 1945 | struct snd_pcm_runtime *runtime = substream->runtime; |
1928 | runtime->hw.info = hw->info; | 1946 | runtime->hw.info = hw->info; |
1929 | runtime->hw.formats = hw->formats; | 1947 | runtime->hw.formats = hw->formats; |
1930 | runtime->hw.period_bytes_min = hw->period_bytes_min; | 1948 | runtime->hw.period_bytes_min = hw->period_bytes_min; |
1931 | runtime->hw.period_bytes_max = hw->period_bytes_max; | 1949 | runtime->hw.period_bytes_max = hw->period_bytes_max; |
1932 | runtime->hw.periods_min = hw->periods_min; | 1950 | runtime->hw.periods_min = hw->periods_min; |
1933 | runtime->hw.periods_max = hw->periods_max; | 1951 | runtime->hw.periods_max = hw->periods_max; |
1934 | runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; | 1952 | runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; |
1935 | runtime->hw.fifo_size = hw->fifo_size; | 1953 | runtime->hw.fifo_size = hw->fifo_size; |
1936 | return 0; | 1954 | return 0; |
1937 | } | 1955 | } |
1938 | EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); | 1956 | EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); |
1939 | 1957 | ||
1940 | /** | 1958 | /** |
1941 | * snd_soc_cnew - create new control | 1959 | * snd_soc_cnew - create new control |
1942 | * @_template: control template | 1960 | * @_template: control template |
1943 | * @data: control private data | 1961 | * @data: control private data |
1944 | * @long_name: control long name | 1962 | * @long_name: control long name |
1945 | * | 1963 | * |
1946 | * Create a new mixer control from a template control. | 1964 | * Create a new mixer control from a template control. |
1947 | * | 1965 | * |
1948 | * Returns 0 for success, else error. | 1966 | * Returns 0 for success, else error. |
1949 | */ | 1967 | */ |
1950 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | 1968 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, |
1951 | void *data, char *long_name) | 1969 | void *data, char *long_name) |
1952 | { | 1970 | { |
1953 | struct snd_kcontrol_new template; | 1971 | struct snd_kcontrol_new template; |
1954 | 1972 | ||
1955 | memcpy(&template, _template, sizeof(template)); | 1973 | memcpy(&template, _template, sizeof(template)); |
1956 | if (long_name) | 1974 | if (long_name) |
1957 | template.name = long_name; | 1975 | template.name = long_name; |
1958 | template.index = 0; | 1976 | template.index = 0; |
1959 | 1977 | ||
1960 | return snd_ctl_new1(&template, data); | 1978 | return snd_ctl_new1(&template, data); |
1961 | } | 1979 | } |
1962 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | 1980 | EXPORT_SYMBOL_GPL(snd_soc_cnew); |
1963 | 1981 | ||
1964 | /** | 1982 | /** |
1965 | * snd_soc_add_controls - add an array of controls to a codec. | 1983 | * snd_soc_add_controls - add an array of controls to a codec. |
1966 | * Convienience function to add a list of controls. Many codecs were | 1984 | * Convienience function to add a list of controls. Many codecs were |
1967 | * duplicating this code. | 1985 | * duplicating this code. |
1968 | * | 1986 | * |
1969 | * @codec: codec to add controls to | 1987 | * @codec: codec to add controls to |
1970 | * @controls: array of controls to add | 1988 | * @controls: array of controls to add |
1971 | * @num_controls: number of elements in the array | 1989 | * @num_controls: number of elements in the array |
1972 | * | 1990 | * |
1973 | * Return 0 for success, else error. | 1991 | * Return 0 for success, else error. |
1974 | */ | 1992 | */ |
1975 | int snd_soc_add_controls(struct snd_soc_codec *codec, | 1993 | int snd_soc_add_controls(struct snd_soc_codec *codec, |
1976 | const struct snd_kcontrol_new *controls, int num_controls) | 1994 | const struct snd_kcontrol_new *controls, int num_controls) |
1977 | { | 1995 | { |
1978 | struct snd_card *card = codec->card->snd_card; | 1996 | struct snd_card *card = codec->card->snd_card; |
1979 | int err, i; | 1997 | int err, i; |
1980 | 1998 | ||
1981 | for (i = 0; i < num_controls; i++) { | 1999 | for (i = 0; i < num_controls; i++) { |
1982 | const struct snd_kcontrol_new *control = &controls[i]; | 2000 | const struct snd_kcontrol_new *control = &controls[i]; |
1983 | err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); | 2001 | err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); |
1984 | if (err < 0) { | 2002 | if (err < 0) { |
1985 | dev_err(codec->dev, "%s: Failed to add %s: %d\n", | 2003 | dev_err(codec->dev, "%s: Failed to add %s: %d\n", |
1986 | codec->name, control->name, err); | 2004 | codec->name, control->name, err); |
1987 | return err; | 2005 | return err; |
1988 | } | 2006 | } |
1989 | } | 2007 | } |
1990 | 2008 | ||
1991 | return 0; | 2009 | return 0; |
1992 | } | 2010 | } |
1993 | EXPORT_SYMBOL_GPL(snd_soc_add_controls); | 2011 | EXPORT_SYMBOL_GPL(snd_soc_add_controls); |
1994 | 2012 | ||
1995 | /** | 2013 | /** |
1996 | * snd_soc_info_enum_double - enumerated double mixer info callback | 2014 | * snd_soc_info_enum_double - enumerated double mixer info callback |
1997 | * @kcontrol: mixer control | 2015 | * @kcontrol: mixer control |
1998 | * @uinfo: control element information | 2016 | * @uinfo: control element information |
1999 | * | 2017 | * |
2000 | * Callback to provide information about a double enumerated | 2018 | * Callback to provide information about a double enumerated |
2001 | * mixer control. | 2019 | * mixer control. |
2002 | * | 2020 | * |
2003 | * Returns 0 for success. | 2021 | * Returns 0 for success. |
2004 | */ | 2022 | */ |
2005 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | 2023 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, |
2006 | struct snd_ctl_elem_info *uinfo) | 2024 | struct snd_ctl_elem_info *uinfo) |
2007 | { | 2025 | { |
2008 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2026 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2009 | 2027 | ||
2010 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2028 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
2011 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | 2029 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; |
2012 | uinfo->value.enumerated.items = e->max; | 2030 | uinfo->value.enumerated.items = e->max; |
2013 | 2031 | ||
2014 | if (uinfo->value.enumerated.item > e->max - 1) | 2032 | if (uinfo->value.enumerated.item > e->max - 1) |
2015 | uinfo->value.enumerated.item = e->max - 1; | 2033 | uinfo->value.enumerated.item = e->max - 1; |
2016 | strcpy(uinfo->value.enumerated.name, | 2034 | strcpy(uinfo->value.enumerated.name, |
2017 | e->texts[uinfo->value.enumerated.item]); | 2035 | e->texts[uinfo->value.enumerated.item]); |
2018 | return 0; | 2036 | return 0; |
2019 | } | 2037 | } |
2020 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | 2038 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); |
2021 | 2039 | ||
2022 | /** | 2040 | /** |
2023 | * snd_soc_get_enum_double - enumerated double mixer get callback | 2041 | * snd_soc_get_enum_double - enumerated double mixer get callback |
2024 | * @kcontrol: mixer control | 2042 | * @kcontrol: mixer control |
2025 | * @ucontrol: control element information | 2043 | * @ucontrol: control element information |
2026 | * | 2044 | * |
2027 | * Callback to get the value of a double enumerated mixer. | 2045 | * Callback to get the value of a double enumerated mixer. |
2028 | * | 2046 | * |
2029 | * Returns 0 for success. | 2047 | * Returns 0 for success. |
2030 | */ | 2048 | */ |
2031 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | 2049 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, |
2032 | struct snd_ctl_elem_value *ucontrol) | 2050 | struct snd_ctl_elem_value *ucontrol) |
2033 | { | 2051 | { |
2034 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2052 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2035 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2053 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2036 | unsigned int val, bitmask; | 2054 | unsigned int val, bitmask; |
2037 | 2055 | ||
2038 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 2056 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
2039 | ; | 2057 | ; |
2040 | val = snd_soc_read(codec, e->reg); | 2058 | val = snd_soc_read(codec, e->reg); |
2041 | ucontrol->value.enumerated.item[0] | 2059 | ucontrol->value.enumerated.item[0] |
2042 | = (val >> e->shift_l) & (bitmask - 1); | 2060 | = (val >> e->shift_l) & (bitmask - 1); |
2043 | if (e->shift_l != e->shift_r) | 2061 | if (e->shift_l != e->shift_r) |
2044 | ucontrol->value.enumerated.item[1] = | 2062 | ucontrol->value.enumerated.item[1] = |
2045 | (val >> e->shift_r) & (bitmask - 1); | 2063 | (val >> e->shift_r) & (bitmask - 1); |
2046 | 2064 | ||
2047 | return 0; | 2065 | return 0; |
2048 | } | 2066 | } |
2049 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | 2067 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); |
2050 | 2068 | ||
2051 | /** | 2069 | /** |
2052 | * snd_soc_put_enum_double - enumerated double mixer put callback | 2070 | * snd_soc_put_enum_double - enumerated double mixer put callback |
2053 | * @kcontrol: mixer control | 2071 | * @kcontrol: mixer control |
2054 | * @ucontrol: control element information | 2072 | * @ucontrol: control element information |
2055 | * | 2073 | * |
2056 | * Callback to set the value of a double enumerated mixer. | 2074 | * Callback to set the value of a double enumerated mixer. |
2057 | * | 2075 | * |
2058 | * Returns 0 for success. | 2076 | * Returns 0 for success. |
2059 | */ | 2077 | */ |
2060 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | 2078 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, |
2061 | struct snd_ctl_elem_value *ucontrol) | 2079 | struct snd_ctl_elem_value *ucontrol) |
2062 | { | 2080 | { |
2063 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2081 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2064 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2082 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2065 | unsigned int val; | 2083 | unsigned int val; |
2066 | unsigned int mask, bitmask; | 2084 | unsigned int mask, bitmask; |
2067 | 2085 | ||
2068 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 2086 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
2069 | ; | 2087 | ; |
2070 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2088 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2071 | return -EINVAL; | 2089 | return -EINVAL; |
2072 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 2090 | val = ucontrol->value.enumerated.item[0] << e->shift_l; |
2073 | mask = (bitmask - 1) << e->shift_l; | 2091 | mask = (bitmask - 1) << e->shift_l; |
2074 | if (e->shift_l != e->shift_r) { | 2092 | if (e->shift_l != e->shift_r) { |
2075 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2093 | if (ucontrol->value.enumerated.item[1] > e->max - 1) |
2076 | return -EINVAL; | 2094 | return -EINVAL; |
2077 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 2095 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; |
2078 | mask |= (bitmask - 1) << e->shift_r; | 2096 | mask |= (bitmask - 1) << e->shift_r; |
2079 | } | 2097 | } |
2080 | 2098 | ||
2081 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); | 2099 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); |
2082 | } | 2100 | } |
2083 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | 2101 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); |
2084 | 2102 | ||
2085 | /** | 2103 | /** |
2086 | * snd_soc_get_value_enum_double - semi enumerated double mixer get callback | 2104 | * snd_soc_get_value_enum_double - semi enumerated double mixer get callback |
2087 | * @kcontrol: mixer control | 2105 | * @kcontrol: mixer control |
2088 | * @ucontrol: control element information | 2106 | * @ucontrol: control element information |
2089 | * | 2107 | * |
2090 | * Callback to get the value of a double semi enumerated mixer. | 2108 | * Callback to get the value of a double semi enumerated mixer. |
2091 | * | 2109 | * |
2092 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | 2110 | * Semi enumerated mixer: the enumerated items are referred as values. Can be |
2093 | * used for handling bitfield coded enumeration for example. | 2111 | * used for handling bitfield coded enumeration for example. |
2094 | * | 2112 | * |
2095 | * Returns 0 for success. | 2113 | * Returns 0 for success. |
2096 | */ | 2114 | */ |
2097 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | 2115 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, |
2098 | struct snd_ctl_elem_value *ucontrol) | 2116 | struct snd_ctl_elem_value *ucontrol) |
2099 | { | 2117 | { |
2100 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2118 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2101 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2119 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2102 | unsigned int reg_val, val, mux; | 2120 | unsigned int reg_val, val, mux; |
2103 | 2121 | ||
2104 | reg_val = snd_soc_read(codec, e->reg); | 2122 | reg_val = snd_soc_read(codec, e->reg); |
2105 | val = (reg_val >> e->shift_l) & e->mask; | 2123 | val = (reg_val >> e->shift_l) & e->mask; |
2106 | for (mux = 0; mux < e->max; mux++) { | 2124 | for (mux = 0; mux < e->max; mux++) { |
2107 | if (val == e->values[mux]) | 2125 | if (val == e->values[mux]) |
2108 | break; | 2126 | break; |
2109 | } | 2127 | } |
2110 | ucontrol->value.enumerated.item[0] = mux; | 2128 | ucontrol->value.enumerated.item[0] = mux; |
2111 | if (e->shift_l != e->shift_r) { | 2129 | if (e->shift_l != e->shift_r) { |
2112 | val = (reg_val >> e->shift_r) & e->mask; | 2130 | val = (reg_val >> e->shift_r) & e->mask; |
2113 | for (mux = 0; mux < e->max; mux++) { | 2131 | for (mux = 0; mux < e->max; mux++) { |
2114 | if (val == e->values[mux]) | 2132 | if (val == e->values[mux]) |
2115 | break; | 2133 | break; |
2116 | } | 2134 | } |
2117 | ucontrol->value.enumerated.item[1] = mux; | 2135 | ucontrol->value.enumerated.item[1] = mux; |
2118 | } | 2136 | } |
2119 | 2137 | ||
2120 | return 0; | 2138 | return 0; |
2121 | } | 2139 | } |
2122 | EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); | 2140 | EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); |
2123 | 2141 | ||
2124 | /** | 2142 | /** |
2125 | * snd_soc_put_value_enum_double - semi enumerated double mixer put callback | 2143 | * snd_soc_put_value_enum_double - semi enumerated double mixer put callback |
2126 | * @kcontrol: mixer control | 2144 | * @kcontrol: mixer control |
2127 | * @ucontrol: control element information | 2145 | * @ucontrol: control element information |
2128 | * | 2146 | * |
2129 | * Callback to set the value of a double semi enumerated mixer. | 2147 | * Callback to set the value of a double semi enumerated mixer. |
2130 | * | 2148 | * |
2131 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | 2149 | * Semi enumerated mixer: the enumerated items are referred as values. Can be |
2132 | * used for handling bitfield coded enumeration for example. | 2150 | * used for handling bitfield coded enumeration for example. |
2133 | * | 2151 | * |
2134 | * Returns 0 for success. | 2152 | * Returns 0 for success. |
2135 | */ | 2153 | */ |
2136 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | 2154 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, |
2137 | struct snd_ctl_elem_value *ucontrol) | 2155 | struct snd_ctl_elem_value *ucontrol) |
2138 | { | 2156 | { |
2139 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2157 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2140 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2158 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2141 | unsigned int val; | 2159 | unsigned int val; |
2142 | unsigned int mask; | 2160 | unsigned int mask; |
2143 | 2161 | ||
2144 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2162 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2145 | return -EINVAL; | 2163 | return -EINVAL; |
2146 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | 2164 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; |
2147 | mask = e->mask << e->shift_l; | 2165 | mask = e->mask << e->shift_l; |
2148 | if (e->shift_l != e->shift_r) { | 2166 | if (e->shift_l != e->shift_r) { |
2149 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2167 | if (ucontrol->value.enumerated.item[1] > e->max - 1) |
2150 | return -EINVAL; | 2168 | return -EINVAL; |
2151 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | 2169 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; |
2152 | mask |= e->mask << e->shift_r; | 2170 | mask |= e->mask << e->shift_r; |
2153 | } | 2171 | } |
2154 | 2172 | ||
2155 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); | 2173 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); |
2156 | } | 2174 | } |
2157 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | 2175 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); |
2158 | 2176 | ||
2159 | /** | 2177 | /** |
2160 | * snd_soc_info_enum_ext - external enumerated single mixer info callback | 2178 | * snd_soc_info_enum_ext - external enumerated single mixer info callback |
2161 | * @kcontrol: mixer control | 2179 | * @kcontrol: mixer control |
2162 | * @uinfo: control element information | 2180 | * @uinfo: control element information |
2163 | * | 2181 | * |
2164 | * Callback to provide information about an external enumerated | 2182 | * Callback to provide information about an external enumerated |
2165 | * single mixer. | 2183 | * single mixer. |
2166 | * | 2184 | * |
2167 | * Returns 0 for success. | 2185 | * Returns 0 for success. |
2168 | */ | 2186 | */ |
2169 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | 2187 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, |
2170 | struct snd_ctl_elem_info *uinfo) | 2188 | struct snd_ctl_elem_info *uinfo) |
2171 | { | 2189 | { |
2172 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2190 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2173 | 2191 | ||
2174 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2192 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
2175 | uinfo->count = 1; | 2193 | uinfo->count = 1; |
2176 | uinfo->value.enumerated.items = e->max; | 2194 | uinfo->value.enumerated.items = e->max; |
2177 | 2195 | ||
2178 | if (uinfo->value.enumerated.item > e->max - 1) | 2196 | if (uinfo->value.enumerated.item > e->max - 1) |
2179 | uinfo->value.enumerated.item = e->max - 1; | 2197 | uinfo->value.enumerated.item = e->max - 1; |
2180 | strcpy(uinfo->value.enumerated.name, | 2198 | strcpy(uinfo->value.enumerated.name, |
2181 | e->texts[uinfo->value.enumerated.item]); | 2199 | e->texts[uinfo->value.enumerated.item]); |
2182 | return 0; | 2200 | return 0; |
2183 | } | 2201 | } |
2184 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); | 2202 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); |
2185 | 2203 | ||
2186 | /** | 2204 | /** |
2187 | * snd_soc_info_volsw_ext - external single mixer info callback | 2205 | * snd_soc_info_volsw_ext - external single mixer info callback |
2188 | * @kcontrol: mixer control | 2206 | * @kcontrol: mixer control |
2189 | * @uinfo: control element information | 2207 | * @uinfo: control element information |
2190 | * | 2208 | * |
2191 | * Callback to provide information about a single external mixer control. | 2209 | * Callback to provide information about a single external mixer control. |
2192 | * | 2210 | * |
2193 | * Returns 0 for success. | 2211 | * Returns 0 for success. |
2194 | */ | 2212 | */ |
2195 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | 2213 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, |
2196 | struct snd_ctl_elem_info *uinfo) | 2214 | struct snd_ctl_elem_info *uinfo) |
2197 | { | 2215 | { |
2198 | int max = kcontrol->private_value; | 2216 | int max = kcontrol->private_value; |
2199 | 2217 | ||
2200 | if (max == 1 && !strstr(kcontrol->id.name, " Volume")) | 2218 | if (max == 1 && !strstr(kcontrol->id.name, " Volume")) |
2201 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 2219 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
2202 | else | 2220 | else |
2203 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2221 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2204 | 2222 | ||
2205 | uinfo->count = 1; | 2223 | uinfo->count = 1; |
2206 | uinfo->value.integer.min = 0; | 2224 | uinfo->value.integer.min = 0; |
2207 | uinfo->value.integer.max = max; | 2225 | uinfo->value.integer.max = max; |
2208 | return 0; | 2226 | return 0; |
2209 | } | 2227 | } |
2210 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | 2228 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); |
2211 | 2229 | ||
2212 | /** | 2230 | /** |
2213 | * snd_soc_info_volsw - single mixer info callback | 2231 | * snd_soc_info_volsw - single mixer info callback |
2214 | * @kcontrol: mixer control | 2232 | * @kcontrol: mixer control |
2215 | * @uinfo: control element information | 2233 | * @uinfo: control element information |
2216 | * | 2234 | * |
2217 | * Callback to provide information about a single mixer control. | 2235 | * Callback to provide information about a single mixer control. |
2218 | * | 2236 | * |
2219 | * Returns 0 for success. | 2237 | * Returns 0 for success. |
2220 | */ | 2238 | */ |
2221 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 2239 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
2222 | struct snd_ctl_elem_info *uinfo) | 2240 | struct snd_ctl_elem_info *uinfo) |
2223 | { | 2241 | { |
2224 | struct soc_mixer_control *mc = | 2242 | struct soc_mixer_control *mc = |
2225 | (struct soc_mixer_control *)kcontrol->private_value; | 2243 | (struct soc_mixer_control *)kcontrol->private_value; |
2226 | int platform_max; | 2244 | int platform_max; |
2227 | unsigned int shift = mc->shift; | 2245 | unsigned int shift = mc->shift; |
2228 | unsigned int rshift = mc->rshift; | 2246 | unsigned int rshift = mc->rshift; |
2229 | 2247 | ||
2230 | if (!mc->platform_max) | 2248 | if (!mc->platform_max) |
2231 | mc->platform_max = mc->max; | 2249 | mc->platform_max = mc->max; |
2232 | platform_max = mc->platform_max; | 2250 | platform_max = mc->platform_max; |
2233 | 2251 | ||
2234 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | 2252 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) |
2235 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 2253 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
2236 | else | 2254 | else |
2237 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2255 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2238 | 2256 | ||
2239 | uinfo->count = shift == rshift ? 1 : 2; | 2257 | uinfo->count = shift == rshift ? 1 : 2; |
2240 | uinfo->value.integer.min = 0; | 2258 | uinfo->value.integer.min = 0; |
2241 | uinfo->value.integer.max = platform_max; | 2259 | uinfo->value.integer.max = platform_max; |
2242 | return 0; | 2260 | return 0; |
2243 | } | 2261 | } |
2244 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 2262 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
2245 | 2263 | ||
2246 | /** | 2264 | /** |
2247 | * snd_soc_get_volsw - single mixer get callback | 2265 | * snd_soc_get_volsw - single mixer get callback |
2248 | * @kcontrol: mixer control | 2266 | * @kcontrol: mixer control |
2249 | * @ucontrol: control element information | 2267 | * @ucontrol: control element information |
2250 | * | 2268 | * |
2251 | * Callback to get the value of a single mixer control. | 2269 | * Callback to get the value of a single mixer control. |
2252 | * | 2270 | * |
2253 | * Returns 0 for success. | 2271 | * Returns 0 for success. |
2254 | */ | 2272 | */ |
2255 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | 2273 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, |
2256 | struct snd_ctl_elem_value *ucontrol) | 2274 | struct snd_ctl_elem_value *ucontrol) |
2257 | { | 2275 | { |
2258 | struct soc_mixer_control *mc = | 2276 | struct soc_mixer_control *mc = |
2259 | (struct soc_mixer_control *)kcontrol->private_value; | 2277 | (struct soc_mixer_control *)kcontrol->private_value; |
2260 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2278 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2261 | unsigned int reg = mc->reg; | 2279 | unsigned int reg = mc->reg; |
2262 | unsigned int shift = mc->shift; | 2280 | unsigned int shift = mc->shift; |
2263 | unsigned int rshift = mc->rshift; | 2281 | unsigned int rshift = mc->rshift; |
2264 | int max = mc->max; | 2282 | int max = mc->max; |
2265 | unsigned int mask = (1 << fls(max)) - 1; | 2283 | unsigned int mask = (1 << fls(max)) - 1; |
2266 | unsigned int invert = mc->invert; | 2284 | unsigned int invert = mc->invert; |
2267 | 2285 | ||
2268 | ucontrol->value.integer.value[0] = | 2286 | ucontrol->value.integer.value[0] = |
2269 | (snd_soc_read(codec, reg) >> shift) & mask; | 2287 | (snd_soc_read(codec, reg) >> shift) & mask; |
2270 | if (shift != rshift) | 2288 | if (shift != rshift) |
2271 | ucontrol->value.integer.value[1] = | 2289 | ucontrol->value.integer.value[1] = |
2272 | (snd_soc_read(codec, reg) >> rshift) & mask; | 2290 | (snd_soc_read(codec, reg) >> rshift) & mask; |
2273 | if (invert) { | 2291 | if (invert) { |
2274 | ucontrol->value.integer.value[0] = | 2292 | ucontrol->value.integer.value[0] = |
2275 | max - ucontrol->value.integer.value[0]; | 2293 | max - ucontrol->value.integer.value[0]; |
2276 | if (shift != rshift) | 2294 | if (shift != rshift) |
2277 | ucontrol->value.integer.value[1] = | 2295 | ucontrol->value.integer.value[1] = |
2278 | max - ucontrol->value.integer.value[1]; | 2296 | max - ucontrol->value.integer.value[1]; |
2279 | } | 2297 | } |
2280 | 2298 | ||
2281 | return 0; | 2299 | return 0; |
2282 | } | 2300 | } |
2283 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | 2301 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); |
2284 | 2302 | ||
2285 | /** | 2303 | /** |
2286 | * snd_soc_put_volsw - single mixer put callback | 2304 | * snd_soc_put_volsw - single mixer put callback |
2287 | * @kcontrol: mixer control | 2305 | * @kcontrol: mixer control |
2288 | * @ucontrol: control element information | 2306 | * @ucontrol: control element information |
2289 | * | 2307 | * |
2290 | * Callback to set the value of a single mixer control. | 2308 | * Callback to set the value of a single mixer control. |
2291 | * | 2309 | * |
2292 | * Returns 0 for success. | 2310 | * Returns 0 for success. |
2293 | */ | 2311 | */ |
2294 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | 2312 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, |
2295 | struct snd_ctl_elem_value *ucontrol) | 2313 | struct snd_ctl_elem_value *ucontrol) |
2296 | { | 2314 | { |
2297 | struct soc_mixer_control *mc = | 2315 | struct soc_mixer_control *mc = |
2298 | (struct soc_mixer_control *)kcontrol->private_value; | 2316 | (struct soc_mixer_control *)kcontrol->private_value; |
2299 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2317 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2300 | unsigned int reg = mc->reg; | 2318 | unsigned int reg = mc->reg; |
2301 | unsigned int shift = mc->shift; | 2319 | unsigned int shift = mc->shift; |
2302 | unsigned int rshift = mc->rshift; | 2320 | unsigned int rshift = mc->rshift; |
2303 | int max = mc->max; | 2321 | int max = mc->max; |
2304 | unsigned int mask = (1 << fls(max)) - 1; | 2322 | unsigned int mask = (1 << fls(max)) - 1; |
2305 | unsigned int invert = mc->invert; | 2323 | unsigned int invert = mc->invert; |
2306 | unsigned int val, val2, val_mask; | 2324 | unsigned int val, val2, val_mask; |
2307 | 2325 | ||
2308 | val = (ucontrol->value.integer.value[0] & mask); | 2326 | val = (ucontrol->value.integer.value[0] & mask); |
2309 | if (invert) | 2327 | if (invert) |
2310 | val = max - val; | 2328 | val = max - val; |
2311 | val_mask = mask << shift; | 2329 | val_mask = mask << shift; |
2312 | val = val << shift; | 2330 | val = val << shift; |
2313 | if (shift != rshift) { | 2331 | if (shift != rshift) { |
2314 | val2 = (ucontrol->value.integer.value[1] & mask); | 2332 | val2 = (ucontrol->value.integer.value[1] & mask); |
2315 | if (invert) | 2333 | if (invert) |
2316 | val2 = max - val2; | 2334 | val2 = max - val2; |
2317 | val_mask |= mask << rshift; | 2335 | val_mask |= mask << rshift; |
2318 | val |= val2 << rshift; | 2336 | val |= val2 << rshift; |
2319 | } | 2337 | } |
2320 | return snd_soc_update_bits_locked(codec, reg, val_mask, val); | 2338 | return snd_soc_update_bits_locked(codec, reg, val_mask, val); |
2321 | } | 2339 | } |
2322 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | 2340 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); |
2323 | 2341 | ||
2324 | /** | 2342 | /** |
2325 | * snd_soc_info_volsw_2r - double mixer info callback | 2343 | * snd_soc_info_volsw_2r - double mixer info callback |
2326 | * @kcontrol: mixer control | 2344 | * @kcontrol: mixer control |
2327 | * @uinfo: control element information | 2345 | * @uinfo: control element information |
2328 | * | 2346 | * |
2329 | * Callback to provide information about a double mixer control that | 2347 | * Callback to provide information about a double mixer control that |
2330 | * spans 2 codec registers. | 2348 | * spans 2 codec registers. |
2331 | * | 2349 | * |
2332 | * Returns 0 for success. | 2350 | * Returns 0 for success. |
2333 | */ | 2351 | */ |
2334 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | 2352 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, |
2335 | struct snd_ctl_elem_info *uinfo) | 2353 | struct snd_ctl_elem_info *uinfo) |
2336 | { | 2354 | { |
2337 | struct soc_mixer_control *mc = | 2355 | struct soc_mixer_control *mc = |
2338 | (struct soc_mixer_control *)kcontrol->private_value; | 2356 | (struct soc_mixer_control *)kcontrol->private_value; |
2339 | int platform_max; | 2357 | int platform_max; |
2340 | 2358 | ||
2341 | if (!mc->platform_max) | 2359 | if (!mc->platform_max) |
2342 | mc->platform_max = mc->max; | 2360 | mc->platform_max = mc->max; |
2343 | platform_max = mc->platform_max; | 2361 | platform_max = mc->platform_max; |
2344 | 2362 | ||
2345 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | 2363 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) |
2346 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 2364 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
2347 | else | 2365 | else |
2348 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2366 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2349 | 2367 | ||
2350 | uinfo->count = 2; | 2368 | uinfo->count = 2; |
2351 | uinfo->value.integer.min = 0; | 2369 | uinfo->value.integer.min = 0; |
2352 | uinfo->value.integer.max = platform_max; | 2370 | uinfo->value.integer.max = platform_max; |
2353 | return 0; | 2371 | return 0; |
2354 | } | 2372 | } |
2355 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); | 2373 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); |
2356 | 2374 | ||
2357 | /** | 2375 | /** |
2358 | * snd_soc_get_volsw_2r - double mixer get callback | 2376 | * snd_soc_get_volsw_2r - double mixer get callback |
2359 | * @kcontrol: mixer control | 2377 | * @kcontrol: mixer control |
2360 | * @ucontrol: control element information | 2378 | * @ucontrol: control element information |
2361 | * | 2379 | * |
2362 | * Callback to get the value of a double mixer control that spans 2 registers. | 2380 | * Callback to get the value of a double mixer control that spans 2 registers. |
2363 | * | 2381 | * |
2364 | * Returns 0 for success. | 2382 | * Returns 0 for success. |
2365 | */ | 2383 | */ |
2366 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | 2384 | int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, |
2367 | struct snd_ctl_elem_value *ucontrol) | 2385 | struct snd_ctl_elem_value *ucontrol) |
2368 | { | 2386 | { |
2369 | struct soc_mixer_control *mc = | 2387 | struct soc_mixer_control *mc = |
2370 | (struct soc_mixer_control *)kcontrol->private_value; | 2388 | (struct soc_mixer_control *)kcontrol->private_value; |
2371 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2389 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2372 | unsigned int reg = mc->reg; | 2390 | unsigned int reg = mc->reg; |
2373 | unsigned int reg2 = mc->rreg; | 2391 | unsigned int reg2 = mc->rreg; |
2374 | unsigned int shift = mc->shift; | 2392 | unsigned int shift = mc->shift; |
2375 | int max = mc->max; | 2393 | int max = mc->max; |
2376 | unsigned int mask = (1 << fls(max)) - 1; | 2394 | unsigned int mask = (1 << fls(max)) - 1; |
2377 | unsigned int invert = mc->invert; | 2395 | unsigned int invert = mc->invert; |
2378 | 2396 | ||
2379 | ucontrol->value.integer.value[0] = | 2397 | ucontrol->value.integer.value[0] = |
2380 | (snd_soc_read(codec, reg) >> shift) & mask; | 2398 | (snd_soc_read(codec, reg) >> shift) & mask; |
2381 | ucontrol->value.integer.value[1] = | 2399 | ucontrol->value.integer.value[1] = |
2382 | (snd_soc_read(codec, reg2) >> shift) & mask; | 2400 | (snd_soc_read(codec, reg2) >> shift) & mask; |
2383 | if (invert) { | 2401 | if (invert) { |
2384 | ucontrol->value.integer.value[0] = | 2402 | ucontrol->value.integer.value[0] = |
2385 | max - ucontrol->value.integer.value[0]; | 2403 | max - ucontrol->value.integer.value[0]; |
2386 | ucontrol->value.integer.value[1] = | 2404 | ucontrol->value.integer.value[1] = |
2387 | max - ucontrol->value.integer.value[1]; | 2405 | max - ucontrol->value.integer.value[1]; |
2388 | } | 2406 | } |
2389 | 2407 | ||
2390 | return 0; | 2408 | return 0; |
2391 | } | 2409 | } |
2392 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); | 2410 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); |
2393 | 2411 | ||
2394 | /** | 2412 | /** |
2395 | * snd_soc_put_volsw_2r - double mixer set callback | 2413 | * snd_soc_put_volsw_2r - double mixer set callback |
2396 | * @kcontrol: mixer control | 2414 | * @kcontrol: mixer control |
2397 | * @ucontrol: control element information | 2415 | * @ucontrol: control element information |
2398 | * | 2416 | * |
2399 | * Callback to set the value of a double mixer control that spans 2 registers. | 2417 | * Callback to set the value of a double mixer control that spans 2 registers. |
2400 | * | 2418 | * |
2401 | * Returns 0 for success. | 2419 | * Returns 0 for success. |
2402 | */ | 2420 | */ |
2403 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | 2421 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, |
2404 | struct snd_ctl_elem_value *ucontrol) | 2422 | struct snd_ctl_elem_value *ucontrol) |
2405 | { | 2423 | { |
2406 | struct soc_mixer_control *mc = | 2424 | struct soc_mixer_control *mc = |
2407 | (struct soc_mixer_control *)kcontrol->private_value; | 2425 | (struct soc_mixer_control *)kcontrol->private_value; |
2408 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2426 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2409 | unsigned int reg = mc->reg; | 2427 | unsigned int reg = mc->reg; |
2410 | unsigned int reg2 = mc->rreg; | 2428 | unsigned int reg2 = mc->rreg; |
2411 | unsigned int shift = mc->shift; | 2429 | unsigned int shift = mc->shift; |
2412 | int max = mc->max; | 2430 | int max = mc->max; |
2413 | unsigned int mask = (1 << fls(max)) - 1; | 2431 | unsigned int mask = (1 << fls(max)) - 1; |
2414 | unsigned int invert = mc->invert; | 2432 | unsigned int invert = mc->invert; |
2415 | int err; | 2433 | int err; |
2416 | unsigned int val, val2, val_mask; | 2434 | unsigned int val, val2, val_mask; |
2417 | 2435 | ||
2418 | val_mask = mask << shift; | 2436 | val_mask = mask << shift; |
2419 | val = (ucontrol->value.integer.value[0] & mask); | 2437 | val = (ucontrol->value.integer.value[0] & mask); |
2420 | val2 = (ucontrol->value.integer.value[1] & mask); | 2438 | val2 = (ucontrol->value.integer.value[1] & mask); |
2421 | 2439 | ||
2422 | if (invert) { | 2440 | if (invert) { |
2423 | val = max - val; | 2441 | val = max - val; |
2424 | val2 = max - val2; | 2442 | val2 = max - val2; |
2425 | } | 2443 | } |
2426 | 2444 | ||
2427 | val = val << shift; | 2445 | val = val << shift; |
2428 | val2 = val2 << shift; | 2446 | val2 = val2 << shift; |
2429 | 2447 | ||
2430 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); | 2448 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); |
2431 | if (err < 0) | 2449 | if (err < 0) |
2432 | return err; | 2450 | return err; |
2433 | 2451 | ||
2434 | err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2); | 2452 | err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2); |
2435 | return err; | 2453 | return err; |
2436 | } | 2454 | } |
2437 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); | 2455 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); |
2438 | 2456 | ||
2439 | /** | 2457 | /** |
2440 | * snd_soc_info_volsw_s8 - signed mixer info callback | 2458 | * snd_soc_info_volsw_s8 - signed mixer info callback |
2441 | * @kcontrol: mixer control | 2459 | * @kcontrol: mixer control |
2442 | * @uinfo: control element information | 2460 | * @uinfo: control element information |
2443 | * | 2461 | * |
2444 | * Callback to provide information about a signed mixer control. | 2462 | * Callback to provide information about a signed mixer control. |
2445 | * | 2463 | * |
2446 | * Returns 0 for success. | 2464 | * Returns 0 for success. |
2447 | */ | 2465 | */ |
2448 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | 2466 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, |
2449 | struct snd_ctl_elem_info *uinfo) | 2467 | struct snd_ctl_elem_info *uinfo) |
2450 | { | 2468 | { |
2451 | struct soc_mixer_control *mc = | 2469 | struct soc_mixer_control *mc = |
2452 | (struct soc_mixer_control *)kcontrol->private_value; | 2470 | (struct soc_mixer_control *)kcontrol->private_value; |
2453 | int platform_max; | 2471 | int platform_max; |
2454 | int min = mc->min; | 2472 | int min = mc->min; |
2455 | 2473 | ||
2456 | if (!mc->platform_max) | 2474 | if (!mc->platform_max) |
2457 | mc->platform_max = mc->max; | 2475 | mc->platform_max = mc->max; |
2458 | platform_max = mc->platform_max; | 2476 | platform_max = mc->platform_max; |
2459 | 2477 | ||
2460 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2478 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2461 | uinfo->count = 2; | 2479 | uinfo->count = 2; |
2462 | uinfo->value.integer.min = 0; | 2480 | uinfo->value.integer.min = 0; |
2463 | uinfo->value.integer.max = platform_max - min; | 2481 | uinfo->value.integer.max = platform_max - min; |
2464 | return 0; | 2482 | return 0; |
2465 | } | 2483 | } |
2466 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | 2484 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); |
2467 | 2485 | ||
2468 | /** | 2486 | /** |
2469 | * snd_soc_get_volsw_s8 - signed mixer get callback | 2487 | * snd_soc_get_volsw_s8 - signed mixer get callback |
2470 | * @kcontrol: mixer control | 2488 | * @kcontrol: mixer control |
2471 | * @ucontrol: control element information | 2489 | * @ucontrol: control element information |
2472 | * | 2490 | * |
2473 | * Callback to get the value of a signed mixer control. | 2491 | * Callback to get the value of a signed mixer control. |
2474 | * | 2492 | * |
2475 | * Returns 0 for success. | 2493 | * Returns 0 for success. |
2476 | */ | 2494 | */ |
2477 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | 2495 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, |
2478 | struct snd_ctl_elem_value *ucontrol) | 2496 | struct snd_ctl_elem_value *ucontrol) |
2479 | { | 2497 | { |
2480 | struct soc_mixer_control *mc = | 2498 | struct soc_mixer_control *mc = |
2481 | (struct soc_mixer_control *)kcontrol->private_value; | 2499 | (struct soc_mixer_control *)kcontrol->private_value; |
2482 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2500 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2483 | unsigned int reg = mc->reg; | 2501 | unsigned int reg = mc->reg; |
2484 | int min = mc->min; | 2502 | int min = mc->min; |
2485 | int val = snd_soc_read(codec, reg); | 2503 | int val = snd_soc_read(codec, reg); |
2486 | 2504 | ||
2487 | ucontrol->value.integer.value[0] = | 2505 | ucontrol->value.integer.value[0] = |
2488 | ((signed char)(val & 0xff))-min; | 2506 | ((signed char)(val & 0xff))-min; |
2489 | ucontrol->value.integer.value[1] = | 2507 | ucontrol->value.integer.value[1] = |
2490 | ((signed char)((val >> 8) & 0xff))-min; | 2508 | ((signed char)((val >> 8) & 0xff))-min; |
2491 | return 0; | 2509 | return 0; |
2492 | } | 2510 | } |
2493 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | 2511 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); |
2494 | 2512 | ||
2495 | /** | 2513 | /** |
2496 | * snd_soc_put_volsw_sgn - signed mixer put callback | 2514 | * snd_soc_put_volsw_sgn - signed mixer put callback |
2497 | * @kcontrol: mixer control | 2515 | * @kcontrol: mixer control |
2498 | * @ucontrol: control element information | 2516 | * @ucontrol: control element information |
2499 | * | 2517 | * |
2500 | * Callback to set the value of a signed mixer control. | 2518 | * Callback to set the value of a signed mixer control. |
2501 | * | 2519 | * |
2502 | * Returns 0 for success. | 2520 | * Returns 0 for success. |
2503 | */ | 2521 | */ |
2504 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | 2522 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, |
2505 | struct snd_ctl_elem_value *ucontrol) | 2523 | struct snd_ctl_elem_value *ucontrol) |
2506 | { | 2524 | { |
2507 | struct soc_mixer_control *mc = | 2525 | struct soc_mixer_control *mc = |
2508 | (struct soc_mixer_control *)kcontrol->private_value; | 2526 | (struct soc_mixer_control *)kcontrol->private_value; |
2509 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2527 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2510 | unsigned int reg = mc->reg; | 2528 | unsigned int reg = mc->reg; |
2511 | int min = mc->min; | 2529 | int min = mc->min; |
2512 | unsigned int val; | 2530 | unsigned int val; |
2513 | 2531 | ||
2514 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | 2532 | val = (ucontrol->value.integer.value[0]+min) & 0xff; |
2515 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | 2533 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; |
2516 | 2534 | ||
2517 | return snd_soc_update_bits_locked(codec, reg, 0xffff, val); | 2535 | return snd_soc_update_bits_locked(codec, reg, 0xffff, val); |
2518 | } | 2536 | } |
2519 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | 2537 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); |
2520 | 2538 | ||
2521 | /** | 2539 | /** |
2522 | * snd_soc_limit_volume - Set new limit to an existing volume control. | 2540 | * snd_soc_limit_volume - Set new limit to an existing volume control. |
2523 | * | 2541 | * |
2524 | * @codec: where to look for the control | 2542 | * @codec: where to look for the control |
2525 | * @name: Name of the control | 2543 | * @name: Name of the control |
2526 | * @max: new maximum limit | 2544 | * @max: new maximum limit |
2527 | * | 2545 | * |
2528 | * Return 0 for success, else error. | 2546 | * Return 0 for success, else error. |
2529 | */ | 2547 | */ |
2530 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | 2548 | int snd_soc_limit_volume(struct snd_soc_codec *codec, |
2531 | const char *name, int max) | 2549 | const char *name, int max) |
2532 | { | 2550 | { |
2533 | struct snd_card *card = codec->card->snd_card; | 2551 | struct snd_card *card = codec->card->snd_card; |
2534 | struct snd_kcontrol *kctl; | 2552 | struct snd_kcontrol *kctl; |
2535 | struct soc_mixer_control *mc; | 2553 | struct soc_mixer_control *mc; |
2536 | int found = 0; | 2554 | int found = 0; |
2537 | int ret = -EINVAL; | 2555 | int ret = -EINVAL; |
2538 | 2556 | ||
2539 | /* Sanity check for name and max */ | 2557 | /* Sanity check for name and max */ |
2540 | if (unlikely(!name || max <= 0)) | 2558 | if (unlikely(!name || max <= 0)) |
2541 | return -EINVAL; | 2559 | return -EINVAL; |
2542 | 2560 | ||
2543 | list_for_each_entry(kctl, &card->controls, list) { | 2561 | list_for_each_entry(kctl, &card->controls, list) { |
2544 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | 2562 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { |
2545 | found = 1; | 2563 | found = 1; |
2546 | break; | 2564 | break; |
2547 | } | 2565 | } |
2548 | } | 2566 | } |
2549 | if (found) { | 2567 | if (found) { |
2550 | mc = (struct soc_mixer_control *)kctl->private_value; | 2568 | mc = (struct soc_mixer_control *)kctl->private_value; |
2551 | if (max <= mc->max) { | 2569 | if (max <= mc->max) { |
2552 | mc->platform_max = max; | 2570 | mc->platform_max = max; |
2553 | ret = 0; | 2571 | ret = 0; |
2554 | } | 2572 | } |
2555 | } | 2573 | } |
2556 | return ret; | 2574 | return ret; |
2557 | } | 2575 | } |
2558 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | 2576 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); |
2559 | 2577 | ||
2560 | /** | 2578 | /** |
2561 | * snd_soc_info_volsw_2r_sx - double with tlv and variable data size | 2579 | * snd_soc_info_volsw_2r_sx - double with tlv and variable data size |
2562 | * mixer info callback | 2580 | * mixer info callback |
2563 | * @kcontrol: mixer control | 2581 | * @kcontrol: mixer control |
2564 | * @uinfo: control element information | 2582 | * @uinfo: control element information |
2565 | * | 2583 | * |
2566 | * Returns 0 for success. | 2584 | * Returns 0 for success. |
2567 | */ | 2585 | */ |
2568 | int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, | 2586 | int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, |
2569 | struct snd_ctl_elem_info *uinfo) | 2587 | struct snd_ctl_elem_info *uinfo) |
2570 | { | 2588 | { |
2571 | struct soc_mixer_control *mc = | 2589 | struct soc_mixer_control *mc = |
2572 | (struct soc_mixer_control *)kcontrol->private_value; | 2590 | (struct soc_mixer_control *)kcontrol->private_value; |
2573 | int max = mc->max; | 2591 | int max = mc->max; |
2574 | int min = mc->min; | 2592 | int min = mc->min; |
2575 | 2593 | ||
2576 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2594 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2577 | uinfo->count = 2; | 2595 | uinfo->count = 2; |
2578 | uinfo->value.integer.min = 0; | 2596 | uinfo->value.integer.min = 0; |
2579 | uinfo->value.integer.max = max-min; | 2597 | uinfo->value.integer.max = max-min; |
2580 | 2598 | ||
2581 | return 0; | 2599 | return 0; |
2582 | } | 2600 | } |
2583 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx); | 2601 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx); |
2584 | 2602 | ||
2585 | /** | 2603 | /** |
2586 | * snd_soc_get_volsw_2r_sx - double with tlv and variable data size | 2604 | * snd_soc_get_volsw_2r_sx - double with tlv and variable data size |
2587 | * mixer get callback | 2605 | * mixer get callback |
2588 | * @kcontrol: mixer control | 2606 | * @kcontrol: mixer control |
2589 | * @uinfo: control element information | 2607 | * @uinfo: control element information |
2590 | * | 2608 | * |
2591 | * Returns 0 for success. | 2609 | * Returns 0 for success. |
2592 | */ | 2610 | */ |
2593 | int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, | 2611 | int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, |
2594 | struct snd_ctl_elem_value *ucontrol) | 2612 | struct snd_ctl_elem_value *ucontrol) |
2595 | { | 2613 | { |
2596 | struct soc_mixer_control *mc = | 2614 | struct soc_mixer_control *mc = |
2597 | (struct soc_mixer_control *)kcontrol->private_value; | 2615 | (struct soc_mixer_control *)kcontrol->private_value; |
2598 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2616 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2599 | unsigned int mask = (1<<mc->shift)-1; | 2617 | unsigned int mask = (1<<mc->shift)-1; |
2600 | int min = mc->min; | 2618 | int min = mc->min; |
2601 | int val = snd_soc_read(codec, mc->reg) & mask; | 2619 | int val = snd_soc_read(codec, mc->reg) & mask; |
2602 | int valr = snd_soc_read(codec, mc->rreg) & mask; | 2620 | int valr = snd_soc_read(codec, mc->rreg) & mask; |
2603 | 2621 | ||
2604 | ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask; | 2622 | ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask; |
2605 | ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask; | 2623 | ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask; |
2606 | return 0; | 2624 | return 0; |
2607 | } | 2625 | } |
2608 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx); | 2626 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx); |
2609 | 2627 | ||
2610 | /** | 2628 | /** |
2611 | * snd_soc_put_volsw_2r_sx - double with tlv and variable data size | 2629 | * snd_soc_put_volsw_2r_sx - double with tlv and variable data size |
2612 | * mixer put callback | 2630 | * mixer put callback |
2613 | * @kcontrol: mixer control | 2631 | * @kcontrol: mixer control |
2614 | * @uinfo: control element information | 2632 | * @uinfo: control element information |
2615 | * | 2633 | * |
2616 | * Returns 0 for success. | 2634 | * Returns 0 for success. |
2617 | */ | 2635 | */ |
2618 | int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, | 2636 | int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, |
2619 | struct snd_ctl_elem_value *ucontrol) | 2637 | struct snd_ctl_elem_value *ucontrol) |
2620 | { | 2638 | { |
2621 | struct soc_mixer_control *mc = | 2639 | struct soc_mixer_control *mc = |
2622 | (struct soc_mixer_control *)kcontrol->private_value; | 2640 | (struct soc_mixer_control *)kcontrol->private_value; |
2623 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2641 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2624 | unsigned int mask = (1<<mc->shift)-1; | 2642 | unsigned int mask = (1<<mc->shift)-1; |
2625 | int min = mc->min; | 2643 | int min = mc->min; |
2626 | int ret; | 2644 | int ret; |
2627 | unsigned int val, valr, oval, ovalr; | 2645 | unsigned int val, valr, oval, ovalr; |
2628 | 2646 | ||
2629 | val = ((ucontrol->value.integer.value[0]+min) & 0xff); | 2647 | val = ((ucontrol->value.integer.value[0]+min) & 0xff); |
2630 | val &= mask; | 2648 | val &= mask; |
2631 | valr = ((ucontrol->value.integer.value[1]+min) & 0xff); | 2649 | valr = ((ucontrol->value.integer.value[1]+min) & 0xff); |
2632 | valr &= mask; | 2650 | valr &= mask; |
2633 | 2651 | ||
2634 | oval = snd_soc_read(codec, mc->reg) & mask; | 2652 | oval = snd_soc_read(codec, mc->reg) & mask; |
2635 | ovalr = snd_soc_read(codec, mc->rreg) & mask; | 2653 | ovalr = snd_soc_read(codec, mc->rreg) & mask; |
2636 | 2654 | ||
2637 | ret = 0; | 2655 | ret = 0; |
2638 | if (oval != val) { | 2656 | if (oval != val) { |
2639 | ret = snd_soc_write(codec, mc->reg, val); | 2657 | ret = snd_soc_write(codec, mc->reg, val); |
2640 | if (ret < 0) | 2658 | if (ret < 0) |
2641 | return ret; | 2659 | return ret; |
2642 | } | 2660 | } |
2643 | if (ovalr != valr) { | 2661 | if (ovalr != valr) { |
2644 | ret = snd_soc_write(codec, mc->rreg, valr); | 2662 | ret = snd_soc_write(codec, mc->rreg, valr); |
2645 | if (ret < 0) | 2663 | if (ret < 0) |
2646 | return ret; | 2664 | return ret; |
2647 | } | 2665 | } |
2648 | 2666 | ||
2649 | return 0; | 2667 | return 0; |
2650 | } | 2668 | } |
2651 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); | 2669 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); |
2652 | 2670 | ||
2653 | /** | 2671 | /** |
2654 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | 2672 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. |
2655 | * @dai: DAI | 2673 | * @dai: DAI |
2656 | * @clk_id: DAI specific clock ID | 2674 | * @clk_id: DAI specific clock ID |
2657 | * @freq: new clock frequency in Hz | 2675 | * @freq: new clock frequency in Hz |
2658 | * @dir: new clock direction - input/output. | 2676 | * @dir: new clock direction - input/output. |
2659 | * | 2677 | * |
2660 | * Configures the DAI master (MCLK) or system (SYSCLK) clocking. | 2678 | * Configures the DAI master (MCLK) or system (SYSCLK) clocking. |
2661 | */ | 2679 | */ |
2662 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 2680 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
2663 | unsigned int freq, int dir) | 2681 | unsigned int freq, int dir) |
2664 | { | 2682 | { |
2665 | if (dai->driver && dai->driver->ops->set_sysclk) | 2683 | if (dai->driver && dai->driver->ops->set_sysclk) |
2666 | return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); | 2684 | return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); |
2667 | else | 2685 | else |
2668 | return -EINVAL; | 2686 | return -EINVAL; |
2669 | } | 2687 | } |
2670 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); | 2688 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); |
2671 | 2689 | ||
2672 | /** | 2690 | /** |
2673 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. | 2691 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. |
2674 | * @dai: DAI | 2692 | * @dai: DAI |
2675 | * @div_id: DAI specific clock divider ID | 2693 | * @div_id: DAI specific clock divider ID |
2676 | * @div: new clock divisor. | 2694 | * @div: new clock divisor. |
2677 | * | 2695 | * |
2678 | * Configures the clock dividers. This is used to derive the best DAI bit and | 2696 | * Configures the clock dividers. This is used to derive the best DAI bit and |
2679 | * frame clocks from the system or master clock. It's best to set the DAI bit | 2697 | * frame clocks from the system or master clock. It's best to set the DAI bit |
2680 | * and frame clocks as low as possible to save system power. | 2698 | * and frame clocks as low as possible to save system power. |
2681 | */ | 2699 | */ |
2682 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | 2700 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, |
2683 | int div_id, int div) | 2701 | int div_id, int div) |
2684 | { | 2702 | { |
2685 | if (dai->driver && dai->driver->ops->set_clkdiv) | 2703 | if (dai->driver && dai->driver->ops->set_clkdiv) |
2686 | return dai->driver->ops->set_clkdiv(dai, div_id, div); | 2704 | return dai->driver->ops->set_clkdiv(dai, div_id, div); |
2687 | else | 2705 | else |
2688 | return -EINVAL; | 2706 | return -EINVAL; |
2689 | } | 2707 | } |
2690 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | 2708 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); |
2691 | 2709 | ||
2692 | /** | 2710 | /** |
2693 | * snd_soc_dai_set_pll - configure DAI PLL. | 2711 | * snd_soc_dai_set_pll - configure DAI PLL. |
2694 | * @dai: DAI | 2712 | * @dai: DAI |
2695 | * @pll_id: DAI specific PLL ID | 2713 | * @pll_id: DAI specific PLL ID |
2696 | * @source: DAI specific source for the PLL | 2714 | * @source: DAI specific source for the PLL |
2697 | * @freq_in: PLL input clock frequency in Hz | 2715 | * @freq_in: PLL input clock frequency in Hz |
2698 | * @freq_out: requested PLL output clock frequency in Hz | 2716 | * @freq_out: requested PLL output clock frequency in Hz |
2699 | * | 2717 | * |
2700 | * Configures and enables PLL to generate output clock based on input clock. | 2718 | * Configures and enables PLL to generate output clock based on input clock. |
2701 | */ | 2719 | */ |
2702 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, | 2720 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, |
2703 | unsigned int freq_in, unsigned int freq_out) | 2721 | unsigned int freq_in, unsigned int freq_out) |
2704 | { | 2722 | { |
2705 | if (dai->driver && dai->driver->ops->set_pll) | 2723 | if (dai->driver && dai->driver->ops->set_pll) |
2706 | return dai->driver->ops->set_pll(dai, pll_id, source, | 2724 | return dai->driver->ops->set_pll(dai, pll_id, source, |
2707 | freq_in, freq_out); | 2725 | freq_in, freq_out); |
2708 | else | 2726 | else |
2709 | return -EINVAL; | 2727 | return -EINVAL; |
2710 | } | 2728 | } |
2711 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); | 2729 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); |
2712 | 2730 | ||
2713 | /** | 2731 | /** |
2714 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. | 2732 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. |
2715 | * @dai: DAI | 2733 | * @dai: DAI |
2716 | * @fmt: SND_SOC_DAIFMT_ format value. | 2734 | * @fmt: SND_SOC_DAIFMT_ format value. |
2717 | * | 2735 | * |
2718 | * Configures the DAI hardware format and clocking. | 2736 | * Configures the DAI hardware format and clocking. |
2719 | */ | 2737 | */ |
2720 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 2738 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
2721 | { | 2739 | { |
2722 | if (dai->driver && dai->driver->ops->set_fmt) | 2740 | if (dai->driver && dai->driver->ops->set_fmt) |
2723 | return dai->driver->ops->set_fmt(dai, fmt); | 2741 | return dai->driver->ops->set_fmt(dai, fmt); |
2724 | else | 2742 | else |
2725 | return -EINVAL; | 2743 | return -EINVAL; |
2726 | } | 2744 | } |
2727 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | 2745 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); |
2728 | 2746 | ||
2729 | /** | 2747 | /** |
2730 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. | 2748 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. |
2731 | * @dai: DAI | 2749 | * @dai: DAI |
2732 | * @tx_mask: bitmask representing active TX slots. | 2750 | * @tx_mask: bitmask representing active TX slots. |
2733 | * @rx_mask: bitmask representing active RX slots. | 2751 | * @rx_mask: bitmask representing active RX slots. |
2734 | * @slots: Number of slots in use. | 2752 | * @slots: Number of slots in use. |
2735 | * @slot_width: Width in bits for each slot. | 2753 | * @slot_width: Width in bits for each slot. |
2736 | * | 2754 | * |
2737 | * Configures a DAI for TDM operation. Both mask and slots are codec and DAI | 2755 | * Configures a DAI for TDM operation. Both mask and slots are codec and DAI |
2738 | * specific. | 2756 | * specific. |
2739 | */ | 2757 | */ |
2740 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | 2758 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, |
2741 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) | 2759 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) |
2742 | { | 2760 | { |
2743 | if (dai->driver && dai->driver->ops->set_tdm_slot) | 2761 | if (dai->driver && dai->driver->ops->set_tdm_slot) |
2744 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, | 2762 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
2745 | slots, slot_width); | 2763 | slots, slot_width); |
2746 | else | 2764 | else |
2747 | return -EINVAL; | 2765 | return -EINVAL; |
2748 | } | 2766 | } |
2749 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | 2767 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); |
2750 | 2768 | ||
2751 | /** | 2769 | /** |
2752 | * snd_soc_dai_set_channel_map - configure DAI audio channel map | 2770 | * snd_soc_dai_set_channel_map - configure DAI audio channel map |
2753 | * @dai: DAI | 2771 | * @dai: DAI |
2754 | * @tx_num: how many TX channels | 2772 | * @tx_num: how many TX channels |
2755 | * @tx_slot: pointer to an array which imply the TX slot number channel | 2773 | * @tx_slot: pointer to an array which imply the TX slot number channel |
2756 | * 0~num-1 uses | 2774 | * 0~num-1 uses |
2757 | * @rx_num: how many RX channels | 2775 | * @rx_num: how many RX channels |
2758 | * @rx_slot: pointer to an array which imply the RX slot number channel | 2776 | * @rx_slot: pointer to an array which imply the RX slot number channel |
2759 | * 0~num-1 uses | 2777 | * 0~num-1 uses |
2760 | * | 2778 | * |
2761 | * configure the relationship between channel number and TDM slot number. | 2779 | * configure the relationship between channel number and TDM slot number. |
2762 | */ | 2780 | */ |
2763 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, | 2781 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, |
2764 | unsigned int tx_num, unsigned int *tx_slot, | 2782 | unsigned int tx_num, unsigned int *tx_slot, |
2765 | unsigned int rx_num, unsigned int *rx_slot) | 2783 | unsigned int rx_num, unsigned int *rx_slot) |
2766 | { | 2784 | { |
2767 | if (dai->driver && dai->driver->ops->set_channel_map) | 2785 | if (dai->driver && dai->driver->ops->set_channel_map) |
2768 | return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, | 2786 | return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, |
2769 | rx_num, rx_slot); | 2787 | rx_num, rx_slot); |
2770 | else | 2788 | else |
2771 | return -EINVAL; | 2789 | return -EINVAL; |
2772 | } | 2790 | } |
2773 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); | 2791 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); |
2774 | 2792 | ||
2775 | /** | 2793 | /** |
2776 | * snd_soc_dai_set_tristate - configure DAI system or master clock. | 2794 | * snd_soc_dai_set_tristate - configure DAI system or master clock. |
2777 | * @dai: DAI | 2795 | * @dai: DAI |
2778 | * @tristate: tristate enable | 2796 | * @tristate: tristate enable |
2779 | * | 2797 | * |
2780 | * Tristates the DAI so that others can use it. | 2798 | * Tristates the DAI so that others can use it. |
2781 | */ | 2799 | */ |
2782 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) | 2800 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) |
2783 | { | 2801 | { |
2784 | if (dai->driver && dai->driver->ops->set_tristate) | 2802 | if (dai->driver && dai->driver->ops->set_tristate) |
2785 | return dai->driver->ops->set_tristate(dai, tristate); | 2803 | return dai->driver->ops->set_tristate(dai, tristate); |
2786 | else | 2804 | else |
2787 | return -EINVAL; | 2805 | return -EINVAL; |
2788 | } | 2806 | } |
2789 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); | 2807 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); |
2790 | 2808 | ||
2791 | /** | 2809 | /** |
2792 | * snd_soc_dai_digital_mute - configure DAI system or master clock. | 2810 | * snd_soc_dai_digital_mute - configure DAI system or master clock. |
2793 | * @dai: DAI | 2811 | * @dai: DAI |
2794 | * @mute: mute enable | 2812 | * @mute: mute enable |
2795 | * | 2813 | * |
2796 | * Mutes the DAI DAC. | 2814 | * Mutes the DAI DAC. |
2797 | */ | 2815 | */ |
2798 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) | 2816 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) |
2799 | { | 2817 | { |
2800 | if (dai->driver && dai->driver->ops->digital_mute) | 2818 | if (dai->driver && dai->driver->ops->digital_mute) |
2801 | return dai->driver->ops->digital_mute(dai, mute); | 2819 | return dai->driver->ops->digital_mute(dai, mute); |
2802 | else | 2820 | else |
2803 | return -EINVAL; | 2821 | return -EINVAL; |
2804 | } | 2822 | } |
2805 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | 2823 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); |
2806 | 2824 | ||
2807 | /** | 2825 | /** |
2808 | * snd_soc_register_card - Register a card with the ASoC core | 2826 | * snd_soc_register_card - Register a card with the ASoC core |
2809 | * | 2827 | * |
2810 | * @card: Card to register | 2828 | * @card: Card to register |
2811 | * | 2829 | * |
2812 | * Note that currently this is an internal only function: it will be | 2830 | * Note that currently this is an internal only function: it will be |
2813 | * exposed to machine drivers after further backporting of ASoC v2 | 2831 | * exposed to machine drivers after further backporting of ASoC v2 |
2814 | * registration APIs. | 2832 | * registration APIs. |
2815 | */ | 2833 | */ |
2816 | static int snd_soc_register_card(struct snd_soc_card *card) | 2834 | static int snd_soc_register_card(struct snd_soc_card *card) |
2817 | { | 2835 | { |
2818 | int i; | 2836 | int i; |
2819 | 2837 | ||
2820 | if (!card->name || !card->dev) | 2838 | if (!card->name || !card->dev) |
2821 | return -EINVAL; | 2839 | return -EINVAL; |
2822 | 2840 | ||
2823 | card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links, | 2841 | card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links, |
2824 | GFP_KERNEL); | 2842 | GFP_KERNEL); |
2825 | if (card->rtd == NULL) | 2843 | if (card->rtd == NULL) |
2826 | return -ENOMEM; | 2844 | return -ENOMEM; |
2827 | 2845 | ||
2828 | for (i = 0; i < card->num_links; i++) | 2846 | for (i = 0; i < card->num_links; i++) |
2829 | card->rtd[i].dai_link = &card->dai_link[i]; | 2847 | card->rtd[i].dai_link = &card->dai_link[i]; |
2830 | 2848 | ||
2831 | INIT_LIST_HEAD(&card->list); | 2849 | INIT_LIST_HEAD(&card->list); |
2832 | card->instantiated = 0; | 2850 | card->instantiated = 0; |
2833 | mutex_init(&card->mutex); | 2851 | mutex_init(&card->mutex); |
2834 | 2852 | ||
2835 | mutex_lock(&client_mutex); | 2853 | mutex_lock(&client_mutex); |
2836 | list_add(&card->list, &card_list); | 2854 | list_add(&card->list, &card_list); |
2837 | snd_soc_instantiate_cards(); | 2855 | snd_soc_instantiate_cards(); |
2838 | mutex_unlock(&client_mutex); | 2856 | mutex_unlock(&client_mutex); |
2839 | 2857 | ||
2840 | dev_dbg(card->dev, "Registered card '%s'\n", card->name); | 2858 | dev_dbg(card->dev, "Registered card '%s'\n", card->name); |
2841 | 2859 | ||
2842 | return 0; | 2860 | return 0; |
2843 | } | 2861 | } |
2844 | 2862 | ||
2845 | /** | 2863 | /** |
2846 | * snd_soc_unregister_card - Unregister a card with the ASoC core | 2864 | * snd_soc_unregister_card - Unregister a card with the ASoC core |
2847 | * | 2865 | * |
2848 | * @card: Card to unregister | 2866 | * @card: Card to unregister |
2849 | * | 2867 | * |
2850 | * Note that currently this is an internal only function: it will be | 2868 | * Note that currently this is an internal only function: it will be |
2851 | * exposed to machine drivers after further backporting of ASoC v2 | 2869 | * exposed to machine drivers after further backporting of ASoC v2 |
2852 | * registration APIs. | 2870 | * registration APIs. |
2853 | */ | 2871 | */ |
2854 | static int snd_soc_unregister_card(struct snd_soc_card *card) | 2872 | static int snd_soc_unregister_card(struct snd_soc_card *card) |
2855 | { | 2873 | { |
2856 | mutex_lock(&client_mutex); | 2874 | mutex_lock(&client_mutex); |
2857 | list_del(&card->list); | 2875 | list_del(&card->list); |
2858 | mutex_unlock(&client_mutex); | 2876 | mutex_unlock(&client_mutex); |
2859 | dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); | 2877 | dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); |
2860 | 2878 | ||
2861 | return 0; | 2879 | return 0; |
2862 | } | 2880 | } |
2863 | 2881 | ||
2864 | /* | 2882 | /* |
2865 | * Simplify DAI link configuration by removing ".-1" from device names | 2883 | * Simplify DAI link configuration by removing ".-1" from device names |
2866 | * and sanitizing names. | 2884 | * and sanitizing names. |
2867 | */ | 2885 | */ |
2868 | static inline char *fmt_single_name(struct device *dev, int *id) | 2886 | static inline char *fmt_single_name(struct device *dev, int *id) |
2869 | { | 2887 | { |
2870 | char *found, name[NAME_SIZE]; | 2888 | char *found, name[NAME_SIZE]; |
2871 | int id1, id2; | 2889 | int id1, id2; |
2872 | 2890 | ||
2873 | if (dev_name(dev) == NULL) | 2891 | if (dev_name(dev) == NULL) |
2874 | return NULL; | 2892 | return NULL; |
2875 | 2893 | ||
2876 | strncpy(name, dev_name(dev), NAME_SIZE); | 2894 | strncpy(name, dev_name(dev), NAME_SIZE); |
2877 | 2895 | ||
2878 | /* are we a "%s.%d" name (platform and SPI components) */ | 2896 | /* are we a "%s.%d" name (platform and SPI components) */ |
2879 | found = strstr(name, dev->driver->name); | 2897 | found = strstr(name, dev->driver->name); |
2880 | if (found) { | 2898 | if (found) { |
2881 | /* get ID */ | 2899 | /* get ID */ |
2882 | if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { | 2900 | if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { |
2883 | 2901 | ||
2884 | /* discard ID from name if ID == -1 */ | 2902 | /* discard ID from name if ID == -1 */ |
2885 | if (*id == -1) | 2903 | if (*id == -1) |
2886 | found[strlen(dev->driver->name)] = '\0'; | 2904 | found[strlen(dev->driver->name)] = '\0'; |
2887 | } | 2905 | } |
2888 | 2906 | ||
2889 | } else { | 2907 | } else { |
2890 | /* I2C component devices are named "bus-addr" */ | 2908 | /* I2C component devices are named "bus-addr" */ |
2891 | if (sscanf(name, "%x-%x", &id1, &id2) == 2) { | 2909 | if (sscanf(name, "%x-%x", &id1, &id2) == 2) { |
2892 | char tmp[NAME_SIZE]; | 2910 | char tmp[NAME_SIZE]; |
2893 | 2911 | ||
2894 | /* create unique ID number from I2C addr and bus */ | 2912 | /* create unique ID number from I2C addr and bus */ |
2895 | *id = ((id1 && 0xffff) << 16) + id2; | 2913 | *id = ((id1 && 0xffff) << 16) + id2; |
2896 | 2914 | ||
2897 | /* sanitize component name for DAI link creation */ | 2915 | /* sanitize component name for DAI link creation */ |
2898 | snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name); | 2916 | snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name); |
2899 | strncpy(name, tmp, NAME_SIZE); | 2917 | strncpy(name, tmp, NAME_SIZE); |
2900 | } else | 2918 | } else |
2901 | *id = 0; | 2919 | *id = 0; |
2902 | } | 2920 | } |
2903 | 2921 | ||
2904 | return kstrdup(name, GFP_KERNEL); | 2922 | return kstrdup(name, GFP_KERNEL); |
2905 | } | 2923 | } |
2906 | 2924 | ||
2907 | /* | 2925 | /* |
2908 | * Simplify DAI link naming for single devices with multiple DAIs by removing | 2926 | * Simplify DAI link naming for single devices with multiple DAIs by removing |
2909 | * any ".-1" and using the DAI name (instead of device name). | 2927 | * any ".-1" and using the DAI name (instead of device name). |
2910 | */ | 2928 | */ |
2911 | static inline char *fmt_multiple_name(struct device *dev, | 2929 | static inline char *fmt_multiple_name(struct device *dev, |
2912 | struct snd_soc_dai_driver *dai_drv) | 2930 | struct snd_soc_dai_driver *dai_drv) |
2913 | { | 2931 | { |
2914 | if (dai_drv->name == NULL) { | 2932 | if (dai_drv->name == NULL) { |
2915 | printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n", | 2933 | printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n", |
2916 | dev_name(dev)); | 2934 | dev_name(dev)); |
2917 | return NULL; | 2935 | return NULL; |
2918 | } | 2936 | } |
2919 | 2937 | ||
2920 | return kstrdup(dai_drv->name, GFP_KERNEL); | 2938 | return kstrdup(dai_drv->name, GFP_KERNEL); |
2921 | } | 2939 | } |
2922 | 2940 | ||
2923 | /** | 2941 | /** |
2924 | * snd_soc_register_dai - Register a DAI with the ASoC core | 2942 | * snd_soc_register_dai - Register a DAI with the ASoC core |
2925 | * | 2943 | * |
2926 | * @dai: DAI to register | 2944 | * @dai: DAI to register |
2927 | */ | 2945 | */ |
2928 | int snd_soc_register_dai(struct device *dev, | 2946 | int snd_soc_register_dai(struct device *dev, |
2929 | struct snd_soc_dai_driver *dai_drv) | 2947 | struct snd_soc_dai_driver *dai_drv) |
2930 | { | 2948 | { |
2931 | struct snd_soc_dai *dai; | 2949 | struct snd_soc_dai *dai; |
2932 | 2950 | ||
2933 | dev_dbg(dev, "dai register %s\n", dev_name(dev)); | 2951 | dev_dbg(dev, "dai register %s\n", dev_name(dev)); |
2934 | 2952 | ||
2935 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | 2953 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); |
2936 | if (dai == NULL) | 2954 | if (dai == NULL) |
2937 | return -ENOMEM; | 2955 | return -ENOMEM; |
2938 | 2956 | ||
2939 | /* create DAI component name */ | 2957 | /* create DAI component name */ |
2940 | dai->name = fmt_single_name(dev, &dai->id); | 2958 | dai->name = fmt_single_name(dev, &dai->id); |
2941 | if (dai->name == NULL) { | 2959 | if (dai->name == NULL) { |
2942 | kfree(dai); | 2960 | kfree(dai); |
2943 | return -ENOMEM; | 2961 | return -ENOMEM; |
2944 | } | 2962 | } |
2945 | 2963 | ||
2946 | dai->dev = dev; | 2964 | dai->dev = dev; |
2947 | dai->driver = dai_drv; | 2965 | dai->driver = dai_drv; |
2948 | if (!dai->driver->ops) | 2966 | if (!dai->driver->ops) |
2949 | dai->driver->ops = &null_dai_ops; | 2967 | dai->driver->ops = &null_dai_ops; |
2950 | 2968 | ||
2951 | mutex_lock(&client_mutex); | 2969 | mutex_lock(&client_mutex); |
2952 | list_add(&dai->list, &dai_list); | 2970 | list_add(&dai->list, &dai_list); |
2953 | snd_soc_instantiate_cards(); | 2971 | snd_soc_instantiate_cards(); |
2954 | mutex_unlock(&client_mutex); | 2972 | mutex_unlock(&client_mutex); |
2955 | 2973 | ||
2956 | pr_debug("Registered DAI '%s'\n", dai->name); | 2974 | pr_debug("Registered DAI '%s'\n", dai->name); |
2957 | 2975 | ||
2958 | return 0; | 2976 | return 0; |
2959 | } | 2977 | } |
2960 | EXPORT_SYMBOL_GPL(snd_soc_register_dai); | 2978 | EXPORT_SYMBOL_GPL(snd_soc_register_dai); |
2961 | 2979 | ||
2962 | /** | 2980 | /** |
2963 | * snd_soc_unregister_dai - Unregister a DAI from the ASoC core | 2981 | * snd_soc_unregister_dai - Unregister a DAI from the ASoC core |
2964 | * | 2982 | * |
2965 | * @dai: DAI to unregister | 2983 | * @dai: DAI to unregister |
2966 | */ | 2984 | */ |
2967 | void snd_soc_unregister_dai(struct device *dev) | 2985 | void snd_soc_unregister_dai(struct device *dev) |
2968 | { | 2986 | { |
2969 | struct snd_soc_dai *dai; | 2987 | struct snd_soc_dai *dai; |
2970 | 2988 | ||
2971 | list_for_each_entry(dai, &dai_list, list) { | 2989 | list_for_each_entry(dai, &dai_list, list) { |
2972 | if (dev == dai->dev) | 2990 | if (dev == dai->dev) |
2973 | goto found; | 2991 | goto found; |
2974 | } | 2992 | } |
2975 | return; | 2993 | return; |
2976 | 2994 | ||
2977 | found: | 2995 | found: |
2978 | mutex_lock(&client_mutex); | 2996 | mutex_lock(&client_mutex); |
2979 | list_del(&dai->list); | 2997 | list_del(&dai->list); |
2980 | mutex_unlock(&client_mutex); | 2998 | mutex_unlock(&client_mutex); |
2981 | 2999 | ||
2982 | pr_debug("Unregistered DAI '%s'\n", dai->name); | 3000 | pr_debug("Unregistered DAI '%s'\n", dai->name); |
2983 | kfree(dai->name); | 3001 | kfree(dai->name); |
2984 | kfree(dai); | 3002 | kfree(dai); |
2985 | } | 3003 | } |
2986 | EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); | 3004 | EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); |
2987 | 3005 | ||
2988 | /** | 3006 | /** |
2989 | * snd_soc_register_dais - Register multiple DAIs with the ASoC core | 3007 | * snd_soc_register_dais - Register multiple DAIs with the ASoC core |
2990 | * | 3008 | * |
2991 | * @dai: Array of DAIs to register | 3009 | * @dai: Array of DAIs to register |
2992 | * @count: Number of DAIs | 3010 | * @count: Number of DAIs |
2993 | */ | 3011 | */ |
2994 | int snd_soc_register_dais(struct device *dev, | 3012 | int snd_soc_register_dais(struct device *dev, |
2995 | struct snd_soc_dai_driver *dai_drv, size_t count) | 3013 | struct snd_soc_dai_driver *dai_drv, size_t count) |
2996 | { | 3014 | { |
2997 | struct snd_soc_dai *dai; | 3015 | struct snd_soc_dai *dai; |
2998 | int i, ret = 0; | 3016 | int i, ret = 0; |
2999 | 3017 | ||
3000 | dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count); | 3018 | dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count); |
3001 | 3019 | ||
3002 | for (i = 0; i < count; i++) { | 3020 | for (i = 0; i < count; i++) { |
3003 | 3021 | ||
3004 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | 3022 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); |
3005 | if (dai == NULL) | 3023 | if (dai == NULL) |
3006 | return -ENOMEM; | 3024 | return -ENOMEM; |
3007 | 3025 | ||
3008 | /* create DAI component name */ | 3026 | /* create DAI component name */ |
3009 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | 3027 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); |
3010 | if (dai->name == NULL) { | 3028 | if (dai->name == NULL) { |
3011 | kfree(dai); | 3029 | kfree(dai); |
3012 | ret = -EINVAL; | 3030 | ret = -EINVAL; |
3013 | goto err; | 3031 | goto err; |
3014 | } | 3032 | } |
3015 | 3033 | ||
3016 | dai->dev = dev; | 3034 | dai->dev = dev; |
3017 | dai->id = i; | 3035 | dai->id = i; |
3018 | dai->driver = &dai_drv[i]; | 3036 | dai->driver = &dai_drv[i]; |
3019 | if (!dai->driver->ops) | 3037 | if (!dai->driver->ops) |
3020 | dai->driver->ops = &null_dai_ops; | 3038 | dai->driver->ops = &null_dai_ops; |
3021 | 3039 | ||
3022 | mutex_lock(&client_mutex); | 3040 | mutex_lock(&client_mutex); |
3023 | list_add(&dai->list, &dai_list); | 3041 | list_add(&dai->list, &dai_list); |
3024 | mutex_unlock(&client_mutex); | 3042 | mutex_unlock(&client_mutex); |
3025 | 3043 | ||
3026 | pr_debug("Registered DAI '%s'\n", dai->name); | 3044 | pr_debug("Registered DAI '%s'\n", dai->name); |
3027 | } | 3045 | } |
3028 | 3046 | ||
3029 | snd_soc_instantiate_cards(); | 3047 | snd_soc_instantiate_cards(); |
3030 | return 0; | 3048 | return 0; |
3031 | 3049 | ||
3032 | err: | 3050 | err: |
3033 | for (i--; i >= 0; i--) | 3051 | for (i--; i >= 0; i--) |
3034 | snd_soc_unregister_dai(dev); | 3052 | snd_soc_unregister_dai(dev); |
3035 | 3053 | ||
3036 | return ret; | 3054 | return ret; |
3037 | } | 3055 | } |
3038 | EXPORT_SYMBOL_GPL(snd_soc_register_dais); | 3056 | EXPORT_SYMBOL_GPL(snd_soc_register_dais); |
3039 | 3057 | ||
3040 | /** | 3058 | /** |
3041 | * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core | 3059 | * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core |
3042 | * | 3060 | * |
3043 | * @dai: Array of DAIs to unregister | 3061 | * @dai: Array of DAIs to unregister |
3044 | * @count: Number of DAIs | 3062 | * @count: Number of DAIs |
3045 | */ | 3063 | */ |
3046 | void snd_soc_unregister_dais(struct device *dev, size_t count) | 3064 | void snd_soc_unregister_dais(struct device *dev, size_t count) |
3047 | { | 3065 | { |
3048 | int i; | 3066 | int i; |
3049 | 3067 | ||
3050 | for (i = 0; i < count; i++) | 3068 | for (i = 0; i < count; i++) |
3051 | snd_soc_unregister_dai(dev); | 3069 | snd_soc_unregister_dai(dev); |
3052 | } | 3070 | } |
3053 | EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); | 3071 | EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); |
3054 | 3072 | ||
3055 | /** | 3073 | /** |
3056 | * snd_soc_register_platform - Register a platform with the ASoC core | 3074 | * snd_soc_register_platform - Register a platform with the ASoC core |
3057 | * | 3075 | * |
3058 | * @platform: platform to register | 3076 | * @platform: platform to register |
3059 | */ | 3077 | */ |
3060 | int snd_soc_register_platform(struct device *dev, | 3078 | int snd_soc_register_platform(struct device *dev, |
3061 | struct snd_soc_platform_driver *platform_drv) | 3079 | struct snd_soc_platform_driver *platform_drv) |
3062 | { | 3080 | { |
3063 | struct snd_soc_platform *platform; | 3081 | struct snd_soc_platform *platform; |
3064 | 3082 | ||
3065 | dev_dbg(dev, "platform register %s\n", dev_name(dev)); | 3083 | dev_dbg(dev, "platform register %s\n", dev_name(dev)); |
3066 | 3084 | ||
3067 | platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); | 3085 | platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); |
3068 | if (platform == NULL) | 3086 | if (platform == NULL) |
3069 | return -ENOMEM; | 3087 | return -ENOMEM; |
3070 | 3088 | ||
3071 | /* create platform component name */ | 3089 | /* create platform component name */ |
3072 | platform->name = fmt_single_name(dev, &platform->id); | 3090 | platform->name = fmt_single_name(dev, &platform->id); |
3073 | if (platform->name == NULL) { | 3091 | if (platform->name == NULL) { |
3074 | kfree(platform); | 3092 | kfree(platform); |
3075 | return -ENOMEM; | 3093 | return -ENOMEM; |
3076 | } | 3094 | } |
3077 | 3095 | ||
3078 | platform->dev = dev; | 3096 | platform->dev = dev; |
3079 | platform->driver = platform_drv; | 3097 | platform->driver = platform_drv; |
3080 | 3098 | ||
3081 | mutex_lock(&client_mutex); | 3099 | mutex_lock(&client_mutex); |
3082 | list_add(&platform->list, &platform_list); | 3100 | list_add(&platform->list, &platform_list); |
3083 | snd_soc_instantiate_cards(); | 3101 | snd_soc_instantiate_cards(); |
3084 | mutex_unlock(&client_mutex); | 3102 | mutex_unlock(&client_mutex); |
3085 | 3103 | ||
3086 | pr_debug("Registered platform '%s'\n", platform->name); | 3104 | pr_debug("Registered platform '%s'\n", platform->name); |
3087 | 3105 | ||
3088 | return 0; | 3106 | return 0; |
3089 | } | 3107 | } |
3090 | EXPORT_SYMBOL_GPL(snd_soc_register_platform); | 3108 | EXPORT_SYMBOL_GPL(snd_soc_register_platform); |
3091 | 3109 | ||
3092 | /** | 3110 | /** |
3093 | * snd_soc_unregister_platform - Unregister a platform from the ASoC core | 3111 | * snd_soc_unregister_platform - Unregister a platform from the ASoC core |
3094 | * | 3112 | * |
3095 | * @platform: platform to unregister | 3113 | * @platform: platform to unregister |
3096 | */ | 3114 | */ |
3097 | void snd_soc_unregister_platform(struct device *dev) | 3115 | void snd_soc_unregister_platform(struct device *dev) |
3098 | { | 3116 | { |
3099 | struct snd_soc_platform *platform; | 3117 | struct snd_soc_platform *platform; |
3100 | 3118 | ||
3101 | list_for_each_entry(platform, &platform_list, list) { | 3119 | list_for_each_entry(platform, &platform_list, list) { |
3102 | if (dev == platform->dev) | 3120 | if (dev == platform->dev) |
3103 | goto found; | 3121 | goto found; |
3104 | } | 3122 | } |
3105 | return; | 3123 | return; |
3106 | 3124 | ||
3107 | found: | 3125 | found: |
3108 | mutex_lock(&client_mutex); | 3126 | mutex_lock(&client_mutex); |
3109 | list_del(&platform->list); | 3127 | list_del(&platform->list); |
3110 | mutex_unlock(&client_mutex); | 3128 | mutex_unlock(&client_mutex); |
3111 | 3129 | ||
3112 | pr_debug("Unregistered platform '%s'\n", platform->name); | 3130 | pr_debug("Unregistered platform '%s'\n", platform->name); |
3113 | kfree(platform->name); | 3131 | kfree(platform->name); |
3114 | kfree(platform); | 3132 | kfree(platform); |
3115 | } | 3133 | } |
3116 | EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); | 3134 | EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); |
3117 | 3135 | ||
3118 | static u64 codec_format_map[] = { | 3136 | static u64 codec_format_map[] = { |
3119 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, | 3137 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, |
3120 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE, | 3138 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE, |
3121 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE, | 3139 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE, |
3122 | SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE, | 3140 | SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE, |
3123 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, | 3141 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, |
3124 | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE, | 3142 | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE, |
3125 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, | 3143 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, |
3126 | SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, | 3144 | SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, |
3127 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE, | 3145 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE, |
3128 | SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE, | 3146 | SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE, |
3129 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE, | 3147 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE, |
3130 | SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE, | 3148 | SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE, |
3131 | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE, | 3149 | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE, |
3132 | SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE, | 3150 | SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE, |
3133 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | 3151 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
3134 | | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, | 3152 | | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, |
3135 | }; | 3153 | }; |
3136 | 3154 | ||
3137 | /* Fix up the DAI formats for endianness: codecs don't actually see | 3155 | /* Fix up the DAI formats for endianness: codecs don't actually see |
3138 | * the endianness of the data but we're using the CPU format | 3156 | * the endianness of the data but we're using the CPU format |
3139 | * definitions which do need to include endianness so we ensure that | 3157 | * definitions which do need to include endianness so we ensure that |
3140 | * codec DAIs always have both big and little endian variants set. | 3158 | * codec DAIs always have both big and little endian variants set. |
3141 | */ | 3159 | */ |
3142 | static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) | 3160 | static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) |
3143 | { | 3161 | { |
3144 | int i; | 3162 | int i; |
3145 | 3163 | ||
3146 | for (i = 0; i < ARRAY_SIZE(codec_format_map); i++) | 3164 | for (i = 0; i < ARRAY_SIZE(codec_format_map); i++) |
3147 | if (stream->formats & codec_format_map[i]) | 3165 | if (stream->formats & codec_format_map[i]) |
3148 | stream->formats |= codec_format_map[i]; | 3166 | stream->formats |= codec_format_map[i]; |
3149 | } | 3167 | } |
3150 | 3168 | ||
3151 | /** | 3169 | /** |
3152 | * snd_soc_register_codec - Register a codec with the ASoC core | 3170 | * snd_soc_register_codec - Register a codec with the ASoC core |
3153 | * | 3171 | * |
3154 | * @codec: codec to register | 3172 | * @codec: codec to register |
3155 | */ | 3173 | */ |
3156 | int snd_soc_register_codec(struct device *dev, | 3174 | int snd_soc_register_codec(struct device *dev, |
3157 | struct snd_soc_codec_driver *codec_drv, | 3175 | struct snd_soc_codec_driver *codec_drv, |
3158 | struct snd_soc_dai_driver *dai_drv, int num_dai) | 3176 | struct snd_soc_dai_driver *dai_drv, int num_dai) |
3159 | { | 3177 | { |
3160 | struct snd_soc_codec *codec; | 3178 | struct snd_soc_codec *codec; |
3161 | int ret, i; | 3179 | int ret, i; |
3162 | 3180 | ||
3163 | dev_dbg(dev, "codec register %s\n", dev_name(dev)); | 3181 | dev_dbg(dev, "codec register %s\n", dev_name(dev)); |
3164 | 3182 | ||
3165 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 3183 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
3166 | if (codec == NULL) | 3184 | if (codec == NULL) |
3167 | return -ENOMEM; | 3185 | return -ENOMEM; |
3168 | 3186 | ||
3169 | /* create CODEC component name */ | 3187 | /* create CODEC component name */ |
3170 | codec->name = fmt_single_name(dev, &codec->id); | 3188 | codec->name = fmt_single_name(dev, &codec->id); |
3171 | if (codec->name == NULL) { | 3189 | if (codec->name == NULL) { |
3172 | kfree(codec); | 3190 | kfree(codec); |
3173 | return -ENOMEM; | 3191 | return -ENOMEM; |
3174 | } | 3192 | } |
3175 | 3193 | ||
3176 | /* allocate CODEC register cache */ | 3194 | /* allocate CODEC register cache */ |
3177 | if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { | 3195 | if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { |
3178 | 3196 | ||
3179 | if (codec_drv->reg_cache_default) | 3197 | if (codec_drv->reg_cache_default) |
3180 | codec->reg_cache = kmemdup(codec_drv->reg_cache_default, | 3198 | codec->reg_cache = kmemdup(codec_drv->reg_cache_default, |
3181 | codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL); | 3199 | codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL); |
3182 | else | 3200 | else |
3183 | codec->reg_cache = kzalloc(codec_drv->reg_cache_size * | 3201 | codec->reg_cache = kzalloc(codec_drv->reg_cache_size * |
3184 | codec_drv->reg_word_size, GFP_KERNEL); | 3202 | codec_drv->reg_word_size, GFP_KERNEL); |
3185 | 3203 | ||
3186 | if (codec->reg_cache == NULL) { | 3204 | if (codec->reg_cache == NULL) { |
3187 | kfree(codec->name); | 3205 | kfree(codec->name); |
3188 | kfree(codec); | 3206 | kfree(codec); |
3189 | return -ENOMEM; | 3207 | return -ENOMEM; |
3190 | } | 3208 | } |
3191 | } | 3209 | } |
3192 | 3210 | ||
3193 | codec->dev = dev; | 3211 | codec->dev = dev; |
3194 | codec->driver = codec_drv; | 3212 | codec->driver = codec_drv; |
3195 | codec->bias_level = SND_SOC_BIAS_OFF; | 3213 | codec->bias_level = SND_SOC_BIAS_OFF; |
3196 | codec->num_dai = num_dai; | 3214 | codec->num_dai = num_dai; |
3197 | mutex_init(&codec->mutex); | 3215 | mutex_init(&codec->mutex); |
3198 | INIT_LIST_HEAD(&codec->dapm_widgets); | 3216 | INIT_LIST_HEAD(&codec->dapm_widgets); |
3199 | INIT_LIST_HEAD(&codec->dapm_paths); | 3217 | INIT_LIST_HEAD(&codec->dapm_paths); |
3200 | 3218 | ||
3201 | for (i = 0; i < num_dai; i++) { | 3219 | for (i = 0; i < num_dai; i++) { |
3202 | fixup_codec_formats(&dai_drv[i].playback); | 3220 | fixup_codec_formats(&dai_drv[i].playback); |
3203 | fixup_codec_formats(&dai_drv[i].capture); | 3221 | fixup_codec_formats(&dai_drv[i].capture); |
3204 | } | 3222 | } |
3205 | 3223 | ||
3206 | /* register any DAIs */ | 3224 | /* register any DAIs */ |
3207 | if (num_dai) { | 3225 | if (num_dai) { |
3208 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | 3226 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); |
3209 | if (ret < 0) | 3227 | if (ret < 0) |
3210 | goto error; | 3228 | goto error; |
3211 | } | 3229 | } |
3212 | 3230 | ||
3213 | mutex_lock(&client_mutex); | 3231 | mutex_lock(&client_mutex); |
3214 | list_add(&codec->list, &codec_list); | 3232 | list_add(&codec->list, &codec_list); |
3215 | snd_soc_instantiate_cards(); | 3233 | snd_soc_instantiate_cards(); |
3216 | mutex_unlock(&client_mutex); | 3234 | mutex_unlock(&client_mutex); |
3217 | 3235 | ||
3218 | pr_debug("Registered codec '%s'\n", codec->name); | 3236 | pr_debug("Registered codec '%s'\n", codec->name); |
3219 | return 0; | 3237 | return 0; |
3220 | 3238 | ||
3221 | error: | 3239 | error: |
3222 | for (i--; i >= 0; i--) | 3240 | for (i--; i >= 0; i--) |
3223 | snd_soc_unregister_dai(dev); | 3241 | snd_soc_unregister_dai(dev); |
3224 | 3242 | ||
3225 | if (codec->reg_cache) | 3243 | if (codec->reg_cache) |
3226 | kfree(codec->reg_cache); | 3244 | kfree(codec->reg_cache); |
3227 | kfree(codec->name); | 3245 | kfree(codec->name); |
3228 | kfree(codec); | 3246 | kfree(codec); |
3229 | return ret; | 3247 | return ret; |
3230 | } | 3248 | } |
3231 | EXPORT_SYMBOL_GPL(snd_soc_register_codec); | 3249 | EXPORT_SYMBOL_GPL(snd_soc_register_codec); |
3232 | 3250 | ||
3233 | /** | 3251 | /** |
3234 | * snd_soc_unregister_codec - Unregister a codec from the ASoC core | 3252 | * snd_soc_unregister_codec - Unregister a codec from the ASoC core |
3235 | * | 3253 | * |
3236 | * @codec: codec to unregister | 3254 | * @codec: codec to unregister |
3237 | */ | 3255 | */ |
3238 | void snd_soc_unregister_codec(struct device *dev) | 3256 | void snd_soc_unregister_codec(struct device *dev) |
3239 | { | 3257 | { |
3240 | struct snd_soc_codec *codec; | 3258 | struct snd_soc_codec *codec; |
3241 | int i; | 3259 | int i; |
3242 | 3260 | ||
3243 | list_for_each_entry(codec, &codec_list, list) { | 3261 | list_for_each_entry(codec, &codec_list, list) { |
3244 | if (dev == codec->dev) | 3262 | if (dev == codec->dev) |
3245 | goto found; | 3263 | goto found; |
3246 | } | 3264 | } |
3247 | return; | 3265 | return; |
3248 | 3266 | ||
3249 | found: | 3267 | found: |
3250 | if (codec->num_dai) | 3268 | if (codec->num_dai) |
3251 | for (i = 0; i < codec->num_dai; i++) | 3269 | for (i = 0; i < codec->num_dai; i++) |
3252 | snd_soc_unregister_dai(dev); | 3270 | snd_soc_unregister_dai(dev); |
3253 | 3271 | ||
3254 | mutex_lock(&client_mutex); | 3272 | mutex_lock(&client_mutex); |
3255 | list_del(&codec->list); | 3273 | list_del(&codec->list); |
3256 | mutex_unlock(&client_mutex); | 3274 | mutex_unlock(&client_mutex); |
3257 | 3275 | ||
3258 | pr_debug("Unregistered codec '%s'\n", codec->name); | 3276 | pr_debug("Unregistered codec '%s'\n", codec->name); |
3259 | 3277 | ||
3260 | if (codec->reg_cache) | 3278 | if (codec->reg_cache) |
3261 | kfree(codec->reg_cache); | 3279 | kfree(codec->reg_cache); |
3262 | kfree(codec); | 3280 | kfree(codec); |
3263 | } | 3281 | } |
3264 | EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); | 3282 | EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); |
3265 | 3283 | ||
3266 | static int __init snd_soc_init(void) | 3284 | static int __init snd_soc_init(void) |
3267 | { | 3285 | { |
3268 | #ifdef CONFIG_DEBUG_FS | 3286 | #ifdef CONFIG_DEBUG_FS |
3269 | debugfs_root = debugfs_create_dir("asoc", NULL); | 3287 | debugfs_root = debugfs_create_dir("asoc", NULL); |
3270 | if (IS_ERR(debugfs_root) || !debugfs_root) { | 3288 | if (IS_ERR(debugfs_root) || !debugfs_root) { |
3271 | printk(KERN_WARNING | 3289 | printk(KERN_WARNING |
3272 | "ASoC: Failed to create debugfs directory\n"); | 3290 | "ASoC: Failed to create debugfs directory\n"); |
3273 | debugfs_root = NULL; | 3291 | debugfs_root = NULL; |
3274 | } | 3292 | } |
3275 | 3293 | ||
3276 | if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL, | 3294 | if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL, |
3277 | &codec_list_fops)) | 3295 | &codec_list_fops)) |
3278 | pr_warn("ASoC: Failed to create CODEC list debugfs file\n"); | 3296 | pr_warn("ASoC: Failed to create CODEC list debugfs file\n"); |
3279 | 3297 | ||
3280 | if (!debugfs_create_file("dais", 0444, debugfs_root, NULL, | 3298 | if (!debugfs_create_file("dais", 0444, debugfs_root, NULL, |
3281 | &dai_list_fops)) | 3299 | &dai_list_fops)) |
3282 | pr_warn("ASoC: Failed to create DAI list debugfs file\n"); | 3300 | pr_warn("ASoC: Failed to create DAI list debugfs file\n"); |
3283 | 3301 | ||
3284 | if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL, | 3302 | if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL, |
3285 | &platform_list_fops)) | 3303 | &platform_list_fops)) |
3286 | pr_warn("ASoC: Failed to create platform list debugfs file\n"); | 3304 | pr_warn("ASoC: Failed to create platform list debugfs file\n"); |
3287 | #endif | 3305 | #endif |
3288 | 3306 | ||
3289 | return platform_driver_register(&soc_driver); | 3307 | return platform_driver_register(&soc_driver); |
3290 | } | 3308 | } |
3291 | 3309 | ||
3292 | static void __exit snd_soc_exit(void) | 3310 | static void __exit snd_soc_exit(void) |
3293 | { | 3311 | { |
3294 | #ifdef CONFIG_DEBUG_FS | 3312 | #ifdef CONFIG_DEBUG_FS |
3295 | debugfs_remove_recursive(debugfs_root); | 3313 | debugfs_remove_recursive(debugfs_root); |
3296 | #endif | 3314 | #endif |
3297 | platform_driver_unregister(&soc_driver); | 3315 | platform_driver_unregister(&soc_driver); |
3298 | } | 3316 | } |
3299 | 3317 | ||
3300 | module_init(snd_soc_init); | 3318 | module_init(snd_soc_init); |
3301 | module_exit(snd_soc_exit); | 3319 | module_exit(snd_soc_exit); |
3302 | 3320 | ||
3303 | /* Module information */ | 3321 | /* Module information */ |
3304 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); | 3322 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); |
3305 | MODULE_DESCRIPTION("ALSA SoC Core"); | 3323 | MODULE_DESCRIPTION("ALSA SoC Core"); |
3306 | MODULE_LICENSE("GPL"); | 3324 | MODULE_LICENSE("GPL"); |
3307 | MODULE_ALIAS("platform:soc-audio"); | 3325 | MODULE_ALIAS("platform:soc-audio"); |
3308 | 3326 |