((unsigned long)&(struct soc_mixer_control) \
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
.max = xmax, .platform_max = xmax, .invert = xinvert})
+#define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \
+ ((unsigned long)&(struct soc_mixer_control) \
+ {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
+ .min = xmin, .max = xmax, .platform_max = xmax, .invert = xinvert})
#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, \
.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, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg, .shift = xshift, .min = xmin,\
+ .max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
{.reg = xreg, .rreg = xreg, \
.shift = xshift, .rshift = xshift, \
.max = xmax, .min = xmin} }
+#define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw_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,\
+ .max = xmax, .platform_max = xmax, .invert = xinvert} }
#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, \
.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, \
+ .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) }
#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
.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_TLV(xname, reg_left, reg_right, xshift, xmin, \
+ xmax, xinvert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw_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) }
#define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max);
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
/* config - must be set by machine driver */
const char *name; /* Codec name */
const char *stream_name; /* Stream name */
- const char *codec_name; /* for multi-codec */
- const struct device_node *codec_of_node;
- const char *platform_name; /* for multi-platform */
- const struct device_node *platform_of_node;
+ /*
+ * You MAY specify the link's CPU-side device, either by device name,
+ * or by DT/OF node, but not both. If this information is omitted,
+ * the CPU-side DAI is matched using .cpu_dai_name only, which hence
+ * must be globally unique. These fields are currently typically used
+ * only for codec to codec links, or systems using device tree.
+ */
+ const char *cpu_name;
+ const struct device_node *cpu_of_node;
+ /*
+ * You MAY specify the DAI name of the CPU DAI. If this information is
+ * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
+ * only, which only works well when that device exposes a single DAI.
+ */
const char *cpu_dai_name;
- const struct device_node *cpu_dai_of_node;
+ /*
+ * You MUST specify the link's codec, either by device name, or by
+ * DT/OF node, but not both.
+ */
+ const char *codec_name;
+ const struct device_node *codec_of_node;
+ /* You MUST specify the DAI name within the codec */
const char *codec_dai_name;
+ /*
+ * You MAY specify the link's platform/PCM/DMA driver, either by
+ * device name, or by DT/OF node, but not both. Some forms of link
+ * do not need a platform.
+ */
+ const char *platform_name;
+ const struct device_node *platform_of_node;
int be_id; /* optional ID for machine driver BE identification */
const struct snd_soc_pcm_stream *params;