diff options
author | Christian Pointner <equinox@helsinki.at> | 2024-05-10 18:56:00 (GMT) |
---|---|---|
committer | Christian Pointner <equinox@helsinki.at> | 2024-05-10 18:56:00 (GMT) |
commit | af6bfbbd2496b1f5aa02b94caff4e6f988fa32c9 (patch) | |
tree | 45bebb68a0bf3bfc2fff1646f6fa0f4b976fba57 /snd-alpx-dkms/snd-alpx/alpx_controls.c | |
parent | 7035064ca063fdf15669ceb790ecef1e5ed054b0 (diff) |
rename package to snd-alpx-dkms
Diffstat (limited to 'snd-alpx-dkms/snd-alpx/alpx_controls.c')
-rw-r--r-- | snd-alpx-dkms/snd-alpx/alpx_controls.c | 2096 |
1 files changed, 2096 insertions, 0 deletions
diff --git a/snd-alpx-dkms/snd-alpx/alpx_controls.c b/snd-alpx-dkms/snd-alpx/alpx_controls.c new file mode 100644 index 0000000..397fe99 --- /dev/null +++ b/snd-alpx-dkms/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; +} |