summaryrefslogtreecommitdiff
path: root/snd-alpx/alpx_controls.c
diff options
context:
space:
mode:
Diffstat (limited to 'snd-alpx/alpx_controls.c')
-rw-r--r--snd-alpx/alpx_controls.c2096
1 files changed, 2096 insertions, 0 deletions
diff --git a/snd-alpx/alpx_controls.c b/snd-alpx/alpx_controls.c
new file mode 100644
index 0000000..397fe99
--- /dev/null
+++ b/snd-alpx/alpx_controls.c
@@ -0,0 +1,2096 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+* Support for Digigram AlpX PCI-e boards
+*
+* Copyright (c) 2024 Digigram Digital (info@digigram.com)
+*/
+
+#include "alpx_controls.h"
+#include "alpx_variants_stereo.h"
+#include "alpx_variants_mc.h"
+#include "alpx_variants_dead.h"
+#include "alpx_variants_madi.h"
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+
+/* Amplifiers */
+
+static int alpx_control_amplifier_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_amplifier* descr =
+ (struct alpx_control_descriptor_amplifier*) &control->descriptor->data.ampli;
+
+ dev_dbg( alpx_dev->dev," for volume[%u] (controls[%lu]){%p}.\n",
+ control->data.ampli.idx,
+ control_index,
+ control);
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1; //Single channel amplifier
+ info->value.integer.min = descr->reg_gain_min;
+ info->value.integer.max = descr->reg_gain_max;
+
+ return 0;
+}
+
+static int alpx_control_amplifier_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ const struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_amplifier* ampli = &control->data.ampli;
+
+ const u32 offset = control->descriptor->base + ALP_INDEX_TO_REG_OFFSET(ampli->idx);
+
+ u32 value;
+
+ value = readl(alpx_dev->base + offset);
+
+ dev_dbg( alpx_dev->dev," volume[%u](controls[%u]){%p} : 0x%x <= [0x%p:%x:%x]\n",
+ control->data.ampli.idx,
+ control_index,
+ control,
+ value,
+ alpx_dev->base,
+ control->descriptor->base,
+ ALP_INDEX_TO_REG_OFFSET(ampli->idx));
+
+ elem_value->value.integer.value[0] = value;
+
+ return 0;
+}
+
+static int alpx_control_amplifier_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ const struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+ const struct alpx_control_amplifier* ampli = &control->data.ampli;
+
+ const u32 offset = control->descriptor->base + ALP_INDEX_TO_REG_OFFSET(ampli->idx);
+ const u32 value = elem_value->value.integer.value[0];
+
+ dev_dbg( alpx_dev->dev," volume[%u](controls[%u]){%p} : 0x%x => [0x%p:%x:%x]\n",
+ control->data.ampli.idx,
+ control_index,
+ control,
+ value,
+ alpx_dev->base,
+ control->descriptor->base,
+ ALP_INDEX_TO_REG_OFFSET(ampli->idx));
+
+ writel(value, alpx_dev->base + offset);
+
+ return 1; /* Value changed */
+}
+
+
+static struct snd_kcontrol_new alpx_control_amplifier = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_amplifier_info,
+ .get = alpx_control_amplifier_get,
+ .put = alpx_control_amplifier_put,
+};
+
+static int alpx_control_amplifier_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor,
+ unsigned int idx)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ const unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ control->descriptor = descriptor;
+ control->data.ampli.idx = idx;
+
+ snprintf(name, sizeof(name), "%s Volume", /* Just add FUNCTION, see alsa driver guide */
+ control->descriptor->prefix);
+
+ dev_dbg( alpx_dev->dev,"creating amplifier %s[%u] in controls[%u] linked to [0x%x:0x%x].\n",
+ name,
+ control->data.ampli.idx,
+ control_index,
+ control->descriptor->base,
+ ALP_INDEX_TO_REG_OFFSET(control->data.ampli.idx));
+
+ alpx_control_amplifier.name = name;
+ alpx_control_amplifier.private_value = control_index;
+ alpx_control_amplifier.index = control->data.ampli.idx;
+ alpx_control_amplifier.access = descriptor->access;
+ alpx_control_amplifier.tlv.p = descriptor->data.ampli.gains_scale;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_amplifier, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+static int alpx_controls_amplifier_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ const unsigned int items_count = descriptor->data.ampli.lines_count;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < items_count; i++) {
+ ret = alpx_control_amplifier_register(card, descriptor, i);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* Codec : analog equalization*/
+
+static int alpx_control_codec_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ const struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned int control_index = kcontrol->private_value;
+ const struct alpx_control *control = &alpx_dev->controls[control_index];
+ const struct alpx_control_descriptor_codec* descr = &control->descriptor->data.codec;
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1; /* single line */
+ info->value.integer.min = descr->reg_gain_min;
+ info->value.integer.max = descr->reg_gain_max;
+
+ return 0;
+}
+
+static int alpx_control_codec_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ const struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned int control_index = kcontrol->private_value;
+ const struct alpx_control *control = &alpx_dev->controls[control_index];
+ const unsigned int idx = control->data.codec.idx;
+
+ const u32 offset = control->descriptor->base + control->descriptor->data.codec.offset +
+ ALPX_CODEC_CTRL_GAIN_REG(idx);
+
+ elem_value->value.integer.value[0] = readl(alpx_dev->base + offset);
+
+
+ dev_dbg( alpx_dev->dev,"0x%lx <= [0x%x:%x]\n",
+ elem_value->value.integer.value[0],
+ control->descriptor->base,
+ control->descriptor->data.codec.offset + ALPX_CODEC_CTRL_GAIN_REG(idx));
+
+ return 0;
+}
+
+static int alpx_control_codec_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ const struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned int control_index = kcontrol->private_value;
+ const struct alpx_control *control = &alpx_dev->controls[control_index];
+ const unsigned int idx = control->data.codec.idx;
+
+ const u32 offset = control->descriptor->base + control->descriptor->data.codec.offset +
+ ALPX_CODEC_CTRL_GAIN_REG(idx);
+
+ const u32 value = elem_value->value.integer.value[0];
+
+ dev_dbg( alpx_dev->dev," 0x%x => [0x%x:%x]\n",
+ value,
+ control->descriptor->base,
+ control->descriptor->data.codec.offset + ALPX_CODEC_CTRL_GAIN_REG(idx));
+
+ writel(value, alpx_dev->base + offset);
+
+ return 1;
+}
+
+
+static struct snd_kcontrol_new alpx_control_codec = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_codec_info,
+ .get = alpx_control_codec_get,
+ .put = alpx_control_codec_put,
+};
+
+static int alpx_control_codec_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor,
+ unsigned int idx)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ control->descriptor = descriptor;
+ control->data.codec.idx = idx;
+
+ snprintf(name, sizeof(name), "%s Volume", descriptor->prefix);
+
+ alpx_control_codec.name = name;
+ alpx_control_codec.private_value = control_index;
+ alpx_control_codec.index = control->data.codec.idx;
+ alpx_control_codec.access = descriptor->access;
+ alpx_control_codec.tlv.p = descriptor->data.codec.gains_scale;
+
+ dev_dbg( alpx_dev->dev," creating codec eq %s[%u] in controls[%u] linked to [0x%x:0x%x].\n",
+ name,
+ control->data.codec.idx,
+ control_index,
+ control->descriptor->base,
+ ALPX_CODEC_CTRL_GAIN_REG(control->data.codec.idx));
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_codec, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+static int alpx_controls_codec_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ const unsigned int items_count = descriptor->data.codec.lines_count;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < items_count; i++) {
+ ret = alpx_control_codec_register(card, descriptor, i);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* Router */
+
+static int alpx_control_router_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor_router *router =
+ &control->descriptor->data.router;
+
+ return snd_ctl_enum_info(info, 1, router->entries_count, router->entries);
+}
+
+static int alpx_control_router_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int index = control->data.router.index;
+ unsigned int index_value;
+ u32 offset, value;
+
+ offset = control->descriptor->base + ALPX_ROUTER_REG(index);
+ value = readl(alpx_dev->base + offset);
+
+ dev_dbg( alpx_dev->dev,"0x%x <= [0x%p:%x:%x]\n",
+ value,
+ alpx_dev->base,
+ control->descriptor->base,
+ ALPX_ROUTER_REG(index));
+
+ index_value = ALPX_ROUTER_VALUE(index, value);
+ elem_value->value.enumerated.item[0] = index_value;
+
+ return 0;
+}
+
+static int alpx_control_router_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int index = control->data.router.index;
+ unsigned int index_value;
+ u32 offset, value;
+
+ offset = control->descriptor->base + ALPX_ROUTER_REG(index);
+ value = readl(alpx_dev->base + offset);
+ index_value = ALPX_ROUTER_VALUE(index, value);
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," 0x%x => [0x%p:%x:%x:%d]\n",
+ value,
+ alpx_dev->base,
+ control->descriptor->base,
+ ALPX_ROUTER_REG(index),
+ index_value);
+#endif
+
+ if (index_value == elem_value->value.enumerated.item[0])
+ return 0;
+
+ index_value = elem_value->value.enumerated.item[0];
+
+ value &= ~ALPX_ROUTER_MASK(index);
+ value |= ALPX_ROUTER_SEL(index, index_value);
+
+ writel(value, alpx_dev->base + offset);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new alpx_control_router = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_router_info,
+ .get = alpx_control_router_get,
+ .put = alpx_control_router_put,
+};
+
+static int alpx_control_router_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor,
+ unsigned int index)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ control->descriptor = descriptor;
+ control->data.router.index = index;
+
+ snprintf(name, sizeof(name), "%s Route", descriptor->prefix);
+
+ alpx_control_router.name = name;
+ alpx_control_router.private_value = control_index;
+ alpx_control_router.index = index;
+ alpx_control_router.access = descriptor->access;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_router, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+/* RESERVED controls */
+static int alpx_control_reserved_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ info->count = 1;
+ info->value.integer.min = 0;
+ info->value.integer.max = 1;
+
+ return 0;
+}
+
+static int alpx_control_reserved_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ elem_value->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int alpx_control_reserved_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ return 0;
+}
+
+static struct snd_kcontrol_new alpx_control_reserved = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+
+ .info = alpx_control_reserved_info,
+ .get = alpx_control_reserved_get,
+ .put = alpx_control_reserved_put,
+};
+
+static int alpx_control_reserved_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ control->descriptor = descriptor;
+ snprintf(name, sizeof(name), "%s", descriptor->prefix);
+
+ alpx_control_reserved.name = name;
+ alpx_control_reserved.private_value = control_index;
+ alpx_control_reserved.index = 0;
+ alpx_control_reserved.access = SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_reserved, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+
+}
+
+/* Constant */
+static int alpx_control_constant_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_constant* descr =
+ (struct alpx_control_descriptor_constant*) &control->descriptor->data.constant;
+
+ dev_dbg(alpx_dev->dev, "INFO constant control \n");
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1;
+ info->value.integer.min = descr->value;
+ info->value.integer.max = descr->value;
+
+ return 0;
+}
+
+static int alpx_control_constant_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_constant* descr =
+ (struct alpx_control_descriptor_constant*) &control->descriptor->data.constant;
+
+ dev_dbg(alpx_dev->dev, "GET constant control \n");
+
+ elem_value->value.integer.value[0] = descr->value;
+ return 0;
+}
+
+
+static struct snd_kcontrol_new alpx_control_constant = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+
+ .info = alpx_control_constant_info,
+ .get = alpx_control_constant_get,
+ .put = NULL,
+};
+
+static int alpx_control_constant_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ dev_dbg(alpx_dev->dev, "Registering constant control for %s\n", card->longname);
+
+ control->descriptor = descriptor;
+ snprintf(name, sizeof(name), "%s", descriptor->prefix);
+
+ alpx_control_constant.name = name;
+ alpx_control_constant.private_value = control_index;
+ alpx_control_constant.index = 0;
+ alpx_control_constant.access = SNDRV_CTL_ELEM_ACCESS_READ; /* ENFORCE Read only */
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_constant, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+/* AXCMem Relative choice control */
+static int alpx_control_axcmem_rel_choice_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_axcmem_rel_choice* choice_descr =
+ (struct alpx_control_descriptor_axcmem_rel_choice*) &control->descriptor->data.axcmem_rel_choice;
+
+ dev_dbg(alpx_dev->dev, "INFO choice control\n");
+
+ return snd_ctl_enum_info(info, 1, choice_descr->entries_count, choice_descr->entries);
+}
+
+static int alpx_control_axcmem_rel_choice_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_axcmem_rel_choice* choice_descr =
+ (struct alpx_control_descriptor_axcmem_rel_choice*) &control->descriptor->data.axcmem_rel_choice;
+
+ const unsigned int choice_index = elem_value->value.enumerated.item[0];
+
+ unsigned int reg_value = choice_descr->getter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &choice_descr->base_loc,
+ &choice_descr->reg_loc));
+
+ unsigned int choice_value = 0;
+
+ if (choice_index >= choice_descr->entries_count ) {
+ dev_err(alpx_dev->dev, "Index out of bound : %d > %d !\n", choice_index, choice_descr->entries_count - 1);
+ return -EINVAL;
+ }
+
+ choice_value = (control->descriptor->data.axcmem_rel_choice.entries_values[choice_index] << choice_descr->pos);
+
+ reg_value &= choice_descr->mask;
+ reg_value |= choice_value;
+
+ choice_descr->setter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &choice_descr->base_loc,
+ &choice_descr->reg_loc),
+ reg_value);
+
+ dev_dbg(alpx_dev->dev, "%s: index = %d, value = 0x%x, mask: 0x%08x => reg_value=0x%08x\n",
+ control->descriptor->prefix,
+ elem_value->value.enumerated.item[0],
+ choice_value,
+ choice_descr->mask,
+ choice_descr->getter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &choice_descr->base_loc,
+ &choice_descr->reg_loc)));
+ return 0;
+}
+
+static int alpx_control_axcmem_rel_choice_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_axcmem_rel_choice* choice =
+ (struct alpx_control_descriptor_axcmem_rel_choice*) &control->descriptor->data.axcmem_rel_choice;
+
+ const unsigned int reg_value = choice->getter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &choice->base_loc,
+ &choice->reg_loc));
+
+ const unsigned int read_value = (reg_value & choice->mask) >> choice->pos;
+ unsigned int value_index = 0;
+
+ for (value_index = 0; value_index < choice->entries_count; ++value_index) {
+ u32 entry_value = choice->entries_values[value_index];
+
+ if (read_value == entry_value) {
+ elem_value->value.enumerated.item[0] = value_index;
+ dev_dbg(alpx_dev->dev, "%s: reg_value=0x%08x, mask: 0x%08x => index = %d\n",
+ control->descriptor->prefix,
+ reg_value,
+ choice->mask,
+ value_index);
+ return 0;
+ }
+ }
+
+ dev_err(alpx_dev->dev, "%s: unknown choice for: reg_value=0x%08x, mask: 0x%08x => value = %d\n",
+ control->descriptor->prefix,
+ reg_value,
+ choice->mask,
+ (reg_value & choice->mask)>>choice->pos);
+
+ return -EINVAL;
+}
+
+static struct snd_kcontrol_new alpx_control_axcmem_rel_choice = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = alpx_control_axcmem_rel_choice_info,
+ .get = alpx_control_axcmem_rel_choice_get,
+ .put = alpx_control_axcmem_rel_choice_put,
+};
+
+int alpx_control_axcmem_rel_choice_register (struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ dev_dbg(alpx_dev->dev, "Registering choice control for %s\n", card->longname);
+
+ control->descriptor = descriptor;
+ snprintf(name, sizeof(name), "%s", descriptor->prefix);
+
+ alpx_control_axcmem_rel_choice.name = name;
+ alpx_control_axcmem_rel_choice.private_value = control_index;
+ alpx_control_axcmem_rel_choice.index = 0;
+ alpx_control_axcmem_rel_choice.access = descriptor->access;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_axcmem_rel_choice, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+
+}
+
+/* AxCMem Value */
+static int alpx_control_axcmem_rel_value_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_axcmem_rel_value* value_descr =
+ (struct alpx_control_descriptor_axcmem_rel_value*) &control->descriptor->data.axcmem_rel_value;
+
+ dev_dbg(alpx_dev->dev, "INFO Value control \n");
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1;
+ info->value.integer.min = value_descr->min;
+ info->value.integer.max = value_descr->max;
+
+ return 0;
+}
+
+static int alpx_control_axcmem_rel_value_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_axcmem_rel_value* value_descr =
+ (struct alpx_control_descriptor_axcmem_rel_value*) &control->descriptor->data.axcmem_rel_value;
+
+ unsigned int reg_value = value_descr->getter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &value_descr->base_loc,
+ &value_descr->reg_loc));
+
+ reg_value &= value_descr->mask;
+ reg_value |= ((elem_value->value.integer.value[0] & value_descr->mask) << value_descr->pos);
+
+ value_descr->setter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &value_descr->base_loc,
+ &value_descr->reg_loc),
+ reg_value);
+
+ dev_dbg(alpx_dev->dev, "%s: reg_value=0x%08x, mask: 0x%08x => index = %ld\n",
+ control->descriptor->prefix,
+ value_descr->getter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &value_descr->base_loc,
+ &value_descr->reg_loc)),
+ value_descr->mask,
+ elem_value->value.integer.value[0]);
+
+ return 0;
+}
+
+static int alpx_control_axcmem_rel_value_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_axcmem_rel_value* value_descr =
+ (struct alpx_control_descriptor_axcmem_rel_value*) &control->descriptor->data.axcmem_rel_value;
+
+ const unsigned int reg_value = value_descr->getter(alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev,
+ &value_descr->base_loc,
+ &value_descr->reg_loc));
+
+ elem_value->value.integer.value[0] = (reg_value & value_descr->mask) >> value_descr->pos;
+
+ dev_dbg(alpx_dev->dev, "%s: reg_value=0x%08x, mask: 0x%08x => value: 0x%lx\n",
+ control->descriptor->prefix,
+ reg_value,
+ value_descr->mask,
+ elem_value->value.integer.value[0]);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new alpx_control_axcmem_rel_value = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = alpx_control_axcmem_rel_value_info,
+ .get = alpx_control_axcmem_rel_value_get,
+ .put = alpx_control_axcmem_rel_value_put,
+};
+
+int alpx_control_axcmem_rel_value_register (struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ char name[64] = { 0 };
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ dev_dbg(alpx_dev->dev, "Registering VALUE control for %s\n", card->longname);
+
+ control->descriptor = descriptor;
+ snprintf(name, sizeof(name), "%s", descriptor->prefix);
+
+ alpx_control_axcmem_rel_value.name = name;
+ alpx_control_axcmem_rel_value.private_value = control_index;
+ alpx_control_axcmem_rel_value.index = 0;
+ alpx_control_axcmem_rel_value.access = descriptor->access;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_axcmem_rel_value, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+ return 0;
+}
+
+/* Mixer */
+
+static int alpx_control_mixer_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ const unsigned long control_index = kcontrol->private_value;
+
+ const struct alpx_control* control = &alpx_dev->controls[control_index];
+
+ const struct alpx_control_descriptor_mixer* descr =
+ (struct alpx_control_descriptor_mixer*) &control->descriptor->data.mixer;
+
+
+
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1;
+ info->value.integer.min = descr->reg_gain_min;
+ info->value.integer.max = descr->reg_gain_max;
+
+ return 0;
+}
+
+static int alpx_control_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int lines_count = control->descriptor->data.mixer.lines_count;
+ unsigned int mixer_in = control->data.mixer.mixer_in;
+ unsigned int mixer_out = control->data.mixer.mixer_out;
+ u32 offset, reg_value;
+
+ //Registers layout depends on the card's variant
+ switch(alpx_dev->variant->model) {
+ case ALPX_VARIANT_MODEL_ALP882:
+ case ALPX_VARIANT_MODEL_ALP882_MIC:
+ case ALPX_VARIANT_MODEL_ALP442:
+ case ALPX_VARIANT_MODEL_ALP442_MIC:
+ offset = control->descriptor->base +
+ ALPMC_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out);
+ reg_value = readl(alpx_dev->base + offset);
+ elem_value->value.integer.value[0] = ALPMC_MIXER_GAIN_VALUE(reg_value);
+
+ #if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," %ld (0x%lx <= 0x%x)<= (%d,%d,%d)[REG:%x:%02x]\n",
+ elem_value->value.integer.value[0],
+ ALPMC_MIXER_GAIN_VALUE(reg_value),
+ reg_value,
+ lines_count, mixer_in, mixer_out,
+ control->descriptor->base,
+ ALPMC_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out));
+ #endif
+ break;
+
+ case ALPX_VARIANT_MODEL_ALP222:
+ case ALPX_VARIANT_MODEL_ALP222_MIC:
+ offset = control->descriptor->base +
+ ALP222_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out);
+ reg_value = readl(alpx_dev->base + offset);
+ elem_value->value.integer.value[0] = ALP222_MIXER_GAIN_VALUE(mixer_in, reg_value);
+
+ #if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," %ld (0x%lx <= 0x%x)<= (%d,%d,%d)[REG:%x:%02x]\n",
+ elem_value->value.integer.value[0],
+ ALP222_MIXER_GAIN_VALUE(mixer_in, reg_value),
+ reg_value,
+ lines_count, mixer_in, mixer_out,
+ control->descriptor->base,
+ ALP222_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out));
+ #endif
+ break;
+
+ default:
+ //No mixer by default !
+ elem_value->value.integer.value[0] = 0;
+ return 0;
+ };
+
+
+ return 0;
+}
+
+static int alpx_control_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int lines_count = control->descriptor->data.mixer.lines_count;
+ unsigned int mixer_in = control->data.mixer.mixer_in;
+ unsigned int mixer_out = control->data.mixer.mixer_out;
+ unsigned int mixer_value;
+ u32 offset, reg_value;
+
+ mixer_value = elem_value->value.integer.value[0];
+
+ switch(alpx_dev->variant->model) {
+ case ALPX_VARIANT_MODEL_ALP882:
+ case ALPX_VARIANT_MODEL_ALP882_MIC:
+ case ALPX_VARIANT_MODEL_ALP442:
+ case ALPX_VARIANT_MODEL_ALP442_MIC:
+ offset = control->descriptor->base +
+ ALPMC_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out);
+ reg_value = readl(alpx_dev->base + offset);
+
+ reg_value &= ~ALPMC_MIXER_GAIN_MASK;
+
+ #if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," 0x%x (0x%lx => 0x%x)=> (%d,%d,%d)[REG:%x:%02x]\n",
+ mixer_value,
+ ALPMC_MIXER_GAIN_SEL(mixer_value),
+ reg_value,
+ lines_count, mixer_in, mixer_out,
+ control->descriptor->base,
+ ALPMC_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out));
+ #endif
+
+ reg_value |= ALPMC_MIXER_GAIN_SEL(mixer_value);
+ break;
+
+ case ALPX_VARIANT_MODEL_ALP222:
+ case ALPX_VARIANT_MODEL_ALP222_MIC:
+ offset = control->descriptor->base +
+ ALP222_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out);
+ reg_value = readl(alpx_dev->base + offset);
+
+ reg_value &= ~ALP222_MIXER_GAIN_MASK(mixer_in);
+
+ #if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," 0x%x (0x%lx => 0x%x)=> (%d,%d,%d)[REG:%x:%02x]\n",
+ mixer_value,
+ ALP222_MIXER_GAIN_SEL(mixer_in, mixer_value),
+ reg_value,
+ lines_count, mixer_in, mixer_out,
+ control->descriptor->base,
+ ALP222_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out));
+ #endif
+
+ reg_value |= ALP222_MIXER_GAIN_SEL(mixer_in, mixer_value);
+
+ break;
+ default:
+ //Nothing to do for others cards yet
+ return 0;
+ }
+
+
+
+ writel(reg_value, alpx_dev->base + offset);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new alpx_control_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+
+ .info = alpx_control_mixer_info,
+ .get = alpx_control_mixer_get,
+ .put = alpx_control_mixer_put,
+};
+
+static int alpx_control_mixer_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor,
+ unsigned int mixer_in,
+ unsigned int mixer_out)
+{
+ struct alpx_device* const alpx_dev = card->private_data;
+ const unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control* const control = &alpx_dev->controls[control_index];
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ const unsigned int lines_count = descriptor->data.mixer.lines_count;
+#endif
+ char name[64] = { 0 };
+ int ret;
+
+ control->descriptor = descriptor;
+ control->data.mixer.mixer_in = mixer_in;
+ control->data.mixer.mixer_out = mixer_out;
+
+ snprintf(name, sizeof(name), "%s %u/%u Playback Volume", descriptor->prefix,
+ mixer_in, mixer_out);
+
+ alpx_control_mixer.name = name;
+ alpx_control_mixer.private_value = control_index;
+ alpx_control_mixer.access = descriptor->access;
+ alpx_control_mixer.tlv.p = descriptor->data.mixer.gains_scale;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," creating mixer %s in controls[%u] linked to [0x%x:0x%x].\n",
+ name,
+ control_index,
+ control->descriptor->base,
+ ALP222_MIXER_GAIN_REG(lines_count, mixer_in, mixer_out));
+#endif
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_mixer, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+/* Field */
+
+static int alpx_control_choice_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor_choice *choice =
+ &control->descriptor->data.choice;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," Field %d entries.\n", choice->entries_count);
+#endif
+
+ return snd_ctl_enum_info(info, 1, choice->entries_count, choice->entries);
+}
+
+static int alpx_control_choice_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ u32 offset, value;
+ unsigned int i;
+
+ offset = control->descriptor->base +
+ control->descriptor->data.choice.offset;
+
+ value = readl(alpx_dev->base + offset);
+ value &= control->descriptor->data.choice.mask;
+ value >>= control->descriptor->data.choice.pos;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_info( alpx_dev->dev," GET[%d] 0x%x (0x%x)<= [0x%p:%x:%x]\n",
+ control_index,
+ value,
+ readl(alpx_dev->base + offset),
+ alpx_dev->base,
+ control->descriptor->base,
+ control->descriptor->data.choice.offset);
+#endif
+
+ for (i = 0; i < control->descriptor->data.choice.entries_count; i++) {
+ u32 entry_value =
+ control->descriptor->data.choice.entries_values[i];
+
+ if (value == entry_value) {
+ elem_value->value.enumerated.item[0] = i;
+
+ dev_info( alpx_dev->dev,"GET[%d]: Reg: %d => Sync[%d] (%s) \n",
+ control_index,
+ value,
+ i,
+ control->descriptor->data.translated_choice.entries[i]);
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int alpx_control_choice_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int index_value;
+ u32 offset, reg_value;
+
+ offset = control->descriptor->base +
+ control->descriptor->data.choice.offset;
+ reg_value = readl(alpx_dev->base + offset);
+
+ reg_value &= ~control->descriptor->data.choice.mask;
+
+ index_value = elem_value->value.enumerated.item[0];
+ reg_value |= control->descriptor->data.choice.entries_values[index_value] << control->descriptor->data.choice.pos ;
+
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_info( alpx_dev->dev,"PUT[%d] 0x%x ->([%d]0x%x) 0x%x => [0x%p:%x:%x]\n",
+ control_index,
+ readl(alpx_dev->base + offset),
+ index_value,
+ control->descriptor->data.choice.entries_values[index_value],
+ reg_value,
+ alpx_dev->base,
+ control->descriptor->base,
+ control->descriptor->data.choice.offset);
+#endif
+
+ dev_info( alpx_dev->dev,"PUT[%d]: Sync[%d] (%s) => Reg: %d\n",
+ control_index,
+ index_value,
+ control->descriptor->data.choice.entries[index_value],
+ control->descriptor->data.choice.entries_values[index_value]);
+
+ writel(reg_value, alpx_dev->base + offset);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new alpx_control_choice = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_choice_info,
+ .get = alpx_control_choice_get,
+ .put = alpx_control_choice_put,
+};
+
+static int alpx_control_choice_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret = 0;
+
+ control->descriptor = descriptor;
+
+ alpx_control_choice.name = descriptor->prefix;
+ alpx_control_choice.private_value = control_index;
+ alpx_control_choice.access = descriptor->access;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"registering CHOICE %s[%d]\n",
+ alpx_control_choice.name,
+ control_index);
+#endif
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_choice, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+/* Translated choice */
+
+
+static int alpx_control_translated_choice_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor_translated_choice *choice =
+ &control->descriptor->data.translated_choice;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," Field %d entries.\n", choice->entries_count);
+#endif
+
+ return snd_ctl_enum_info(info, 1, choice->entries_count, choice->entries);
+}
+
+static int alpx_control_translated_choice_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ u32 offset, value;
+
+ offset = control->descriptor->base +
+ control->descriptor->data.translated_choice.offset;
+
+ value = readl(alpx_dev->base + offset);
+ value &= control->descriptor->data.translated_choice.mask;
+ value >>= control->descriptor->data.translated_choice.pos;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," 0x%x (0x%x)<= [0x%p:%x:%x]\n",
+ value,
+ readl(alpx_dev->base + offset),
+ alpx_dev->base,
+ control->descriptor->base,
+ control->descriptor->data.translated_choice.offset);
+#endif
+
+
+ if (value < control->descriptor->data.translated_choice.card_entries_count) {
+ const unsigned int app_value = control->descriptor->data.translated_choice.card_entries_values[value];
+ dev_info( alpx_dev->dev,"GET[%d]: Reg: %d => %d: App Sync: %s \n",
+ control_index,
+ value,
+ app_value,
+ control->descriptor->data.translated_choice.entries[app_value]);
+ elem_value->value.enumerated.item[0] = app_value;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int alpx_control_translated_choice_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int index_value;
+ u32 offset, reg_value;
+
+ offset = control->descriptor->base +
+ control->descriptor->data.translated_choice.offset;
+ reg_value = readl(alpx_dev->base + offset);
+
+ reg_value &= ~control->descriptor->data.translated_choice.mask;
+
+ index_value = elem_value->value.enumerated.item[0];
+
+ //Avoid error :RESET the source if BUGGED !!
+ if (index_value >= control->descriptor->data.translated_choice.entries_count)
+ index_value = 0;
+
+ reg_value |= control->descriptor->data.translated_choice.entries_values[index_value] << control->descriptor->data.translated_choice.pos ;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"0x%x ->([%d]0x%x) 0x%x => [0x%p:%x:%x]\n",
+ readl(alpx_dev->base + offset),
+ index_value,
+ control->descriptor->data.translated_choice.entries_values[index_value],
+ reg_value,
+ alpx_dev->base,
+ control->descriptor->base,
+ control->descriptor->data.translated_choice.offset);
+#endif
+
+ dev_info( alpx_dev->dev,"PUT[%d]: App Sync[%d] (%s) => Reg: %d\n",
+ control_index,
+ index_value,
+ control->descriptor->data.translated_choice.entries[index_value],
+ control->descriptor->data.translated_choice.entries_values[index_value]);
+
+ //Avoid out of range values
+ if (control->descriptor->data.translated_choice.entries_values[index_value] <= ALP222_CLK_MANAGER_CLK_SRC_MAX) {
+ writel(reg_value, alpx_dev->base + offset);
+ }
+
+ return 1;
+}
+
+
+static struct snd_kcontrol_new alpx_control_translated_choice = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_translated_choice_info,
+ .get = alpx_control_translated_choice_get,
+ .put = alpx_control_translated_choice_put,
+};
+
+static int alpx_control_translated_choice_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret = 0;
+
+ control->descriptor = descriptor;
+
+ alpx_control_translated_choice.name = descriptor->prefix;
+ alpx_control_translated_choice.private_value = control_index;
+ alpx_control_translated_choice.access = descriptor->access;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"registering Translated CHOICE %s[%d]\n",
+ alpx_control_translated_choice.name,
+ control_index);
+#endif
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_translated_choice, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+/* Flags */
+static int alpx_control_flag_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor_choice *choice =
+ &control->descriptor->data.choice;
+
+ dev_dbg( alpx_dev->dev," Flag %d entries.\n", choice->entries_count);
+#endif
+
+ info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ info->count = 1;
+ info->value.integer.min = 0;
+ info->value.integer.max = 1;
+
+ return 0;
+}
+
+static int alpx_control_flag_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ u32 offset, value;
+
+ offset = control->descriptor->base +
+ control->descriptor->data.flag.offset;
+
+ value = readl(alpx_dev->base + offset);
+ value &= control->descriptor->data.flag.mask;
+ value >>= control->descriptor->data.flag.pos;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"0x%x (0x%x)<= [0x%p:%x:%x]\n",
+ value,
+ readl(alpx_dev->base + offset),
+ alpx_dev->base,
+ control->descriptor->base,
+ control->descriptor->data.flag.offset);
+#endif
+
+ elem_value->value.enumerated.item[0] = value;
+
+ return 0;
+}
+
+static int alpx_control_flag_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ unsigned int new_value;
+ u32 offset, reg_value;
+
+ offset = control->descriptor->base +
+ control->descriptor->data.flag.offset;
+ reg_value = readl(alpx_dev->base + offset);
+
+ reg_value &= ~control->descriptor->data.flag.mask;
+
+ new_value = elem_value->value.enumerated.item[0];
+ reg_value |= new_value << control->descriptor->data.flag.pos;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"0x%x -> 0x%x => [0x%p:%x:%x]\n",
+ readl(alpx_dev->base + offset),
+ reg_value,
+ alpx_dev->base,
+ control->descriptor->base,
+ control->descriptor->data.flag.offset);
+#endif
+
+ writel(reg_value, alpx_dev->base + offset);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new alpx_control_flag = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_flag_info,
+ .get = alpx_control_flag_get,
+ .put = alpx_control_flag_put,
+};
+
+
+static int alpx_control_flag_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ control->descriptor = descriptor;
+
+ alpx_control_flag.name = descriptor->prefix;
+ alpx_control_flag.private_value = control_index;
+ alpx_control_flag.access = descriptor->access;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_flag, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+/* Flags_channels */
+static struct alpx_control* alpx_lookup_codec_pga_control(struct alpx_device * alpx_dev, unsigned int side)
+{
+ //Lookup the LINE PGA associated to the given side
+ unsigned int ctrl_idx = 0;
+dev_dbg(alpx_dev->dev," alpx_dev->controls_count = %d, side:%d\n", alpx_dev->controls_count, side);
+
+ for (ctrl_idx = 0 ; ctrl_idx < (alpx_dev->controls_count - 1) ; ctrl_idx++) {
+ if ((alpx_dev->controls[ctrl_idx].descriptor->type == ALPX_CONTROL_TYPE_ANALOG_EQ) &&
+ (alpx_dev->controls[ctrl_idx].data.codec.idx == side)){
+ dev_dbg(alpx_dev->dev," found LINE EQ ctrl[%d]{%d: 0x%x:%x}\n",
+ ctrl_idx, alpx_dev->controls[ctrl_idx].data.codec.idx,
+ alpx_dev->controls[ctrl_idx].descriptor->base, ALPX_CODEC_CTRL_GAIN_REG(side));
+
+ //return alpx_dev->controls[ctrl_idx].descriptor->base + ALPX_CODEC_CTRL_GAIN_REG(side);
+ return &alpx_dev->controls[ctrl_idx];
+ }
+ }
+ dev_err(alpx_dev->dev," NOTHING FOUND\n");
+ return NULL;
+}
+
+
+static struct alpx_control* alpx_lookup_codec_mic_gain_control(struct alpx_device * alpx_dev, unsigned int pos)
+{
+ //Lookup the LINE PGA associated to the given side
+ unsigned int ctrl_idx = 0;
+dev_dbg(alpx_dev->dev," alpx_dev->controls_count = %d, pos:%d\n", alpx_dev->controls_count, pos);
+
+ for (ctrl_idx = 0 ; ctrl_idx < (alpx_dev->controls_count - 1) ; ctrl_idx++) {
+#if 0
+ dev_dbg(alpx_dev->dev,"idx:%d, descriptor : %p (%s), t:%d\n",
+ ctrl_idx,
+ &alpx_dev->controls[ctrl_idx].descriptor,
+ alpx_dev->controls[ctrl_idx].descriptor->prefix,
+ alpx_dev->controls[ctrl_idx].descriptor->type);
+#endif
+ if ((alpx_dev->controls[ctrl_idx].descriptor->type == ALPX_CONTROL_TYPE_GAINS_EMBEDDED) &&
+ (alpx_dev->controls[ctrl_idx].descriptor->data.mic_gains.pos == pos)){
+ dev_dbg(alpx_dev->dev," found MIC Gain ctrl[%d]{0x%x:%x}\n", ctrl_idx,
+ alpx_dev->controls[ctrl_idx].descriptor->base, alpx_dev->controls[ctrl_idx].descriptor->data.mic_gains.offset);
+
+ //return alpx_dev->controls[ctrl_idx].descriptor->base + alpx_dev->controls[ctrl_idx].descriptor->data.mic_gains.offset;
+ return &alpx_dev->controls[ctrl_idx];
+ }
+ }
+ dev_err(alpx_dev->dev,"NOTHING FOUND\n");
+ return NULL;
+}
+
+static void alpx_mic_handle_activate_change(struct alpx_device * alpx_dev, struct alpx_control * mic_control, u32 mic_pos, unsigned int is_mic_on)
+{
+ struct alpx_control* mic_gain_ctrl = NULL;
+ struct alpx_control* line_eq_gain_ctrl = NULL;
+ u32 line_codec_reg_offset = 0;
+ u32 mic_gain_offset;
+ u32 mic_gain_mask;
+ u32 line_side = 0;
+ u32 mic_side_pos = 0;
+
+
+ dev_dbg(alpx_dev->dev,"%s(%p, %p,%d,%d) : CALLED\n",__func__,
+ alpx_dev,
+ mic_control,
+ mic_pos,
+ is_mic_on);
+
+ //Find the right LINE PGA register
+ switch(mic_pos) {
+ case ALP222_MIC_EN_L_POS:
+ dev_dbg(alpx_dev->dev,"LEFT %s\n", is_mic_on ? "On" : "Off");
+ line_side = 0;
+ mic_side_pos = ALP222_MIC_GAIN_L_POS;
+ break;
+ case ALP222_MIC_EN_R_POS:
+ dev_dbg(alpx_dev->dev," RIGHT %s\n",is_mic_on ? "On" : "Off");
+ line_side = 1;
+ mic_side_pos = ALP222_MIC_GAIN_R_POS;
+ break;
+ default:
+ dev_dbg(alpx_dev->dev," Unknown mic position %d !!\n", mic_pos);
+ return;
+ };
+
+
+ line_eq_gain_ctrl = alpx_lookup_codec_pga_control(alpx_dev, line_side);
+ line_codec_reg_offset = line_eq_gain_ctrl->descriptor->base + ALPX_CODEC_CTRL_GAIN_REG(line_side);
+ mic_gain_ctrl = alpx_lookup_codec_mic_gain_control(alpx_dev, mic_side_pos);
+
+ if (line_eq_gain_ctrl == NULL){
+ dev_warn(alpx_dev->dev,"No line EQ ctrl found !\n");
+ return;
+ }
+
+ if ( mic_gain_ctrl == NULL){
+ dev_warn(alpx_dev->dev,"No MIC ctrl found !!\n");
+ return;
+ }
+
+ mic_gain_mask = mic_gain_ctrl->descriptor->data.mic_gains.mask;
+ mic_gain_offset = mic_gain_ctrl->descriptor->base + mic_gain_ctrl->descriptor->data.mic_gains.offset;
+
+
+ dev_dbg(alpx_dev->dev,"PGA offset :0x%x, MIC %s offset : 0x%x, MIC mask: 0x%08x\n",
+ line_codec_reg_offset,
+ mic_control->descriptor->prefix,
+ mic_gain_offset,
+ mic_gain_mask);
+
+#if 1
+ dev_dbg(alpx_dev->dev,"BEFORE MIC %s stored:0X%x, regMIC:0x%x, regPGA:0x%x\n",
+ is_mic_on ? "On" : "Off",
+ mic_control->data.mic.stored_gain_in_reg,
+ readl(alpx_dev->base + mic_gain_offset),
+ readl(alpx_dev->base + line_codec_reg_offset));
+
+ //Now handle the mute state change
+ if (is_mic_on == 0) {
+ //MIC is going to be MUTED
+ //restore the LINE gain and store the current MIC gain.
+ writel(mic_control->data.mic.stored_gain_in_reg, alpx_dev->base + line_codec_reg_offset);
+ mic_control->data.mic.stored_gain_in_reg = readl(alpx_dev->base + mic_gain_offset);
+ //MUTE with MIC with ZERO in gain
+ writel(mic_control->data.mic.stored_gain_in_reg & ~mic_gain_mask, alpx_dev->base + mic_gain_offset);
+ //Keep the gain only
+ mic_control->data.mic.stored_gain_in_reg &= mic_gain_mask;
+
+ } else {
+ //LINE is going to be MUTED
+ //Restore the MIC gain and store the line gain and MUTE line
+ u32 mic_reg_value = readl(alpx_dev->base + mic_gain_offset);
+ writel(mic_control->data.mic.stored_gain_in_reg | (mic_reg_value & ~mic_gain_mask), alpx_dev->base + mic_gain_offset);
+ mic_control->data.mic.stored_gain_in_reg = readl(alpx_dev->base + line_codec_reg_offset);
+ //MUTE LINE with 0 in LINE
+ writel(0, alpx_dev->base + line_codec_reg_offset);
+ }
+
+ dev_dbg(alpx_dev->dev," AFTER MIC %s stored: 0x%x, regMIC:0x%x, regPGA:0x%x\n",
+ is_mic_on ? "On" : "Off",
+ mic_control->data.mic.stored_gain_in_reg,
+ readl(alpx_dev->base + mic_gain_offset),
+ readl(alpx_dev->base + line_codec_reg_offset));
+#endif
+}
+
+static int alpx_control_flags_embedded_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor *control_desc = control->descriptor;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"Flags %d entries.\n", control_desc->data.mic_flags.lines_count);
+#endif
+
+ info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ info->count = 1; //One line per control
+ info->value.integer.min = 0;
+ info->value.integer.max = 1;
+ return 0;
+}
+
+static int alpx_control_flags_embedded_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor *control_desc = control->descriptor;
+ u32 offset, value;
+
+ /* read the composite register */
+ offset = control_desc->base +
+ control_desc->data.mic_flags.offset;
+
+ value = readl(alpx_dev->base + offset);
+
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"0x%x (0x%x)<= [0x%p:%x:%x]\n",
+ value,
+ readl(alpx_dev->base + offset),
+ alpx_dev->base,
+ control_desc->base,
+ control_desc->data.mic_flags.offset);
+#endif
+
+ elem_value->value.enumerated.item[0] = value & control_desc->data.mic_flags.mask;
+ elem_value->value.enumerated.item[0] >>= control_desc->data.mic_flags.pos;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"item[0]=%d\n",
+ elem_value->value.enumerated.item[0]);
+#endif
+
+ return 0;
+}
+
+static int alpx_control_flags_embedded_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor *control_desc = control->descriptor;
+ const unsigned int new_state = elem_value->value.enumerated.item[0];
+ const u32 offset = control_desc->base +
+ control_desc->data.mic_flags.offset;
+ u32 reg_value;
+ u32 current_state;
+
+
+ reg_value = readl(alpx_dev->base + offset);
+
+ dev_dbg(alpx_dev->dev," ctrl[%d]=>%p{name:%s pos:%d reg:0x%08x} : %d\n", control_index, control, control_desc->prefix, control_desc->data.mic_flags.pos, reg_value, new_state);
+
+ current_state = (reg_value & control_desc->data.mic_flags.mask) >> control_desc->data.mic_flags.pos;
+
+ if (current_state == new_state) {
+ dev_dbg(alpx_dev->dev,"EXIT W/O state change\n");
+ return 0;
+ }
+
+ //* SET the bit according to the associated line */
+ reg_value &= ~control_desc->data.mic_flags.mask;
+ reg_value |= new_state << control_desc->data.mic_flags.pos;
+ writel(reg_value, alpx_dev->base + offset);
+
+ //Handle the MUTE state transition Only for MIC enable/disable
+ if ((control_desc->data.mic_flags.pos == ALP222_MIC_EN_L_POS) ||
+ (control_desc->data.mic_flags.pos == ALP222_MIC_EN_R_POS)){
+ alpx_mic_handle_activate_change(alpx_dev, control,control_desc->data.mic_flags.pos, new_state);
+ }
+
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," item[0]=%d\n",
+ elem_value->value.enumerated.item[0]);
+ dev_dbg( alpx_dev->dev," 0x%x -> 0x%x => [0x%p:%x:%x]\n",
+ readl(alpx_dev->base + offset),
+ reg_value,
+ alpx_dev->base,
+ control_desc->base,
+ control_desc->data.mic_flags.offset);
+#endif
+
+ dev_dbg(alpx_dev->dev," EXIT\n");
+ return 1;
+}
+
+static struct snd_kcontrol_new alpx_control_flags_embedded = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_flags_embedded_info,
+ .get = alpx_control_flags_embedded_get,
+ .put = alpx_control_flags_embedded_put,
+};
+
+static int alpx_control_flags_embedded_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+
+ control->descriptor = descriptor;
+
+ alpx_control_flags_embedded.name = descriptor->prefix;
+ alpx_control_flags_embedded.private_value = control_index;
+ alpx_control_flags_embedded.access = descriptor->access;
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_flags_embedded, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ //Mut the MIC
+ alpx_mic_handle_activate_change(alpx_dev, control, descriptor->data.mic_flags.pos, 0);
+
+ return 0;
+}
+
+/* Gains mixed */
+
+static u32 alpx_mic_gain_db_to_reg (u32 db)
+{
+ /* Gain range is 10 to 65, skip special value 0*/
+ if (db <= ALP222_MIC_GAINS_MIN_REG_VAL){
+ return 1;
+ } else if (db < ALP222_MIC_GAINS_MAX_REG_VAL){
+ return db - ALP222_MIC_REG_GAIN_SHIFT;
+ } else {
+ return (ALP222_MIC_GAINS_MAX_REG_VAL + 1 - ALP222_MIC_REG_GAIN_SHIFT);
+ }
+}
+
+static u32 alpx_mic_gain_reg_to_db (u32 reg)
+{
+ /* Skip reg == 0 */
+ if (reg <= 1) {
+ return ALP222_MIC_GAINS_MIN_REG_VAL;
+ } else if (reg < (ALP222_MIC_GAINS_MAX_REG_VAL + 1 - ALP222_MIC_REG_GAIN_SHIFT)) {
+ return reg + ALP222_MIC_REG_GAIN_SHIFT;
+ } else {
+ return ALP222_MIC_GAINS_MAX_REG_VAL;
+ }
+}
+
+static int alpx_control_gains_embedded_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ struct alpx_control_descriptor *control_desc = control->descriptor;
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," Gains %d entries.\n", control_desc->data.mic_gains.lines_count);
+#endif
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1; //One control per item !
+ info->value.integer.min = control_desc->data.mic_gains.min;
+ info->value.integer.max = control_desc->data.mic_gains.max;
+
+ return 0;
+}
+
+static int alpx_control_gains_embedded_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ u32 offset, reg_value, raw_value;
+ struct alpx_control_descriptor *control_desc = control->descriptor;
+
+ /* read the composite register */
+ offset = control_desc->base + control_desc->data.mic_gains.offset;
+
+ reg_value = readl(alpx_dev->base + offset);
+
+
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev," 0x%x (0x%x)<= [0x%p:%x:%x]\n",
+ reg_value,
+ readl(alpx_dev->base + offset),
+ alpx_dev->base,
+ control_desc->base,
+ control_desc->data.mic_gains.offset);
+#endif
+ //* GET the bit according to the associated line */
+ raw_value = reg_value & (control_desc->data.mic_gains.mask);
+ raw_value >>= (control_desc->data.mic_gains.pos);
+ //Convert Raw value into dB
+ elem_value->value.integer.value[0] = alpx_mic_gain_reg_to_db(raw_value);
+
+ #if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"value[0]=%ld / raw: 0x%x\n",
+ elem_value->value.integer.value[0],
+ raw_value);
+#endif
+
+ return 0;
+}
+
+static int alpx_control_gains_embedded_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *elem_value)
+{
+ struct alpx_device *alpx_dev = snd_kcontrol_chip(kcontrol);
+ unsigned int control_index = kcontrol->private_value;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ const unsigned int new_value = alpx_mic_gain_db_to_reg(elem_value->value.integer.value[0]);
+ u32 offset, reg_value;
+ struct alpx_control_descriptor *control_desc = control->descriptor;
+
+ offset = control_desc->base +
+ control_desc->data.mic_gains.offset;
+ reg_value = readl(alpx_dev->base + offset);
+
+ //* SET the bit according to the associated line */
+ reg_value &= ~(control_desc->data.mic_gains.mask);
+ reg_value |= new_value << (control_desc->data.mic_gains.pos);
+
+
+
+
+#if defined(CONFIG_ALPX_LOG_CONTROLS)
+ dev_dbg( alpx_dev->dev,"value[0]=%ld, reg_value: 0x%x\n",
+ elem_value->value.integer.value[0],
+ reg_value );
+ dev_dbg( alpx_dev->dev,"0x%x -> 0x%x => [0x%p:%x:%x]\n",
+ readl(alpx_dev->base + offset),
+ reg_value,
+ alpx_dev->base,
+ control_desc->base,
+ control_desc->data.mic_gains.offset);
+#endif
+
+ writel(reg_value, alpx_dev->base + offset);
+
+
+ return 1;
+}
+
+
+static struct snd_kcontrol_new alpx_control_gains_embedded = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+
+ .info = alpx_control_gains_embedded_info,
+ .get = alpx_control_gains_embedded_get,
+ .put = alpx_control_gains_embedded_put,
+};
+
+static int alpx_control_gains_embedded_register(struct snd_card *card,
+ struct alpx_control_descriptor *alp_descriptor)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ unsigned int control_index = alpx_dev->controls_index;
+ struct alpx_control *control = &alpx_dev->controls[control_index];
+ int ret;
+ char name[64] = { 0 };
+ control->descriptor = alp_descriptor;
+
+ snprintf(name, sizeof(name), "%s Volume", alp_descriptor->prefix);
+
+ alpx_control_gains_embedded.name = name;
+ alpx_control_gains_embedded.private_value = control_index;
+ alpx_control_gains_embedded.access = alp_descriptor->access;
+ alpx_control_gains_embedded.tlv.p = alp_descriptor->data.mic_gains.gains_scale;
+
+
+ dev_dbg(alpx_dev->dev," mic: %s, gain offset : 0x%x, gains scale : %p\n",
+ name,
+ alp_descriptor->data.mic_gains.offset,
+ alp_descriptor->data.mic_gains.gains_scale);
+
+ ret = snd_ctl_add(card, snd_ctl_new1(&alpx_control_gains_embedded, alpx_dev));
+ if (ret)
+ return ret;
+
+ alpx_dev->controls_index++;
+
+ return 0;
+}
+
+/* Controls */
+
+static int alpx_controls_router_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < descriptor->data.router.lines_count; i++) {
+ ret = alpx_control_router_register(card, descriptor, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alpx_controls_mixer_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ unsigned int lines_count = descriptor->data.mixer.lines_count;
+ unsigned int i, o;
+ int ret;
+
+ for (o = 0; o < lines_count; o++) {
+ for (i = 0; i < lines_count; i++) {
+ ret = alpx_control_mixer_register(card, descriptor, i, o);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#if 0
+static int alpx_controls_gains_embedded_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ unsigned int lines_count = descriptor->data.mixer.lines_count;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; !ret && i < lines_count; i++) {
+ ret = alpx_control_gains_embedded_register(card, descriptor, i);
+ }
+
+ return ret;
+}
+
+static int alpx_controls_flags_embedded_register(struct snd_card *card,
+ struct alpx_control_descriptor *descriptor)
+{
+ unsigned int lines_count = descriptor->data.mixer.lines_count;
+ unsigned int i, o;
+ int ret = 0;
+
+ for (i = 0;!ret && i < lines_count; i++) {
+ ret = alpx_control_flags_embedded_register(card, descriptor, i, o);
+ }
+
+ return ret;
+}
+#endif
+
+
+/* AlpX Controls */
+int alpx_controls_register(struct snd_card *card)
+{
+ struct alpx_device *alpx_dev = card->private_data;
+ const struct alpx_variant *variant = alpx_dev->variant;
+ unsigned int controls_count = 0;
+ unsigned int i;
+ int ret;
+
+ dev_dbg(alpx_dev->dev, "Registering controls for %s\n", card->longname);
+
+ if (alpx_dev->controls)
+ return -EBUSY;
+
+ for (i = 0; i < variant->control_descriptors_count; i++) {
+ struct alpx_control_descriptor *descriptor =
+ &variant->control_descriptors[i];
+
+ switch (descriptor->type) {
+ case ALPX_CONTROL_TYPE_CHOICE:
+ case ALPX_CONTROL_TYPE_FLAG:
+ case ALPX_CONTROL_TYPE_TRANSLATED_CHOICE:
+ /* One control for each descriptor. */
+ controls_count++;
+ break;
+ case ALPX_CONTROL_TYPE_AMPLIFIER:
+ /* Amplified lines */
+ controls_count += descriptor->data.ampli.lines_count;
+ break;
+ case ALPX_CONTROL_TYPE_ROUTER:
+ /* One control for each router line. */
+ controls_count += descriptor->data.router.lines_count;
+ break;
+ case ALPX_CONTROL_TYPE_MIXER:
+ /* One control for each mixer line intersection. */
+ controls_count += descriptor->data.mixer.lines_count *
+ descriptor->data.mixer.lines_count;
+ break;
+ case ALPX_CONTROL_TYPE_ANALOG_EQ:
+ controls_count += descriptor->data.codec.lines_count;
+ break;
+ case ALPX_CONTROL_TYPE_GAINS_EMBEDDED:
+ controls_count += descriptor->data.mic_gains.lines_count;
+ break;
+ case ALPX_CONTROL_TYPE_FLAGS_EMBEDDED:
+ controls_count += descriptor->data.mic_flags.lines_count;
+ break;
+ case ALPX_CONTROL_RESERVED:
+ controls_count ++;
+ break;
+ case ALPX_CONTROL_TYPE_CONSTANT:
+ controls_count++;
+ break;
+ case ALPX_CONTROL_TYPE_AXCMEM_REL_CHOICE:
+ controls_count++;
+ break;
+ case ALPX_CONTROL_TYPE_AXCMEM_REL_VALUE:
+ controls_count++;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ alpx_dev->controls = kcalloc(controls_count,
+ sizeof(struct alpx_control), GFP_KERNEL);
+
+ if (!alpx_dev->controls)
+ return -ENOMEM;
+
+ alpx_dev->controls_count = controls_count;
+
+ dev_dbg(alpx_dev->dev," alpx_dev->controls_count = %d\n", alpx_dev->controls_count);
+
+ for (i = 0; i < variant->control_descriptors_count; i++) {
+ struct alpx_control_descriptor *alp_descriptor =
+ &variant->control_descriptors[i];
+
+ dev_dbg(alpx_dev->dev,"descriptor[%d]:{%d, %s}\n",
+ i, alp_descriptor->type, alp_descriptor->prefix);
+
+ switch (alp_descriptor->type) {
+ case ALPX_CONTROL_TYPE_AMPLIFIER:
+ ret = alpx_controls_amplifier_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_ANALOG_EQ:
+ ret = alpx_controls_codec_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_ROUTER:
+ ret = alpx_controls_router_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_MIXER:
+ ret = alpx_controls_mixer_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_CHOICE:
+ ret = alpx_control_choice_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_TRANSLATED_CHOICE:
+ ret = alpx_control_translated_choice_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_FLAG:
+ ret = alpx_control_flag_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_GAINS_EMBEDDED:
+ ret = alpx_control_gains_embedded_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_FLAGS_EMBEDDED:
+ ret = alpx_control_flags_embedded_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_RESERVED:
+ ret = alpx_control_reserved_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_CONSTANT:
+ ret = alpx_control_constant_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_AXCMEM_REL_CHOICE:
+ ret = alpx_control_axcmem_rel_choice_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ case ALPX_CONTROL_TYPE_AXCMEM_REL_VALUE:
+ ret = alpx_control_axcmem_rel_value_register(card, alp_descriptor);
+ if (ret)
+ return ret;
+ break;
+ }
+ }
+ return 0;
+}
+
+int alp222_mic_controls_default_config(struct alpx_device * alpx_dev)
+{
+ //By default CM is enabled and DC is disabled
+ uint32_t ctrl_reg = readl(alpx_dev->base + ALP222_CONTROL_BASE + ALP222_MIC_CONTROL_REG);
+
+ dev_dbg(alpx_dev->dev," mic::ctrl_reg[0x%08x:%x]=0x%08x\n",
+ ALP222_CONTROL_BASE, ALP222_MIC_CONTROL_REG,
+ readl(alpx_dev->base + ALP222_CONTROL_BASE + ALP222_MIC_CONTROL_REG));
+
+ //remove DC and CM bits
+ ctrl_reg &= ~(ALP222_MIC_DC_L_MASK | ALP222_MIC_DC_R_MASK);
+ ctrl_reg &= ~(ALP222_MIC_CM_L_MASK | ALP222_MIC_CM_R_MASK);
+
+ //Then set the default value, only CM
+ ctrl_reg |= (1<<ALP222_MIC_CM_L_POS) | (1<<ALP222_MIC_CM_R_POS);
+
+ writel(ctrl_reg, alpx_dev->base + ALP222_CONTROL_BASE + ALP222_MIC_CONTROL_REG);
+
+ dev_dbg(alpx_dev->dev," mic::ctrl_reg[0x%08x:%x]=0x%08x\n",
+ ALP222_CONTROL_BASE, ALP222_MIC_CONTROL_REG,
+ readl(alpx_dev->base + ALP222_CONTROL_BASE + ALP222_MIC_CONTROL_REG));
+
+ return 0;
+}