ASoC: tegra-alt: Add get/put handlers for T210 xbar

Bug 1442940

Change-Id: I633c144a4f22b1c9d41f656a47331358b46d43d7
Signed-off-by: Arun Shamanna Lakshmi <aruns@nvidia.com>
Reviewed-on: http://git-master/r/412204
Reviewed-by: Songhee Baek <sbaek@nvidia.com>
Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com>
This commit is contained in:
Arun Shamanna Lakshmi
2014-05-20 12:25:18 -07:00
committed by Sameer Pujar
parent 1ce137c34c
commit d9c7333753

View File

@@ -297,22 +297,131 @@ static const int tegra210_xbar_mux_values[] = {
/* index 35..53 above are inputs of PART2 Mux */ /* index 35..53 above are inputs of PART2 Mux */
}; };
#define MUX0_REG(id) (TEGRA210_XBAR_PART0_RX + \ int tegra210_xbar_get_value_enum(struct snd_kcontrol *kcontrol,
(TEGRA210_XBAR_RX_STRIDE * (id))) struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg_count, reg_val, val, bit_pos = 0, i;
unsigned int reg[TEGRA210_XBAR_UPDATE_MAX_REG];
#define MUX1_REG(id) (TEGRA210_XBAR_PART1_RX + \ reg_count = xbar->soc_data->reg_count;
(TEGRA210_XBAR_RX_STRIDE * (id)))
#define MUX2_REG(id) (TEGRA210_XBAR_PART2_RX + \ if (reg_count > TEGRA210_XBAR_UPDATE_MAX_REG)
(TEGRA210_XBAR_RX_STRIDE * (id))) return -EINVAL;
for (i = 0; i < reg_count; i++) {
reg[i] = (e->reg +
xbar->soc_data->reg_offset * i);
reg_val = snd_soc_read(codec, reg[i]);
val = reg_val & xbar->soc_data->mask[i];
if (val != 0) {
bit_pos = ffs(val) + (8 * codec->val_bytes * i);
break;
}
}
for (i = 0; i < e->max; i++) {
if (bit_pos == e->values[i]) {
ucontrol->value.enumerated.item[0] = i;
break;
}
}
return 0;
}
int tegra210_xbar_put_value_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
unsigned int change = 0, reg_idx = 0, value, *mask, bit_pos = 0;
unsigned int i, wi, reg_count, reg_val = 0, update_idx = 0;
unsigned int reg[TEGRA210_XBAR_UPDATE_MAX_REG];
struct snd_soc_dapm_update update[TEGRA210_XBAR_UPDATE_MAX_REG];
/* initialize the reg_count and mask from soc_data */
reg_count = xbar->soc_data->reg_count;
mask = (unsigned int *)xbar->soc_data->mask;
if (item[0] >= e->max || reg_count > TEGRA210_XBAR_UPDATE_MAX_REG)
return -EINVAL;
value = e->values[item[0]];
if (value) {
/* get the register index and value to set */
reg_idx = (value - 1) / (8 * codec->val_bytes);
bit_pos = (value - 1) % (8 * codec->val_bytes);
reg_val = BIT(bit_pos);
}
for (i = 0; i < reg_count; i++) {
reg[i] = e->reg + xbar->soc_data->reg_offset * i;
if (i == reg_idx) {
change |= snd_soc_test_bits(codec, reg[i],
mask[i], reg_val);
/* set the selected register */
update[reg_count - 1].reg = reg[reg_idx];
update[reg_count - 1].mask = mask[reg_idx];
update[reg_count - 1].val = reg_val;
} else {
/* accumulate the change to update the DAPM path
when none is selected */
change |= snd_soc_test_bits(codec, reg[i],
mask[i], 0);
/* clear the register when not selected */
update[update_idx].reg = reg[i];
update[update_idx].mask = mask[i];
update[update_idx++].val = 0;
}
}
/* power the widgets */
if (change) {
for (wi = 0; wi < wlist->num_widgets; wi++) {
widget = wlist->widgets[wi];
widget->value = reg_val;
for (i = 0; i < reg_count; i++) {
update[i].kcontrol = kcontrol;
update[i].widget = widget;
widget->dapm->update = &update[i];
snd_soc_dapm_mux_update_power(widget,
kcontrol, item[0], e);
widget->dapm->update = NULL;
}
}
}
return change;
}
#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id))
#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues) \
{ .reg = xreg, .shift_l = shift, .shift_r = shift, \
.max = xmax, .texts = xtexts, .values = xvalues, \
.mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0}
#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, \
xtexts, xvalues) \
struct soc_enum name = SOC_VALUE_ENUM_WIDE(xreg, shift, \
ARRAY_SIZE(xtexts), xtexts, xvalues)
#define MUX_ENUM_CTRL_DECL(ename, id) \ #define MUX_ENUM_CTRL_DECL(ename, id) \
int ename##_regs[3] = { MUX0_REG(id), MUX1_REG(id), MUX2_REG(id) }; \ SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \
unsigned int ename##_masks[3] = { 0xf1f03ff, 0x3f30031f, 0xff1cf313 }; \
SOC_VALUE_ENUM_ONEHOT_DECL(ename##_enum, ename##_regs, ename##_masks, 3, \
tegra210_xbar_mux_texts, tegra210_xbar_mux_values); \ tegra210_xbar_mux_texts, tegra210_xbar_mux_values); \
static const struct snd_kcontrol_new ename##_control = \ static const struct snd_kcontrol_new ename##_control = \
SOC_DAPM_ENUM_ONEHOT("Route", ename##_enum) SOC_DAPM_ENUM_EXT("Route", ename##_enum,\
tegra210_xbar_get_value_enum,\
tegra210_xbar_put_value_enum)
MUX_ENUM_CTRL_DECL(admaif1_tx, 0x00); MUX_ENUM_CTRL_DECL(admaif1_tx, 0x00);
MUX_ENUM_CTRL_DECL(admaif2_tx, 0x01); MUX_ENUM_CTRL_DECL(admaif2_tx, 0x01);
@@ -600,6 +709,11 @@ static struct snd_soc_codec_driver tegra210_xbar_codec = {
static const struct tegra210_xbar_soc_data soc_data_tegra210 = { static const struct tegra210_xbar_soc_data soc_data_tegra210 = {
.regmap_config = &tegra210_xbar_regmap_config, .regmap_config = &tegra210_xbar_regmap_config,
.mask[0] = 0xf1f03ff,
.mask[1] = 0x3f30031f,
.mask[2] = 0xff1cf313,
.reg_count = 3,
.reg_offset = TEGRA210_XBAR_PART1_RX,
}; };
static const struct of_device_id tegra210_xbar_of_match[] = { static const struct of_device_id tegra210_xbar_of_match[] = {