This patch adds initial support for firmware based kcontrols by allowing
soc.h to be included by any userspace firmware generation tools and assigns
IDs to the standard ASoC kcontrol types using the kcontrol_new index and IDs
to kcontrol get/put/info functions.
Signed-off-by: Liam Girdwood <lrg(a)ti.com>
---
include/sound/soc.h | 135 +++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 116 insertions(+), 19 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 91244a0..b0b1703 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -13,6 +13,8 @@
#ifndef __LINUX_SND_SOC_H
#define __LINUX_SND_SOC_H
+#ifdef __KERNEL__
+
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/notifier.h>
@@ -27,6 +29,8 @@
#include <sound/control.h>
#include <sound/ac97_codec.h>
+#endif
+
/*
* Convenience kcontrol builders
*/
@@ -51,12 +55,12 @@
#define SOC_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
- .put = snd_soc_put_volsw, \
+ .put = snd_soc_put_volsw, .index = SOC_CONTROL_IO_VOLSW, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
- .put = snd_soc_put_volsw_range, \
+ .put = snd_soc_put_volsw_range, .index = SOC_CONTROL_IO_RANGE, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .min = xmin,\
.max = xmax, .platform_max = xmax, .invert = xinvert} }
@@ -66,7 +70,7 @@
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
- .put = snd_soc_put_volsw, \
+ .put = snd_soc_put_volsw, .index = SOC_CONTROL_IO_VOLSW, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -76,6 +80,7 @@
.info = snd_soc_info_volsw, \
.get = snd_soc_get_volsw_sx,\
.put = snd_soc_put_volsw_sx, \
+ .index = SOC_CONTROL_IO_VOLSW_SX \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .rreg = xreg, \
.shift = xshift, .rshift = xshift, \
@@ -85,7 +90,7 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_range, \
+ .info = snd_soc_info_volsw_range, .index = SOC_CONTROL_IO_RANGE, \
.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .min = xmin,\
@@ -93,19 +98,19 @@
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
- .put = snd_soc_put_volsw, \
+ .put = snd_soc_put_volsw, .index = SOC_CONTROL_IO_VOLSW, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert) }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_VOLSW, \
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) }
#define SOC_DOUBLE_R_RANGE(xname, reg_left, reg_right, xshift, xmin, \
xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
- .info = snd_soc_info_volsw_range, \
+ .info = snd_soc_info_volsw_range, .index = SOC_CONTROL_IO_RANGE, \
.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
.private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \
xshift, xmin, xmax, xinvert) }
@@ -115,7 +120,7 @@
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
- .put = snd_soc_put_volsw, \
+ .put = snd_soc_put_volsw, .index = SOC_CONTROL_IO_VOLSW, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert) }
#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
@@ -123,7 +128,7 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_VOLSW, \
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) }
@@ -133,7 +138,7 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_range, \
+ .info = snd_soc_info_volsw_range, .index = SOC_CONTROL_IO_RANGE, \
.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
.private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \
xshift, xmin, xmax, xinvert) }
@@ -145,6 +150,7 @@
.info = snd_soc_info_volsw, \
.get = snd_soc_get_volsw_sx, \
.put = snd_soc_put_volsw_sx, \
+ .index = SOC_CONTROL_IO_SX, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .rreg = xrreg, \
.shift = xshift, .rshift = xshift, \
@@ -155,7 +161,7 @@
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
- .put = snd_soc_put_volsw_s8, \
+ .put = snd_soc_put_volsw_s8, .index = SOC_CONTROL_IO_VOLSW_S8, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .min = xmin, .max = xmax, \
.platform_max = xmax} }
@@ -174,7 +180,7 @@
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues)
#define SOC_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
- .info = snd_soc_info_enum_double, \
+ .info = snd_soc_info_enum_double, .index = SOC_CONTROL_IO_ENUM, \
.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
.private_value = (unsigned long)&xenum }
#define SOC_VALUE_ENUM(xname, xenum) \
@@ -182,17 +188,18 @@
.info = snd_soc_info_enum_double, \
.get = snd_soc_get_value_enum_double, \
.put = snd_soc_put_value_enum_double, \
+ .index = SOC_CONTROL_IO_ENUM_VALUE, \
.private_value = (unsigned long)&xenum }
#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_EXT, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
#define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\
xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_EXT, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = \
SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) }
@@ -202,7 +209,7 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_EXT, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
#define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
@@ -211,7 +218,7 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_EXT,\
.get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \
xmax, xinvert) }
@@ -221,24 +228,25 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
+ .info = snd_soc_info_volsw, .index = SOC_CONTROL_IO_EXT, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) }
#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_bool_ext, \
+ .info = snd_soc_info_bool_ext, .index = SOC_CONTROL_IO_BOOL_EXT, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = xdata }
#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_enum_ext, \
+ .info = snd_soc_info_enum_ext, .index = SOC_CONTROL_IO_ENUM_EXT, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
#define SND_SOC_BYTES(xname, xbase, xregs) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+ .index = SOC_CONTROL_IO_BYTES, \
.put = snd_soc_bytes_put, .private_value = \
((unsigned long)&(struct soc_bytes) \
{.base = xbase, .num_regs = xregs }) }
@@ -247,6 +255,7 @@
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
.put = snd_soc_bytes_put, .private_value = \
+ .index = SOC_CONTROL_IO_BYTES, \
((unsigned long)&(struct soc_bytes) \
{.base = xbase, .num_regs = xregs, \
.mask = xmask }) }
@@ -256,6 +265,7 @@
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \
.put = snd_soc_put_xr_sx, \
+ .index = SOC_CONTROL_IO_XR_SX, \
.private_value = (unsigned long)&(struct soc_mreg_control) \
{.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
.invert = xinvert, .min = xmin, .max = xmax} }
@@ -281,6 +291,92 @@
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+
+/*
+ * Numeric IDs for stock mixer types that are used to enumerate FW based mixers.
+ */
+
+#define SOC_CONTROL_ID_PUT(p) ((p & 0xff) << 16)
+#define SOC_CONTROL_ID_GET(g) ((g & 0xff) << 8)
+#define SOC_CONTROL_ID_INFO(i) ((i & 0xff) << 0)
+#define SOC_CONTROL_ID(g, p, i) \
+ (SOC_CONTROL_ID_PUT(p) | SOC_CONTROL_ID_GET(g) |\
+ SOC_CONTROL_ID_INFO(i))
+
+#define SOC_CONTROL_GET_ID_PUT(id) ((id & 0xff0000) >> 16)
+#define SOC_CONTROL_GET_ID_GET(id) ((id & 0x00ff00) >> 8)
+#define SOC_CONTROL_GET_ID_INFO(id) ((id & 0x0000ff) >> 0)
+
+/* individual kcontrol info types - can be mixed with other types */
+#define SOC_CONTROL_TYPE_EXT 0 /* driver defined */
+#define SOC_CONTROL_TYPE_VOLSW 1
+#define SOC_CONTROL_TYPE_VOLSW_SX 2
+#define SOC_CONTROL_TYPE_VOLSW_S8 3
+#define SOC_CONTROL_TYPE_VOLSW_XR_SX 4
+#define SOC_CONTROL_TYPE_ENUM 6
+#define SOC_CONTROL_TYPE_ENUM_EXT 7
+#define SOC_CONTROL_TYPE_BYTES 8
+#define SOC_CONTROL_TYPE_BOOL_EXT 9
+#define SOC_CONTROL_TYPE_ENUM_VALUE 10
+#define SOC_CONTROL_TYPE_RANGE 11
+#define SOC_CONTROL_TYPE_STROBE 12
+
+/* compound control IDs */
+#define SOC_CONTROL_IO_VOLSW \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_VOLSW, \
+ SOC_CONTROL_TYPE_VOLSW, \
+ SOC_CONTROL_TYPE_VOLSW)
+#define SOC_CONTROL_IO_VOLSW_SX \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_VOLSW_SX, \
+ SOC_CONTROL_TYPE_VOLSW_SX, \
+ SOC_CONTROL_TYPE_VOLSW)
+#define SOC_CONTROL_IO_VOLSW_S8 \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_VOLSW_S8, \
+ SOC_CONTROL_TYPE_VOLSW_S8, \
+ SOC_CONTROL_TYPE_VOLSW_S8)
+#define SOC_CONTROL_IO_VOLSW_XR_SX \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_VOLSW_XR_SX, \
+ SOC_CONTROL_TYPE_VOLSW_XR_SX, \
+ SOC_CONTROL_TYPE_VOLSW_XR_SX)
+#define SOC_CONTROL_IO_EXT \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_EXT, \
+ SOC_CONTROL_TYPE_EXT, \
+ SOC_CONTROL_TYPE_VOLSW)
+#define SOC_CONTROL_IO_ENUM \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_ENUM, \
+ SOC_CONTROL_TYPE_ENUM, \
+ SOC_CONTROL_TYPE_ENUM)
+#define SOC_CONTROL_IO_ENUM_EXT \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_EXT, \
+ SOC_CONTROL_TYPE_EXT, \
+ SOC_CONTROL_TYPE_ENUM_EXT)
+#define SOC_CONTROL_IO_BYTES \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_BYTES, \
+ SOC_CONTROL_TYPE_BYTES, \
+ SOC_CONTROL_TYPE_BYTES)
+#define SOC_CONTROL_IO_BOOL_EXT \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_EXT, \
+ SOC_CONTROL_TYPE_EXT, \
+ SOC_CONTROL_TYPE_BOOL_EXT)
+#define SOC_CONTROL_IO_ENUM_VALUE \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_ENUM_VALUE, \
+ SOC_CONTROL_TYPE_ENUM_VALUE, \
+ SOC_CONTROL_TYPE_ENUM)
+#define SOC_CONTROL_IO_RANGE \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_RANGE, \
+ SOC_CONTROL_TYPE_RANGE, \
+ SOC_CONTROL_TYPE_RANGE)
+#define SOC_CONTROL_IO_STROBE \
+ SOC_CONTROL_ID(SOC_CONTROL_TYPE_STROBE, \
+ SOC_CONTROL_TYPE_STROBE, \
+ SOC_CONTROL_TYPE_STROBE)
+
+#ifdef __KERNEL__
+
+#define snd_soc_get_enum_text(soc_enum, idx) \
+ (soc_enum->texts ? soc_enum->texts[idx] : soc_enum->dtexts[idx])
+
+
/*
* Component probe and remove ordering levels for components with runtime
* dependencies.
@@ -1178,3 +1274,4 @@ extern struct dentry *snd_soc_debugfs_root;
extern const struct dev_pm_ops snd_soc_pm_ops;
#endif
+#endif
--
1.7.10.4