// 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 #include #include #include /* 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<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; }