blob: b69411783a456000eec58f68245b54b1816800f9 [file] [log] [blame]
/*
* arizona.c - Wolfson Arizona class device shared support
*
* Copyright 2014 Cirrus Logic
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/registers.h>
#include "arizona.h"
#define ARIZONA_AIF_BCLK_CTRL 0x00
#define ARIZONA_AIF_TX_PIN_CTRL 0x01
#define ARIZONA_AIF_RX_PIN_CTRL 0x02
#define ARIZONA_AIF_RATE_CTRL 0x03
#define ARIZONA_AIF_FORMAT 0x04
#define ARIZONA_AIF_TX_BCLK_RATE 0x05
#define ARIZONA_AIF_RX_BCLK_RATE 0x06
#define ARIZONA_AIF_FRAME_CTRL_1 0x07
#define ARIZONA_AIF_FRAME_CTRL_2 0x08
#define ARIZONA_AIF_FRAME_CTRL_3 0x09
#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
#define ARIZONA_AIF_FRAME_CTRL_10 0x10
#define ARIZONA_AIF_FRAME_CTRL_11 0x11
#define ARIZONA_AIF_FRAME_CTRL_12 0x12
#define ARIZONA_AIF_FRAME_CTRL_13 0x13
#define ARIZONA_AIF_FRAME_CTRL_14 0x14
#define ARIZONA_AIF_FRAME_CTRL_15 0x15
#define ARIZONA_AIF_FRAME_CTRL_16 0x16
#define ARIZONA_AIF_FRAME_CTRL_17 0x17
#define ARIZONA_AIF_FRAME_CTRL_18 0x18
#define ARIZONA_AIF_TX_ENABLES 0x19
#define ARIZONA_AIF_RX_ENABLES 0x1A
#define ARIZONA_AIF_FORCE_WRITE 0x1B
#define ARIZONA_FLL_VCO_CORNER 141900000
#define ARIZONA_FLL_MAX_FREF 13500000
#define ARIZONA_FLL_MAX_N 1023
#define ARIZONA_FLLAO_MAX_FREF 12288000
#define ARIZONA_FLLAO_MIN_N 4
#define ARIZONA_FLLAO_MAX_N 1023
#define ARIZONA_FLLAO_MAX_FBDIV 254
#define ARIZONA_FLL_MIN_FVCO 90000000
#define ARIZONA_FLL_MAX_FRATIO 16
#define ARIZONA_FLL_MAX_REFDIV 8
#define ARIZONA_FLL_MIN_OUTDIV 2
#define ARIZONA_FLL_MAX_OUTDIV 7
#define ARIZONA_FLL_SYNC_OFFSET 0x10
#define ARIZONA_FMT_DSP_MODE_A 0
#define ARIZONA_FMT_DSP_MODE_B 1
#define ARIZONA_FMT_I2S_MODE 2
#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
#define arizona_fll_err(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_warn(_fll, fmt, ...) \
dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_dbg(_fll, fmt, ...) \
dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_aif_err(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_warn(_dai, fmt, ...) \
dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_dbg(_dai, fmt, ...) \
dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
static const int arizona_aif1_inputs[32] = {
ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE,
ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE,
ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE,
ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE,
ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE,
};
static const int arizona_aif2_inputs[32] = {
ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX7MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX7MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX7MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX7MIX_INPUT_4_SOURCE,
ARIZONA_AIF2TX8MIX_INPUT_1_SOURCE,
ARIZONA_AIF2TX8MIX_INPUT_2_SOURCE,
ARIZONA_AIF2TX8MIX_INPUT_3_SOURCE,
ARIZONA_AIF2TX8MIX_INPUT_4_SOURCE,
};
static const int arizona_aif3_inputs[8] = {
ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE,
ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE,
ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE,
ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE,
ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE,
ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE,
ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE,
ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE,
};
static const int arizona_aif4_inputs[8] = {
ARIZONA_AIF4TX1MIX_INPUT_1_SOURCE,
ARIZONA_AIF4TX1MIX_INPUT_2_SOURCE,
ARIZONA_AIF4TX1MIX_INPUT_3_SOURCE,
ARIZONA_AIF4TX1MIX_INPUT_4_SOURCE,
ARIZONA_AIF4TX2MIX_INPUT_1_SOURCE,
ARIZONA_AIF4TX2MIX_INPUT_2_SOURCE,
ARIZONA_AIF4TX2MIX_INPUT_3_SOURCE,
ARIZONA_AIF4TX2MIX_INPUT_4_SOURCE,
};
static unsigned int arizona_aif_sources_cache[ARRAY_SIZE(arizona_aif1_inputs)];
static const struct reg_sequence fll_ao_32K_patch[] = {
{ MOON_FLLAO_CONTROL_11, 0x0085 },
{ MOON_FLLAO_CONTROL_10, 0x06DA },
{ MOON_FLLAO_CONTROL_8, 0x0077 },
{ MOON_FLLAO_CONTROL_6, 0x8001 },
};
static int arizona_get_sources(struct arizona *arizona,
struct snd_soc_dai *dai,
const int **source, int *lim)
{
int ret = 0;
*lim = dai->driver->playback.channels_max * 4;
switch (dai->driver->base) {
case ARIZONA_AIF1_BCLK_CTRL:
*source = arizona_aif1_inputs;
break;
case ARIZONA_AIF2_BCLK_CTRL:
*source = arizona_aif2_inputs;
break;
case ARIZONA_AIF3_BCLK_CTRL:
*source = arizona_aif3_inputs;
break;
case ARIZONA_AIF4_BCLK_CTRL:
*source = arizona_aif4_inputs;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
int arizona_cache_and_clear_sources(struct arizona *arizona,
const int *sources,
unsigned int *cache,
int lim)
{
int ret = 0;
int i;
for (i = 0; i < lim; i++)
cache[i] = 0;
for (i = 0; i < lim; i++) {
ret = regmap_read(arizona->regmap,
sources[i],
&cache[i]);
dev_dbg(arizona->dev,
"%s addr: 0x%04x value: 0x%04x\n",
__func__, sources[i], cache[i]);
if (ret != 0) {
dev_err(arizona->dev,
"%s Failed to cache AIF:0x%04x inputs: %d\n",
__func__, sources[i], ret);
break;
}
ret = regmap_write(arizona->regmap,
sources[i],
0);
if (ret != 0) {
dev_err(arizona->dev,
"%s Failed to clear AIF:0x%04x inputs: %d\n",
__func__, sources[i], ret);
break;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(arizona_cache_and_clear_sources);
void clearwater_spin_sysclk(struct arizona *arizona)
{
unsigned int val;
int ret, i;
/* Skip this if the chip is down */
if (pm_runtime_suspended(arizona->dev))
return;
/*
* Just read a register a few times to ensure the internal
* oscillator sends out a few clocks.
*/
for (i = 0; i < 4; i++) {
ret = regmap_read(arizona->regmap,
ARIZONA_SOFTWARE_RESET,
&val);
if (ret != 0)
dev_err(arizona->dev,
"%s Failed to read register: %d (%d)\n",
__func__, ret, i);
}
}
EXPORT_SYMBOL_GPL(clearwater_spin_sysclk);
int arizona_restore_sources(struct arizona *arizona,
const int *sources,
unsigned int *cache,
int lim)
{
int ret = 0;
int i;
for (i = 0; i < lim; i++) {
dev_dbg(arizona->dev,
"%s addr: 0x%04x value: 0x%04x\n",
__func__, sources[i], cache[i]);
ret = regmap_write(arizona->regmap,
sources[i],
cache[i]);
if (ret != 0) {
dev_err(arizona->dev,
"%s Failed to restore AIF:0x%04x inputs: %d\n",
__func__, sources[i], ret);
break;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(arizona_restore_sources);
static int vegas_spk_pre_enable(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
unsigned int mute_reg, mute_mask, thr2_mask;
switch (w->shift) {
case ARIZONA_OUT4L_ENA_SHIFT:
mute_reg = ARIZONA_DAC_DIGITAL_VOLUME_4L;
mute_mask = ARIZONA_OUT4L_MUTE_MASK;
thr2_mask = CLEARWATER_EDRE_OUT4L_THR2_ENA_MASK;
break;
case ARIZONA_OUT4R_ENA_SHIFT:
mute_reg = ARIZONA_DAC_DIGITAL_VOLUME_4R;
mute_mask = ARIZONA_OUT4R_MUTE_MASK;
thr2_mask = CLEARWATER_EDRE_OUT4R_THR2_ENA_MASK;
break;
default:
return 0;
}
/* mute to prevent pops */
priv->spk_mute_cache &= ~mute_mask;
priv->spk_mute_cache |= snd_soc_read(codec, mute_reg) & mute_mask;
snd_soc_update_bits(codec, mute_reg, mute_mask, mute_mask);
/* disable thr2 while we enable */
priv->spk_thr2_cache &= ~thr2_mask;
priv->spk_thr2_cache |=
snd_soc_read(codec, CLEARWATER_EDRE_ENABLE) & thr2_mask;
snd_soc_update_bits(codec, CLEARWATER_EDRE_ENABLE, thr2_mask,
0);
return 0;
}
static int vegas_spk_post_enable(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
unsigned int mute_reg, mute_mask, thr1_mask, thr2_mask, val;
switch (w->shift) {
case ARIZONA_OUT4L_ENA_SHIFT:
mute_reg = ARIZONA_DAC_DIGITAL_VOLUME_4L;
mute_mask = ARIZONA_OUT4L_MUTE_MASK;
thr1_mask = CLEARWATER_EDRE_OUT4L_THR1_ENA_MASK;
thr2_mask = CLEARWATER_EDRE_OUT4L_THR2_ENA_MASK;
break;
case ARIZONA_OUT4R_ENA_SHIFT:
mute_reg = ARIZONA_DAC_DIGITAL_VOLUME_4R;
mute_mask = ARIZONA_OUT4R_MUTE_MASK;
thr1_mask = CLEARWATER_EDRE_OUT4R_THR1_ENA_MASK;
thr2_mask = CLEARWATER_EDRE_OUT4R_THR2_ENA_MASK;
break;
default:
return 0;
}
/* write sequencer sets OUT4R_THR2_ENA - update cache */
snd_soc_update_bits(codec, CLEARWATER_EDRE_ENABLE, thr2_mask, thr2_mask);
/* restore THR2 to what it was at the start of the sequence */
snd_soc_update_bits(codec, CLEARWATER_EDRE_ENABLE, thr2_mask,
priv->spk_thr2_cache);
/* disable THR2 if THR1 disabled */
val = snd_soc_read(codec, CLEARWATER_EDRE_ENABLE);
if ((val & thr1_mask) == 0)
snd_soc_update_bits(codec, CLEARWATER_EDRE_ENABLE, thr2_mask, 0);
/* restore mute state */
snd_soc_update_bits(codec, mute_reg, mute_mask, priv->spk_mute_cache);
return 0;
}
static int vegas_spk_post_disable(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
unsigned int thr2_mask;
switch (w->shift) {
case ARIZONA_OUT4L_ENA_SHIFT:
thr2_mask = CLEARWATER_EDRE_OUT4L_THR2_ENA_MASK;
break;
case ARIZONA_OUT4R_ENA_SHIFT:
thr2_mask = CLEARWATER_EDRE_OUT4R_THR2_ENA_MASK;
break;
default:
return 0;
}
/* Read the current value of THR2 in to the cache so we can restore
* it after the write sequencer has executed
*/
priv->spk_thr2_cache &= ~thr2_mask;
priv->spk_thr2_cache |=
snd_soc_read(codec, CLEARWATER_EDRE_ENABLE) & thr2_mask;
/* write sequencer clears OUT4R_THR2_ENA - update cache */
snd_soc_update_bits(codec, CLEARWATER_EDRE_ENABLE, thr2_mask, 0);
/* Restore the previous value after the write sequencer update */
snd_soc_update_bits(codec, CLEARWATER_EDRE_ENABLE, thr2_mask,
priv->spk_thr2_cache);
return 0;
}
static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
int val;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
switch (arizona->type) {
case WM8998:
case WM1814:
vegas_spk_pre_enable(w, kcontrol, event);
break;
default:
break;
}
break;
case SND_SOC_DAPM_POST_PMU:
val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
if (val & ARIZONA_SPK_OVERHEAT_STS) {
dev_crit(arizona->dev,
"Speaker not enabled due to temperature\n");
return -EBUSY;
}
snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
1 << w->shift, 1 << w->shift);
switch (arizona->type) {
case WM8280:
case WM5110:
case WM1831:
case CS47L24:
msleep(10);
break;
case WM8998:
case WM1814:
msleep(10); /* wait for wseq to end */
vegas_spk_post_enable(w, kcontrol, event);
break;
default:
break;
};
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
1 << w->shift, 0);
break;
case SND_SOC_DAPM_POST_PMD:
switch (arizona->type) {
case WM8998:
case WM1814:
msleep(5); /* wait for wseq to end */
vegas_spk_post_disable(w, kcontrol, event);
break;
default:
break;
}
break;
}
return 0;
}
static irqreturn_t arizona_thermal_warn(int irq, void *data)
{
struct arizona *arizona = data;
unsigned int val;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
&val);
if (ret != 0) {
dev_err(arizona->dev, "Failed to read thermal status: %d\n",
ret);
} else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
dev_crit(arizona->dev, "Thermal warning\n");
}
return IRQ_HANDLED;
}
static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
{
struct arizona *arizona = data;
unsigned int val;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
&val);
if (ret != 0) {
dev_err(arizona->dev, "Failed to read thermal status: %d\n",
ret);
} else if (val & ARIZONA_SPK_OVERHEAT_STS) {
dev_crit(arizona->dev, "Thermal shutdown\n");
ret = regmap_update_bits(arizona->regmap,
ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT4L_ENA |
ARIZONA_OUT4R_ENA, 0);
if (ret != 0)
dev_crit(arizona->dev,
"Failed to disable speaker outputs: %d\n",
ret);
}
return IRQ_HANDLED;
}
static const struct snd_soc_dapm_widget arizona_spkl =
SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU);
static const struct snd_soc_dapm_widget arizona_spkr =
SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU);
int arizona_init_spk(struct snd_soc_codec *codec)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
if (ret != 0)
return ret;
switch (arizona->type) {
case WM8997:
case WM1831:
case CS47L24:
case CS47L35:
break;
default:
ret = snd_soc_dapm_new_controls(&codec->dapm,
&arizona_spkr, 1);
if (ret != 0)
return ret;
break;
}
ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
"Thermal warning", arizona_thermal_warn,
arizona);
if (ret != 0)
dev_err(arizona->dev,
"Failed to get thermal warning IRQ: %d\n",
ret);
ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
"Thermal shutdown", arizona_thermal_shutdown,
arizona);
if (ret != 0)
dev_err(arizona->dev,
"Failed to get thermal shutdown IRQ: %d\n",
ret);
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_spk);
int arizona_mux_put(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 snd_soc_card *card = codec->card;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mask;
int ret;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
ret = widget->power_check(widget);
if (ret) {
val = e->values[ucontrol->value.enumerated.item[0]];
val <<= e->shift_l;
mask = e->mask << e->shift_l;
mutex_lock(&arizona->rate_lock);
snd_soc_update_bits(codec, e->reg, mask, val);
mutex_unlock(&arizona->rate_lock);
}
mutex_unlock(&card->dapm_mutex);
return snd_soc_dapm_put_enum_virt(kcontrol, ucontrol);
}
EXPORT_SYMBOL_GPL(arizona_mux_put);
int arizona_mux_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct soc_enum *e;
unsigned int val, mask;
int ret;
e = (struct soc_enum *)w->kcontrols[0]->private_value;
mask = e->mask << e->shift_l;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
val = e->values[w->value] << e->shift_l;
break;
case SND_SOC_DAPM_PRE_PMD:
val = 0;
break;
default:
return -EINVAL;
}
mutex_lock(&arizona->rate_lock);
ret = regmap_update_bits(arizona->regmap, e->reg, mask, val);
mutex_unlock(&arizona->rate_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_mux_event);
int arizona_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
unsigned int v ;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev,
"Failed to read SYSCLK state: %d\n", ret);
return -EIO;
}
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
return wm_adsp2_early_event(w, kcontrol, event, v);
}
EXPORT_SYMBOL_GPL(arizona_adsp_power_ev);
static const struct snd_soc_dapm_route arizona_mono_routes[] = {
{ "OUT1R", NULL, "OUT1L" },
{ "OUT2R", NULL, "OUT2L" },
{ "OUT3R", NULL, "OUT3L" },
{ "OUT4R", NULL, "OUT4L" },
{ "OUT5R", NULL, "OUT5L" },
{ "OUT6R", NULL, "OUT6L" },
};
int arizona_init_mono(struct snd_soc_codec *codec)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int i;
for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
if (arizona->pdata.out_mono[i])
snd_soc_dapm_add_routes(&codec->dapm,
&arizona_mono_routes[i], 1);
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_mono);
static const char * const arizona_dmic_refs[] = {
"MICVDD",
"MICBIAS1",
"MICBIAS2",
"MICBIAS3",
};
static const char * const marley_dmic_refs[] = {
"MICVDD",
"MICBIAS1B",
"MICBIAS2A",
"MICBIAS2B",
};
static const char * const arizona_dmic_inputs[] = {
"IN1L",
"IN1R",
"IN2L",
"IN2R",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
};
static const char * const clearwater_dmic_inputs[] = {
"IN1L Mux",
"IN1R",
"IN2L Mux",
"IN2R Mux",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
"IN5L",
"IN5R",
"IN6L",
"IN6R",
};
static const char * const marley_dmic_inputs[] = {
"IN1L Mux",
"IN1R Mux",
"IN2L",
"IN2R",
};
static const char * const moon_dmic_inputs[] = {
"IN1L Mux",
"IN1R Mux",
"IN2L Mux",
"IN2R",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
"IN5L",
"IN5R",
};
int arizona_init_input(struct snd_soc_codec *codec)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
struct arizona_pdata *pdata = &arizona->pdata;
int i, ret;
struct snd_soc_dapm_route routes[2];
memset(&routes, 0, sizeof(routes));
for (i = 0; i < priv->num_inputs / 2; ++i) {
switch (arizona->type) {
case CS47L35:
routes[0].source = marley_dmic_refs[pdata->dmic_ref[i]];
routes[1].source = marley_dmic_refs[pdata->dmic_ref[i]];
break;
default:
routes[0].source =
arizona_dmic_refs[pdata->dmic_ref[i]];
routes[1].source =
arizona_dmic_refs[pdata->dmic_ref[i]];
break;
}
switch (arizona->type) {
case WM5102:
case WM5110:
case WM8997:
case WM8280:
case WM8998:
case WM1814:
case WM1831:
case CS47L24:
routes[0].sink = arizona_dmic_inputs[i * 2];
routes[1].sink = arizona_dmic_inputs[(i * 2) + 1];
break;
case WM8285:
case WM1840:
routes[0].sink = clearwater_dmic_inputs[i * 2];
routes[1].sink = clearwater_dmic_inputs[(i * 2) + 1];
break;
case CS47L35:
routes[0].sink = marley_dmic_inputs[i * 2];
routes[1].sink = marley_dmic_inputs[(i * 2) + 1];
break;
default:
routes[0].sink = moon_dmic_inputs[i * 2];
routes[1].sink = moon_dmic_inputs[(i * 2) + 1];
break;
}
ret = snd_soc_dapm_add_routes(&codec->dapm, routes, 2);
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_input);
int arizona_init_gpio(struct snd_soc_codec *codec)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int i;
mutex_lock(&codec->card->dapm_mutex);
switch (arizona->type) {
case WM8280:
case WM5110:
case WM1831:
case CS47L24:
snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
break;
default:
break;
}
snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
snd_soc_dapm_enable_pin(&codec->dapm,
"DRC1 Signal Activity");
break;
case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
snd_soc_dapm_enable_pin(&codec->dapm,
"DRC2 Signal Activity");
break;
default:
break;
}
}
mutex_unlock(&codec->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_gpio);
const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
"Tone Generator 1",
"Tone Generator 2",
"Haptics",
"AEC",
"AEC2",
"Mic Mute Mixer",
"Noise Generator",
"IN1L",
"IN1R",
"IN2L",
"IN2R",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
"IN5L",
"IN5R",
"IN6L",
"IN6R",
"AIF1RX1",
"AIF1RX2",
"AIF1RX3",
"AIF1RX4",
"AIF1RX5",
"AIF1RX6",
"AIF1RX7",
"AIF1RX8",
"AIF2RX1",
"AIF2RX2",
"AIF2RX3",
"AIF2RX4",
"AIF2RX5",
"AIF2RX6",
"AIF2RX7",
"AIF2RX8",
"AIF3RX1",
"AIF3RX2",
"AIF4RX1",
"AIF4RX2",
"SLIMRX1",
"SLIMRX2",
"SLIMRX3",
"SLIMRX4",
"SLIMRX5",
"SLIMRX6",
"SLIMRX7",
"SLIMRX8",
"EQ1",
"EQ2",
"EQ3",
"EQ4",
"DRC1L",
"DRC1R",
"DRC2L",
"DRC2R",
"LHPF1",
"LHPF2",
"LHPF3",
"LHPF4",
"DSP1.1",
"DSP1.2",
"DSP1.3",
"DSP1.4",
"DSP1.5",
"DSP1.6",
"DSP2.1",
"DSP2.2",
"DSP2.3",
"DSP2.4",
"DSP2.5",
"DSP2.6",
"DSP3.1",
"DSP3.2",
"DSP3.3",
"DSP3.4",
"DSP3.5",
"DSP3.6",
"DSP4.1",
"DSP4.2",
"DSP4.3",
"DSP4.4",
"DSP4.5",
"DSP4.6",
"DSP5.1",
"DSP5.2",
"DSP5.3",
"DSP5.4",
"DSP5.5",
"DSP5.6",
"DSP6.1",
"DSP6.2",
"DSP6.3",
"DSP6.4",
"DSP6.5",
"DSP6.6",
"DSP7.1",
"DSP7.2",
"DSP7.3",
"DSP7.4",
"DSP7.5",
"DSP7.6",
"ASRC1L",
"ASRC1R",
"ASRC2L",
"ASRC2R",
"ISRC1INT1",
"ISRC1INT2",
"ISRC1INT3",
"ISRC1INT4",
"ISRC1DEC1",
"ISRC1DEC2",
"ISRC1DEC3",
"ISRC1DEC4",
"ISRC2INT1",
"ISRC2INT2",
"ISRC2INT3",
"ISRC2INT4",
"ISRC2DEC1",
"ISRC2DEC2",
"ISRC2DEC3",
"ISRC2DEC4",
"ISRC3INT1",
"ISRC3INT2",
"ISRC3INT3",
"ISRC3INT4",
"ISRC3DEC1",
"ISRC3DEC2",
"ISRC3DEC3",
"ISRC3DEC4",
"ISRC4INT1",
"ISRC4INT2",
"ISRC4DEC1",
"ISRC4DEC2",
};
EXPORT_SYMBOL_GPL(arizona_mixer_texts);
unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x00, /* None */
0x04, /* Tone */
0x05,
0x06, /* Haptics */
0x08, /* AEC */
0x09, /* AEC2 */
0x0c, /* Noise mixer */
0x0d, /* Comfort noise */
0x10, /* IN1L */
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x18,
0x19,
0x1A,
0x1B,
0x20, /* AIF1RX1 */
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28, /* AIF2RX1 */
0x29,
0x2a,
0x2b,
0x2c,
0x2d,
0x2e,
0x2f,
0x30, /* AIF3RX1 */
0x31,
0x34, /* AIF4RX1 */
0x35,
0x38, /* SLIMRX1 */
0x39,
0x3a,
0x3b,
0x3c,
0x3d,
0x3e,
0x3f,
0x50, /* EQ1 */
0x51,
0x52,
0x53,
0x58, /* DRC1L */
0x59,
0x5a,
0x5b,
0x60, /* LHPF1 */
0x61,
0x62,
0x63,
0x68, /* DSP1.1 */
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x70, /* DSP2.1 */
0x71,
0x72,
0x73,
0x74,
0x75,
0x78, /* DSP3.1 */
0x79,
0x7a,
0x7b,
0x7c,
0x7d,
0x80, /* DSP4.1 */
0x81,
0x82,
0x83,
0x84,
0x85,
0x88, /* DSP5.1 */
0x89,
0x8a,
0x8b,
0x8c,
0x8d,
0xc0, /* DSP6.1 */
0xc1,
0xc2,
0xc3,
0xc4,
0xc5,
0xc8, /* DSP7.1 */
0xc9,
0xca,
0xcb,
0xcc,
0xcd,
0x90, /* ASRC1L */
0x91,
0x92,
0x93,
0xa0, /* ISRC1INT1 */
0xa1,
0xa2,
0xa3,
0xa4, /* ISRC1DEC1 */
0xa5,
0xa6,
0xa7,
0xa8, /* ISRC2DEC1 */
0xa9,
0xaa,
0xab,
0xac, /* ISRC2INT1 */
0xad,
0xae,
0xaf,
0xb0, /* ISRC3DEC1 */
0xb1,
0xb2,
0xb3,
0xb4, /* ISRC3INT1 */
0xb5,
0xb6,
0xb7,
0xb8, /* ISRC4INT1 */
0xb9,
0xbc, /* ISRC4DEC1 */
0xbd,
};
EXPORT_SYMBOL_GPL(arizona_mixer_values);
const char * const arizona_v2_mixer_texts[ARIZONA_V2_NUM_MIXER_INPUTS] = {
"None",
"Tone Generator 1",
"Tone Generator 2",
"Haptics",
"AEC",
"AEC2",
"Mic Mute Mixer",
"Noise Generator",
"IN1L",
"IN1R",
"IN2L",
"IN2R",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
"IN5L",
"IN5R",
"IN6L",
"IN6R",
"AIF1RX1",
"AIF1RX2",
"AIF1RX3",
"AIF1RX4",
"AIF1RX5",
"AIF1RX6",
"AIF1RX7",
"AIF1RX8",
"AIF2RX1",
"AIF2RX2",
"AIF2RX3",
"AIF2RX4",
"AIF2RX5",
"AIF2RX6",
"AIF2RX7",
"AIF2RX8",
"AIF3RX1",
"AIF3RX2",
"AIF4RX1",
"AIF4RX2",
"SLIMRX1",
"SLIMRX2",
"SLIMRX3",
"SLIMRX4",
"SLIMRX5",
"SLIMRX6",
"SLIMRX7",
"SLIMRX8",
"EQ1",
"EQ2",
"EQ3",
"EQ4",
"DRC1L",
"DRC1R",
"DRC2L",
"DRC2R",
"LHPF1",
"LHPF2",
"LHPF3",
"LHPF4",
"DSP1.1",
"DSP1.2",
"DSP1.3",
"DSP1.4",
"DSP1.5",
"DSP1.6",
"DSP2.1",
"DSP2.2",
"DSP2.3",
"DSP2.4",
"DSP2.5",
"DSP2.6",
"DSP3.1",
"DSP3.2",
"DSP3.3",
"DSP3.4",
"DSP3.5",
"DSP3.6",
"DSP4.1",
"DSP4.2",
"DSP4.3",
"DSP4.4",
"DSP4.5",
"DSP4.6",
"DSP5.1",
"DSP5.2",
"DSP5.3",
"DSP5.4",
"DSP5.5",
"DSP5.6",
"DSP6.1",
"DSP6.2",
"DSP6.3",
"DSP6.4",
"DSP6.5",
"DSP6.6",
"DSP7.1",
"DSP7.2",
"DSP7.3",
"DSP7.4",
"DSP7.5",
"DSP7.6",
"ASRC1IN1L",
"ASRC1IN1R",
"ASRC1IN2L",
"ASRC1IN2R",
"ASRC2IN1L",
"ASRC2IN1R",
"ASRC2IN2L",
"ASRC2IN2R",
"ISRC1INT1",
"ISRC1INT2",
"ISRC1INT3",
"ISRC1INT4",
"ISRC1DEC1",
"ISRC1DEC2",
"ISRC1DEC3",
"ISRC1DEC4",
"ISRC2INT1",
"ISRC2INT2",
"ISRC2INT3",
"ISRC2INT4",
"ISRC2DEC1",
"ISRC2DEC2",
"ISRC2DEC3",
"ISRC2DEC4",
"ISRC3INT1",
"ISRC3INT2",
"ISRC3INT3",
"ISRC3INT4",
"ISRC3DEC1",
"ISRC3DEC2",
"ISRC3DEC3",
"ISRC3DEC4",
"ISRC4INT1",
"ISRC4INT2",
"ISRC4DEC1",
"ISRC4DEC2",
"DFC1",
"DFC2",
"DFC3",
"DFC4",
"DFC5",
"DFC6",
"DFC7",
"DFC8",
};
EXPORT_SYMBOL_GPL(arizona_v2_mixer_texts);
unsigned int arizona_v2_mixer_values[ARIZONA_V2_NUM_MIXER_INPUTS] = {
0x00, /* None */
0x04, /* Tone */
0x05,
0x06, /* Haptics */
0x08, /* AEC */
0x09, /* AEC2 */
0x0c, /* Noise mixer */
0x0d, /* Comfort noise */
0x10, /* IN1L */
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x18,
0x19,
0x1A,
0x1B,
0x20, /* AIF1RX1 */
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28, /* AIF2RX1 */
0x29,
0x2a,
0x2b,
0x2c,
0x2d,
0x2e,
0x2f,
0x30, /* AIF3RX1 */
0x31,
0x34, /* AIF4RX1 */
0x35,
0x38, /* SLIMRX1 */
0x39,
0x3a,
0x3b,
0x3c,
0x3d,
0x3e,
0x3f,
0x50, /* EQ1 */
0x51,
0x52,
0x53,
0x58, /* DRC1L */
0x59,
0x5a,
0x5b,
0x60, /* LHPF1 */
0x61,
0x62,
0x63,
0x68, /* DSP1.1 */
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x70, /* DSP2.1 */
0x71,
0x72,
0x73,
0x74,
0x75,
0x78, /* DSP3.1 */
0x79,
0x7a,
0x7b,
0x7c,
0x7d,
0x80, /* DSP4.1 */
0x81,
0x82,
0x83,
0x84,
0x85,
0x88, /* DSP5.1 */
0x89,
0x8a,
0x8b,
0x8c,
0x8d,
0xc0, /* DSP6.1 */
0xc1,
0xc2,
0xc3,
0xc4,
0xc5,
0xc8, /* DSP7.1 */
0xc9,
0xca,
0xcb,
0xcc,
0xcd,
0x90, /* ASRC1IN1L */
0x91,
0x92,
0x93,
0x94, /* ASRC2IN1L */
0x95,
0x96,
0x97,
0xa0, /* ISRC1INT1 */
0xa1,
0xa2,
0xa3,
0xa4, /* ISRC1DEC1 */
0xa5,
0xa6,
0xa7,
0xa8, /* ISRC2DEC1 */
0xa9,
0xaa,
0xab,
0xac, /* ISRC2INT1 */
0xad,
0xae,
0xaf,
0xb0, /* ISRC3DEC1 */
0xb1,
0xb2,
0xb3,
0xb4, /* ISRC3INT1 */
0xb5,
0xb6,
0xb7,
0xb8, /* ISRC4INT1 */
0xb9,
0xbc, /* ISRC4DEC1 */
0xbd,
0xf8, /* DFC1 */
0xf9,
0xfa,
0xfb,
0xfc,
0xfd,
0xfe,
0xff, /* DFC8 */
};
EXPORT_SYMBOL_GPL(arizona_v2_mixer_values);
const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
"12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
"11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
"4kHz", "8kHz", "16kHz", "32kHz",
};
EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0x10, 0x11, 0x12, 0x13,
};
EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
{
int i;
for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
if (arizona_sample_rate_val[i] == rate_val)
return arizona_sample_rate_text[i];
}
return "Illegal";
}
EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
const struct soc_enum arizona_sample_rate[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_SAMPLE_RATE_2,
ARIZONA_SAMPLE_RATE_2_SHIFT, 0x1f,
ARIZONA_SAMPLE_RATE_ENUM_SIZE,
arizona_sample_rate_text,
arizona_sample_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_SAMPLE_RATE_3,
ARIZONA_SAMPLE_RATE_3_SHIFT, 0x1f,
ARIZONA_SAMPLE_RATE_ENUM_SIZE,
arizona_sample_rate_text,
arizona_sample_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ASYNC_SAMPLE_RATE_2,
ARIZONA_ASYNC_SAMPLE_RATE_2_SHIFT, 0x1f,
ARIZONA_SAMPLE_RATE_ENUM_SIZE,
arizona_sample_rate_text,
arizona_sample_rate_val),
};
EXPORT_SYMBOL_GPL(arizona_sample_rate);
const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
"SYNCCLK rate 1", "SYNCCLK rate 2", "SYNCCLK rate 3",
"ASYNCCLK rate", "ASYNCCLK rate 2",
};
EXPORT_SYMBOL_GPL(arizona_rate_text);
const struct soc_enum arizona_output_rate =
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_RATE_1,
ARIZONA_OUT_RATE_SHIFT,
0x0f,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val);
EXPORT_SYMBOL_GPL(arizona_output_rate);
const struct soc_enum arizona_input_rate =
SOC_VALUE_ENUM_SINGLE(ARIZONA_INPUT_RATE,
ARIZONA_IN_RATE_SHIFT,
0x0f,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val);
EXPORT_SYMBOL_GPL(arizona_input_rate);
const struct soc_enum moon_input_rate[] = {
SOC_VALUE_ENUM_SINGLE(MOON_IN1L_RATE_CONTROL,
MOON_IN1L_RATE_SHIFT,
MOON_IN1L_RATE_MASK >> MOON_IN1L_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN1R_RATE_CONTROL,
MOON_IN1R_RATE_SHIFT,
MOON_IN1R_RATE_MASK >> MOON_IN1R_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN2L_RATE_CONTROL,
MOON_IN2L_RATE_SHIFT,
MOON_IN2L_RATE_MASK >> MOON_IN2L_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN2R_RATE_CONTROL,
MOON_IN2R_RATE_SHIFT,
MOON_IN2R_RATE_MASK >> MOON_IN2R_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN3L_RATE_CONTROL,
MOON_IN3L_RATE_SHIFT,
MOON_IN3L_RATE_MASK >> MOON_IN3L_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN3R_RATE_CONTROL,
MOON_IN3R_RATE_SHIFT,
MOON_IN3R_RATE_MASK >> MOON_IN3R_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN4L_RATE_CONTROL,
MOON_IN4L_RATE_SHIFT,
MOON_IN4L_RATE_MASK >> MOON_IN4L_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN4R_RATE_CONTROL,
MOON_IN4R_RATE_SHIFT,
MOON_IN4R_RATE_MASK >> MOON_IN4R_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN5L_RATE_CONTROL,
MOON_IN5L_RATE_SHIFT,
MOON_IN5L_RATE_MASK >> MOON_IN5L_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(MOON_IN5R_RATE_CONTROL,
MOON_IN5R_RATE_SHIFT,
MOON_IN5R_RATE_MASK >> MOON_IN5R_RATE_SHIFT,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val),
};
EXPORT_SYMBOL_GPL(moon_input_rate);
const char * const moon_dfc_width_text[MOON_DFC_WIDTH_ENUM_SIZE] = {
"8bit", "16bit", "20bit", "24bit", "32bit",
};
EXPORT_SYMBOL_GPL(moon_dfc_width_text);
const unsigned int moon_dfc_width_val[MOON_DFC_WIDTH_ENUM_SIZE] = {
7, 15, 19, 23, 31,
};
EXPORT_SYMBOL_GPL(moon_dfc_width_val);
const char * const moon_dfc_type_text[MOON_DFC_TYPE_ENUM_SIZE] = {
"Fixed", "Unsigned Fixed", "Single Precision Floating",
"Half Precision Floating", "Arm Alternative Floating",
};
EXPORT_SYMBOL_GPL(moon_dfc_type_text);
const unsigned int moon_dfc_type_val[MOON_DFC_TYPE_ENUM_SIZE] = {
0, 1, 2, 4, 5,
};
EXPORT_SYMBOL_GPL(moon_dfc_type_val);
const struct soc_enum moon_dfc_width[] = {
SOC_VALUE_ENUM_SINGLE(MOON_DFC1_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC1_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC2_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC2_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC3_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC3_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC4_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC4_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC5_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC5_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC6_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC6_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC7_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC7_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC8_RX,
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
MOON_DFC1_RX_DATA_WIDTH_MASK >>
MOON_DFC1_RX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC8_TX,
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
MOON_DFC1_TX_DATA_WIDTH_MASK >>
MOON_DFC1_TX_DATA_WIDTH_SHIFT,
ARRAY_SIZE(moon_dfc_width_text),
moon_dfc_width_text,
moon_dfc_width_val),
};
EXPORT_SYMBOL_GPL(moon_dfc_width);
const struct soc_enum moon_dfc_type[] = {
SOC_VALUE_ENUM_SINGLE(MOON_DFC1_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC1_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC2_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC2_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC3_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC3_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC4_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC4_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC5_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC5_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC6_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC6_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC7_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC7_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC8_RX,
MOON_DFC1_RX_DATA_TYPE_SHIFT,
MOON_DFC1_RX_DATA_TYPE_MASK >>
MOON_DFC1_RX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
SOC_VALUE_ENUM_SINGLE(MOON_DFC8_TX,
MOON_DFC1_TX_DATA_TYPE_SHIFT,
MOON_DFC1_TX_DATA_TYPE_MASK >>
MOON_DFC1_TX_DATA_TYPE_SHIFT,
ARRAY_SIZE(moon_dfc_type_text),
moon_dfc_type_text,
moon_dfc_type_val),
};
EXPORT_SYMBOL_GPL(moon_dfc_type);
const struct soc_enum arizona_fx_rate =
SOC_VALUE_ENUM_SINGLE(ARIZONA_FX_CTRL1,
ARIZONA_FX_RATE_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val);
EXPORT_SYMBOL_GPL(arizona_fx_rate);
const struct soc_enum arizona_spdif_rate =
SOC_VALUE_ENUM_SINGLE(ARIZONA_SPD1_TX_CONTROL,
ARIZONA_SPD1_RATE_SHIFT,
0x0f,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text,
arizona_rate_val);
EXPORT_SYMBOL_GPL(arizona_spdif_rate);
const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
0x0, 0x1, 0x2, 0x8, 0x9,
};
EXPORT_SYMBOL_GPL(arizona_rate_val);
const struct soc_enum arizona_isrc_fsh[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
ARIZONA_ISRC1_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
ARIZONA_ISRC2_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
ARIZONA_ISRC3_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_4_CTRL_1,
ARIZONA_ISRC4_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
};
EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
const struct soc_enum arizona_isrc_fsl[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
ARIZONA_ISRC1_FSL_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
ARIZONA_ISRC2_FSL_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
ARIZONA_ISRC3_FSL_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_4_CTRL_2,
ARIZONA_ISRC4_FSL_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
};
EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
const struct soc_enum arizona_asrc_rate1 =
SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
ARIZONA_ASRC_RATE1_SHIFT, 0xf,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val);
EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
const struct soc_enum arizona_asrc_rate2 =
SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE2,
ARIZONA_ASRC_RATE2_SHIFT, 0xf,
ARIZONA_ASYNC_RATE_ENUM_SIZE,
arizona_rate_text + ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_val + ARIZONA_SYNC_RATE_ENUM_SIZE);
EXPORT_SYMBOL_GPL(arizona_asrc_rate2);
const struct soc_enum clearwater_asrc1_rate[] = {
SOC_VALUE_ENUM_SINGLE(CLEARWATER_ASRC1_RATE1,
CLEARWATER_ASRC1_RATE1_SHIFT, 0xf,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(CLEARWATER_ASRC1_RATE2,
CLEARWATER_ASRC1_RATE1_SHIFT, 0xf,
ARIZONA_ASYNC_RATE_ENUM_SIZE,
arizona_rate_text + ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_val + ARIZONA_SYNC_RATE_ENUM_SIZE),
};
EXPORT_SYMBOL_GPL(clearwater_asrc1_rate);
const struct soc_enum clearwater_asrc2_rate[] = {
SOC_VALUE_ENUM_SINGLE(CLEARWATER_ASRC2_RATE1,
CLEARWATER_ASRC2_RATE1_SHIFT, 0xf,
ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(CLEARWATER_ASRC2_RATE2,
CLEARWATER_ASRC2_RATE2_SHIFT, 0xf,
ARIZONA_ASYNC_RATE_ENUM_SIZE,
arizona_rate_text + ARIZONA_SYNC_RATE_ENUM_SIZE,
arizona_rate_val + ARIZONA_SYNC_RATE_ENUM_SIZE),
};
EXPORT_SYMBOL_GPL(clearwater_asrc2_rate);
static const char * const arizona_vol_ramp_text[] = {
"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
"15ms/6dB", "30ms/6dB",
};
const SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
ARIZONA_INPUT_VOLUME_RAMP,
ARIZONA_IN_VD_RAMP_SHIFT,
arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
const SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
ARIZONA_INPUT_VOLUME_RAMP,
ARIZONA_IN_VI_RAMP_SHIFT,
arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
const SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
ARIZONA_OUTPUT_VOLUME_RAMP,
ARIZONA_OUT_VD_RAMP_SHIFT,
arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
const SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
ARIZONA_OUTPUT_VOLUME_RAMP,
ARIZONA_OUT_VI_RAMP_SHIFT,
arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
static const char * const arizona_lhpf_mode_text[] = {
"Low-pass", "High-pass"
};
const SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
ARIZONA_HPLPF1_1,
ARIZONA_LHPF1_MODE_SHIFT,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
const SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
ARIZONA_HPLPF2_1,
ARIZONA_LHPF2_MODE_SHIFT,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
const SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
ARIZONA_HPLPF3_1,
ARIZONA_LHPF3_MODE_SHIFT,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
const SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
ARIZONA_HPLPF4_1,
ARIZONA_LHPF4_MODE_SHIFT,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
static const char * const arizona_ng_hold_text[] = {
"30ms", "120ms", "250ms", "500ms",
};
const SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
ARIZONA_NOISE_GATE_CONTROL,
ARIZONA_NGATE_HOLD_SHIFT,
arizona_ng_hold_text);
EXPORT_SYMBOL_GPL(arizona_ng_hold);
static const char * const arizona_in_hpf_cut_text[] = {
"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
};
const SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
ARIZONA_HPF_CONTROL,
ARIZONA_IN_HPF_CUT_SHIFT,
arizona_in_hpf_cut_text);
EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
static const char * const arizona_in_dmic_osr_text[] = {
"1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
};
const struct soc_enum arizona_in_dmic_osr[] = {
SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
ARRAY_SIZE(arizona_in_dmic_osr_text),
arizona_in_dmic_osr_text),
SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
ARRAY_SIZE(arizona_in_dmic_osr_text),
arizona_in_dmic_osr_text),
SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
ARRAY_SIZE(arizona_in_dmic_osr_text),
arizona_in_dmic_osr_text),
SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
ARRAY_SIZE(arizona_in_dmic_osr_text),
arizona_in_dmic_osr_text),
};
EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
static const char * const clearwater_in_dmic_osr_text[CLEARWATER_OSR_ENUM_SIZE] = {
"384kHz", "768kHz", "1.536MHz", "3.072MHz", "6.144MHz",
};
static const unsigned int clearwater_in_dmic_osr_val[CLEARWATER_OSR_ENUM_SIZE] = {
2, 3, 4, 5, 6,
};
const struct soc_enum clearwater_in_dmic_osr[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_DMIC1L_CONTROL, CLEARWATER_IN1_OSR_SHIFT,
0x7, CLEARWATER_OSR_ENUM_SIZE,
clearwater_in_dmic_osr_text, clearwater_in_dmic_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_DMIC2L_CONTROL, CLEARWATER_IN2_OSR_SHIFT,
0x7, CLEARWATER_OSR_ENUM_SIZE,
clearwater_in_dmic_osr_text, clearwater_in_dmic_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_DMIC3L_CONTROL, CLEARWATER_IN3_OSR_SHIFT,
0x7, CLEARWATER_OSR_ENUM_SIZE,
clearwater_in_dmic_osr_text, clearwater_in_dmic_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_DMIC4L_CONTROL, CLEARWATER_IN4_OSR_SHIFT,
0x7, CLEARWATER_OSR_ENUM_SIZE,
clearwater_in_dmic_osr_text, clearwater_in_dmic_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_DMIC5L_CONTROL, CLEARWATER_IN5_OSR_SHIFT,
0x7, CLEARWATER_OSR_ENUM_SIZE,
clearwater_in_dmic_osr_text, clearwater_in_dmic_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_DMIC6L_CONTROL, CLEARWATER_IN6_OSR_SHIFT,
0x7, CLEARWATER_OSR_ENUM_SIZE,
clearwater_in_dmic_osr_text, clearwater_in_dmic_osr_val),
};
EXPORT_SYMBOL_GPL(clearwater_in_dmic_osr);
static const char * const arizona_anc_input_src_text[] = {
"None", "IN1", "IN2", "IN3", "IN4", "IN5", "IN6",
};
static const char * const arizona_anc_channel_src_text[] = {
"None", "Left", "Right", "Combine",
};
const struct soc_enum arizona_anc_input_src[] = {
SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
ARIZONA_IN_RXANCL_SEL_SHIFT,
ARRAY_SIZE(arizona_anc_input_src_text),
arizona_anc_input_src_text),
SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
ARIZONA_FCL_MIC_MODE_SEL,
ARRAY_SIZE(arizona_anc_channel_src_text),
arizona_anc_channel_src_text),
SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
ARIZONA_IN_RXANCR_SEL_SHIFT,
ARRAY_SIZE(arizona_anc_input_src_text),
arizona_anc_input_src_text),
SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
ARIZONA_FCR_MIC_MODE_SEL,
ARRAY_SIZE(arizona_anc_channel_src_text),
arizona_anc_channel_src_text),
};
EXPORT_SYMBOL_GPL(arizona_anc_input_src);
const struct soc_enum clearwater_anc_input_src[] = {
SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
ARIZONA_IN_RXANCL_SEL_SHIFT,
ARRAY_SIZE(arizona_anc_input_src_text),
arizona_anc_input_src_text),
SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
ARIZONA_FCL_MIC_MODE_SEL,
ARRAY_SIZE(arizona_anc_channel_src_text),
arizona_anc_channel_src_text),
SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
ARIZONA_IN_RXANCR_SEL_SHIFT,
ARRAY_SIZE(arizona_anc_input_src_text),
arizona_anc_input_src_text),
SOC_ENUM_SINGLE(CLEARWATER_FCR_ADC_REFORMATTER_CONTROL,
ARIZONA_FCR_MIC_MODE_SEL,
ARRAY_SIZE(arizona_anc_channel_src_text),
arizona_anc_channel_src_text),
};
EXPORT_SYMBOL_GPL(clearwater_anc_input_src);
static const char * const arizona_anc_ng_texts[] = {
"None",
"Internal",
"External",
};
const struct soc_enum arizona_anc_ng_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(arizona_anc_ng_texts),
arizona_anc_ng_texts);
EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
static const char * const arizona_output_anc_src_text[] = {
"None", "RXANCL", "RXANCR",
};
const struct soc_enum arizona_output_anc_src[] = {
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
ARIZONA_OUT1L_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
ARIZONA_OUT1R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
ARIZONA_OUT2L_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
ARIZONA_OUT2R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
ARIZONA_OUT3L_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
ARIZONA_OUT3R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
ARIZONA_OUT4L_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
ARIZONA_OUT4R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
ARIZONA_OUT5L_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
ARIZONA_OUT5R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
ARIZONA_OUT6L_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
ARIZONA_OUT6R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
};
EXPORT_SYMBOL_GPL(arizona_output_anc_src);
const struct soc_enum clearwater_output_anc_src_defs[] = {
SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3R,
ARIZONA_OUT3R_ANC_SRC_SHIFT,
ARRAY_SIZE(arizona_output_anc_src_text),
arizona_output_anc_src_text),
};
EXPORT_SYMBOL_GPL(clearwater_output_anc_src_defs);
static const char * const arizona_ip_mode_text[2] = {
"Analog", "Digital",
};
const struct soc_enum arizona_ip_mode[] = {
SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_MODE_SHIFT,
ARRAY_SIZE(arizona_ip_mode_text), arizona_ip_mode_text),
SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_MODE_SHIFT,
ARRAY_SIZE(arizona_ip_mode_text), arizona_ip_mode_text),
SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_MODE_SHIFT,
ARRAY_SIZE(arizona_ip_mode_text), arizona_ip_mode_text),
};
EXPORT_SYMBOL_GPL(arizona_ip_mode);
int arizona_ip_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg, ret = 0;
mutex_lock_nested(&codec->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
/* Cannot change input mode on an active input*/
reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
switch (e->reg) {
case ARIZONA_IN1L_CONTROL:
if (reg & (ARIZONA_IN1L_ENA_MASK |ARIZONA_IN1R_ENA_MASK)) {
ret = -EBUSY;
goto exit;
}
break;
case ARIZONA_IN2L_CONTROL:
if (reg & (ARIZONA_IN2L_ENA_MASK |ARIZONA_IN2R_ENA_MASK)) {
ret = -EBUSY;
goto exit;
}
break;
case ARIZONA_IN3L_CONTROL:
if (reg & (ARIZONA_IN3L_ENA_MASK |ARIZONA_IN3R_ENA_MASK)) {
ret = -EBUSY;
goto exit;
}
break;
default:
ret = -EINVAL;
goto exit;
break;
}
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
exit:
mutex_unlock(&codec->card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_ip_mode_put);
int moon_in_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg, mask;
int ret = 0;
mutex_lock_nested(&codec->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
/* Cannot change rate on an active input */
reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
mask = (e->reg - ARIZONA_IN1L_CONTROL) / 4;
mask ^= 0x1; /* Flip bottom bit for channel order */
if ((reg) & (1 << mask)) {
ret = -EBUSY;
goto exit;
}
ret = snd_soc_put_value_enum_double(kcontrol, ucontrol);
exit:
mutex_unlock(&codec->card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(moon_in_rate_put);
int moon_dfc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = e->reg;
unsigned int val;
int ret = 0;
reg = ((reg / 6) * 6) - 2;
mutex_lock_nested(&codec->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
/* Cannot change dfc settings when its on */
val = snd_soc_read(codec, reg);
if (val & MOON_DFC1_ENA) {
ret = -EBUSY;
goto exit;
}
ret = snd_soc_put_value_enum_double(kcontrol, ucontrol);
exit:
mutex_unlock(&codec->card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(moon_dfc_put);
int moon_osr_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mode;
/* for analog mode osr is fixed */
mode = snd_soc_read(codec, e->reg - 2);
if (!(mode & ARIZONA_IN1_MODE_MASK)) {
dev_err(codec->dev,
"OSR is fixed to 3.072MHz in analog mode\n");
return -EINVAL;
}
return snd_soc_put_value_enum_double(kcontrol, ucontrol);
}
EXPORT_SYMBOL_GPL(moon_osr_put);
int moon_lp_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg, mask;
int ret;
mutex_lock_nested(&codec->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
/* Cannot change lp mode on an active input */
reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
mask = (mc->reg - ARIZONA_ADC_DIGITAL_VOLUME_1L) / 4;
mask ^= 0x1; /* Flip bottom bit for channel order */
if ((reg) & (1 << mask)) {
ret = -EBUSY;
dev_err(codec->dev,
"Can't change lp mode on an active input\n");
goto exit;
}
ret = snd_soc_put_volsw(kcontrol, ucontrol);
exit:
mutex_unlock(&codec->card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(moon_lp_mode_put);
static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
unsigned int val;
int i;
if (ena)
val = ARIZONA_IN_VU;
else
val = 0;
for (i = 0; i < priv->num_inputs; i++)
snd_soc_update_bits(codec,
ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
ARIZONA_IN_VU, val);
}
static int arizona_update_input(struct arizona* arizona, bool enable)
{
unsigned int val;
switch (arizona->type) {
case WM8280:
case WM5110:
if (arizona->rev >= 6)
return 0;
break;
default:
return 0;
}
mutex_lock(&arizona->reg_setting_lock);
regmap_write(arizona->regmap, 0x80, 0x3);
if (enable) {
arizona_florida_mute_analog(arizona, ARIZONA_IN1L_MUTE);
msleep(10);
regmap_write(arizona->regmap, 0x3A6, 0x5555);
regmap_write(arizona->regmap, 0x3A5, 0x3);
} else {
regmap_read(arizona->regmap, 0x3A5, &val);
if (val) {
msleep(10);
regmap_write(arizona->regmap, 0x3A5, 0x0);
regmap_write(arizona->regmap, 0x3A6, 0x0);
msleep(5);
}
arizona_florida_mute_analog(arizona, 0);
}
regmap_write(arizona->regmap, 0x80, 0x0);
mutex_unlock(&arizona->reg_setting_lock);
return 0;
}
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
unsigned int ctrl;
unsigned int reg;
if (w->shift % 2) {
reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
ctrl = reg - 1;
} else {
reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
ctrl = reg - 5;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
priv->in_pending++;
/* Check for analogue input */
if ((snd_soc_read(w->codec, ctrl) & 0x0400) == 0)
arizona_update_input(priv->arizona, true);
break;
case SND_SOC_DAPM_POST_PMU:
priv->in_pending--;
if (priv->in_pending == 0)
arizona_update_input(priv->arizona, false);
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
/* If this is the last input pending then allow VU */
if (priv->in_pending == 0) {
msleep(1);
arizona_in_set_vu(w->codec, 1);
}
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(w->codec, reg,
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
break;
case SND_SOC_DAPM_POST_PMD:
/* Disable volume updates if no inputs are enabled */
reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
if (reg == 0)
arizona_in_set_vu(w->codec, 0);
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_in_ev);
static void clearwater_hp_post_enable(struct snd_soc_dapm_widget *w)
{
unsigned int val;
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
val = snd_soc_read(w->codec, ARIZONA_OUTPUT_ENABLES_1);
val &= (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA);
if (val == (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))
snd_soc_update_bits(w->codec,
CLEARWATER_EDRE_HP_STEREO_CONTROL,
ARIZONA_HP1_EDRE_STEREO_MASK,
ARIZONA_HP1_EDRE_STEREO);
break;
default:
break;
}
}
static void clearwater_hp_post_disable(struct snd_soc_dapm_widget *w)
{
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
snd_soc_write(w->codec,
ARIZONA_DCS_HP1L_CONTROL,
0x2006);
break;
case ARIZONA_OUT1R_ENA_SHIFT:
snd_soc_write(w->codec,
ARIZONA_DCS_HP1R_CONTROL,
0x2006);
break;
default:
return;
}
/* Only get to here for OUT1L and OUT1R */
snd_soc_update_bits(w->codec,
CLEARWATER_EDRE_HP_STEREO_CONTROL,
ARIZONA_HP1_EDRE_STEREO_MASK,
0);
}
int clearwater_put_dre(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int ret;
mutex_lock_nested(&codec->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
ret = snd_soc_put_volsw(kcontrol, ucontrol);
mutex_unlock(&codec->card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(clearwater_put_dre);
int arizona_out_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
case ARIZONA_OUT2L_ENA_SHIFT:
case ARIZONA_OUT2R_ENA_SHIFT:
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_up_pending++;
priv->out_up_delay += 17;
break;
default:
break;
}
break;
case SND_SOC_DAPM_POST_PMU:
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
case ARIZONA_OUT2L_ENA_SHIFT:
case ARIZONA_OUT2R_ENA_SHIFT:
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_up_pending--;
if (!priv->out_up_pending) {
msleep(priv->out_up_delay);
priv->out_up_delay = 0;
}
break;
default:
break;
}
break;
case SND_SOC_DAPM_PRE_PMD:
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
case ARIZONA_OUT2L_ENA_SHIFT:
case ARIZONA_OUT2R_ENA_SHIFT:
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_down_pending++;
priv->out_down_delay++;
break;
default:
break;
}
break;
case SND_SOC_DAPM_POST_PMD:
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
case ARIZONA_OUT2L_ENA_SHIFT:
case ARIZONA_OUT2R_ENA_SHIFT:
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_down_pending--;
if (!priv->out_down_pending) {
msleep(priv->out_down_delay);
priv->out_down_delay = 0;
}
break;
default:
break;
}
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_out_ev);
int arizona_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
unsigned int mask = 1 << w->shift;
unsigned int val;
unsigned int ep_sel = 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
val = mask;
break;
case SND_SOC_DAPM_PRE_PMD:
val = 0;
break;
case SND_SOC_DAPM_PRE_PMU:
case SND_SOC_DAPM_POST_PMD:
return arizona_out_ev(w, kcontrol, event);
default:
return -EINVAL;
}
/* Store the desired state for the HP outputs */
priv->arizona->hp_ena &= ~mask;
priv->arizona->hp_ena |= val;
/* in case of Marley check if OUT1 is routed to EPOUT, do not disable
* OUT1 in this case */
switch (priv->arizona->type) {
case CS47L35:
regmap_read(priv->arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
&ep_sel);
ep_sel &= ARIZONA_EP_SEL_MASK;
break;
default:
break;
}
/* Force off if HPDET clamp is active */
if ((priv->arizona->hpdet_clamp ||
priv->arizona->hp_impedance <=
priv->arizona->pdata.hpdet_short_circuit_imp) && !ep_sel)
val = 0;
snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
return arizona_out_ev(w, kcontrol, event);
}
EXPORT_SYMBOL_GPL(arizona_hp_ev);
int clearwater_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
int ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
case SND_SOC_DAPM_PRE_PMD:
return arizona_hp_ev(w, kcontrol, event);
case SND_SOC_DAPM_POST_PMU:
ret = arizona_hp_ev(w, kcontrol, event);
if (ret < 0)
return ret;
clearwater_hp_post_enable(w);
return 0;
case SND_SOC_DAPM_POST_PMD:
ret = arizona_hp_ev(w, kcontrol, event);
clearwater_hp_post_disable(w);
return ret;
default:
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(clearwater_hp_ev);
static void moon_analog_post_enable(struct snd_soc_dapm_widget *w)
{
unsigned int mask, val;
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
mask = ARIZONA_HP1_EDRE_STEREO_MASK;
val = ARIZONA_HP1_EDRE_STEREO;
break;
case ARIZONA_OUT2L_ENA_SHIFT:
case ARIZONA_OUT2R_ENA_SHIFT:
mask = ARIZONA_HP2_EDRE_STEREO_MASK;
val = ARIZONA_HP2_EDRE_STEREO;
break;
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
mask = ARIZONA_HP3_EDRE_STEREO_MASK;
val = ARIZONA_HP3_EDRE_STEREO;
break;
default:
return;
}
snd_soc_update_bits(w->codec,
CLEARWATER_EDRE_HP_STEREO_CONTROL,
mask, val);
}
static void moon_analog_post_disable(struct snd_soc_dapm_widget *w)
{
unsigned int mask;
switch (w->shift) {
case ARIZONA_OUT1L_ENA_SHIFT:
case ARIZONA_OUT1R_ENA_SHIFT:
mask = ARIZONA_HP1_EDRE_STEREO_MASK;
break;
case ARIZONA_OUT2L_ENA_SHIFT:
case ARIZONA_OUT2R_ENA_SHIFT:
mask = ARIZONA_HP2_EDRE_STEREO_MASK;
break;
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
mask = ARIZONA_HP3_EDRE_STEREO_MASK;
break;
default:
return;
}
snd_soc_update_bits(w->codec,
CLEARWATER_EDRE_HP_STEREO_CONTROL,
mask, 0);
}
int moon_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
int ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
case SND_SOC_DAPM_PRE_PMD:
return arizona_hp_ev(w, kcontrol, event);
case SND_SOC_DAPM_POST_PMU:
ret = arizona_hp_ev(w, kcontrol, event);
if (ret < 0)
return ret;
moon_analog_post_enable(w);
return 0;
case SND_SOC_DAPM_POST_PMD:
ret = arizona_hp_ev(w, kcontrol, event);
moon_analog_post_disable(w);
return ret;
default:
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(moon_hp_ev);
int moon_analog_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
int ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
case SND_SOC_DAPM_PRE_PMD:
return arizona_out_ev(w, kcontrol, event);
case SND_SOC_DAPM_POST_PMU:
ret = arizona_out_ev(w, kcontrol, event);
if (ret < 0)
return ret;
moon_analog_post_enable(w);
return 0;
case SND_SOC_DAPM_POST_PMD:
ret = arizona_out_ev(w, kcontrol, event);
moon_analog_post_disable(w);
return ret;
default:
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(moon_analog_ev);
int arizona_anc_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
unsigned int mask = 0x3 << w->shift;
unsigned int val;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
val = 1 << w->shift;
break;
case SND_SOC_DAPM_PRE_PMD:
val = 1 << (w->shift + 1);
break;
default:
return 0;
}
snd_soc_update_bits(w->codec, ARIZONA_CLOCK_CONTROL, mask, val);
return 0;
}
EXPORT_SYMBOL_GPL(arizona_anc_ev);
static int arizona_dvfs_enable(struct snd_soc_codec *codec)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
return ret;
}
ret = regmap_update_bits(arizona->regmap,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ,
ARIZONA_SUBSYS_MAX_FREQ);
if (ret) {
dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
return ret;
}
return 0;
}
static int arizona_dvfs_disable(struct snd_soc_codec *codec)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = regmap_update_bits(arizona->regmap,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ, 0);
if (ret) {
dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
return ret;
}
ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
return ret;
}
return 0;
}
int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
if (!priv->dvfs_cached && !priv->dvfs_reqs) {
ret = arizona_dvfs_enable(codec);
if (ret)
goto err;
}
priv->dvfs_reqs |= flags;
err:
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_up);
int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
unsigned int old_reqs;
int ret = 0;
mutex_lock(&priv->dvfs_lock);
old_reqs = priv->dvfs_reqs;
priv->dvfs_reqs &= ~flags;
if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_down);
int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (priv->dvfs_reqs)
ret = arizona_dvfs_enable(codec);
priv->dvfs_cached = false;
break;
case SND_SOC_DAPM_PRE_PMD:
/* We must ensure DVFS is disabled before the codec goes into
* suspend so that we are never in an illegal state of DVFS
* enabled without enough DCVDD
*/
priv->dvfs_cached = true;
if (priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
break;
default:
break;
}
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
void arizona_init_dvfs(struct arizona_priv *priv)
{
mutex_init(&priv->dvfs_lock);
}
EXPORT_SYMBOL_GPL(arizona_init_dvfs);
static unsigned int arizona_sysclk_48k_rates[] = {
6144000,
12288000,
24576000,
49152000,
73728000,
98304000,
147456000,
};
static unsigned int arizona_sysclk_44k1_rates[] = {
5644800,
11289600,
22579200,
45158400,
67737600,
90316800,
135475200,
};
static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
unsigned int freq)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
unsigned int reg;
unsigned int *rates;
int ref, div, refclk;
switch (clk) {
case ARIZONA_CLK_OPCLK:
reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
refclk = priv->sysclk;
break;
case ARIZONA_CLK_ASYNC_OPCLK:
reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
refclk = priv->asyncclk;
break;
default:
return -EINVAL;
}
if (refclk % 8000)
rates = arizona_sysclk_44k1_rates;
else
rates = arizona_sysclk_48k_rates;
for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
rates[ref] <= refclk; ref++) {
div = 1;
while (rates[ref] / div >= freq && div < 32) {
if (rates[ref] / div == freq) {
dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
freq);
snd_soc_update_bits(codec, reg,
ARIZONA_OPCLK_DIV_MASK |
ARIZONA_OPCLK_SEL_MASK,
(div <<
ARIZONA_OPCLK_DIV_SHIFT) |
ref);
return 0;
}
div++;
}
}
dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
return -EINVAL;
}
static int arizona_get_sysclk_setting(unsigned int freq)
{
switch (freq) {
case 0:
case 5644800:
case 6144000:
return 0;
case 11289600:
case 12288000:
return ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 22579200:
case 24576000:
return ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 45158400:
case 49152000:
return ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 67737600:
case 73728000:
return ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 90316800:
case 98304000:
return ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 135475200:
case 147456000:
return ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
default:
return -EINVAL;
}
}
static int clearwater_get_sysclk_setting(unsigned int freq)
{
switch (freq) {
case 0:
case 5644800:
case 6144000:
return 0;
case 11289600:
case 12288000:
return ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 22579200:
case 24576000:
return ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 45158400:
case 49152000:
return ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
case 90316800:
case 98304000:
return CLEARWATER_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
default:
return -EINVAL;
}
}
static int clearwater_get_dspclk_setting(unsigned int freq,
struct arizona *arizona,
int source)
{
switch (freq) {
case 0:
return 0;
case 45158400:
case 49152000:
switch (arizona->type) {
case WM1840:
case WM8285:
if (arizona->rev >= 3 &&
source == CLEARWATER_CLK_SRC_FLL1_DIV6)
return ARIZONA_CLK_49MHZ <<
ARIZONA_SYSCLK_FREQ_SHIFT;
else
return -EINVAL;
default:
return -EINVAL;
}
case 135475200:
case 147456000:
return CLEARWATER_DSP_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
default:
return -EINVAL;
}
}
static void clearwater_get_dsp_reg_seq(unsigned int cur, unsigned int tar,
unsigned int reg, unsigned int mask,
struct reg_sequence *s)
{
/* To transition DSPCLK to a new source and frequency we must:
* - Disable DSPCLK_ENA
* - Wait 34us
* - Write the new source, freq and enable in one write
*/
unsigned int tmp;
mask |= CLEARWATER_DSP_CLK_ENA_MASK;
s[0].reg = reg;
s[0].def = (cur & ~CLEARWATER_DSP_CLK_ENA_MASK);
/* The required delay is one worst case clock period (32kHz) + 2 us */
s[0].delay_us = 34;
/* Clear the fields we care about */
tmp = (cur & ~mask);
/* Update the fields */
tmp |= tar & mask;
/* Re-set the enable bit */
tmp |= CLEARWATER_DSP_CLK_ENA_MASK;
s[1].reg = reg;
s[1].def = tmp;
s[1].delay_us = 0;
}
static int moon_get_dspclk_setting(unsigned int freq, unsigned int *val)
{
if (freq > 150000000)
return -EINVAL;
/* freq * (2^6) / (10^6) */
*val = freq / 15625;
return 0;
}
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret = 0;
char *name;
unsigned int reg;
unsigned int reg2, val2;
unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
int clk_freq;
int *clk;
unsigned int dspclk_change = 0;
unsigned int dspclk_val;
struct reg_sequence dspclk_seq[2];
reg2 = val2 = 0;
switch (arizona->type) {
case WM8997:
case WM8998:
case WM1814:
case WM5102:
case WM8280:
case WM5110:
case WM1831:
case CS47L24:
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
name = "SYSCLK";
reg = ARIZONA_SYSTEM_CLOCK_1;
clk = &priv->sysclk;
mask |= ARIZONA_SYSCLK_FRAC;
clk_freq = arizona_get_sysclk_setting(freq);
break;
case ARIZONA_CLK_ASYNCCLK:
name = "ASYNCCLK";
reg = ARIZONA_ASYNC_CLOCK_1;
clk = &priv->asyncclk;
clk_freq = arizona_get_sysclk_setting(freq);
break;
case ARIZONA_CLK_OPCLK:
case ARIZONA_CLK_ASYNC_OPCLK:
return arizona_set_opclk(codec, clk_id, freq);
default:
return -EINVAL;
}
break;
case CS47L35:
case WM8285:
case WM1840:
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
name = "SYSCLK";
reg = ARIZONA_SYSTEM_CLOCK_1;
clk = &priv->sysclk;
clk_freq = clearwater_get_sysclk_setting(freq);
mask |= ARIZONA_SYSCLK_FRAC;
break;
case ARIZONA_CLK_ASYNCCLK:
name = "ASYNCCLK";
reg = ARIZONA_ASYNC_CLOCK_1;
clk = &priv->asyncclk;
clk_freq = clearwater_get_sysclk_setting(freq);
break;
case ARIZONA_CLK_OPCLK:
case ARIZONA_CLK_ASYNC_OPCLK:
return arizona_set_opclk(codec, clk_id, freq);
case ARIZONA_CLK_DSPCLK:
name = "DSPCLK";
reg = CLEARWATER_DSP_CLOCK_1;
clk = &priv->dspclk;
clk_freq = clearwater_get_dspclk_setting(freq,
arizona,
source);
switch (arizona->type) {
case WM1840:
case WM8285:
dspclk_change = 1;
break;
default:
break;
}
break;
default:
return -EINVAL;
}
break;
default:
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
name = "SYSCLK";
reg = ARIZONA_SYSTEM_CLOCK_1;
clk = &priv->sysclk;
clk_freq = clearwater_get_sysclk_setting(freq);
mask |= ARIZONA_SYSCLK_FRAC;
break;
case ARIZONA_CLK_ASYNCCLK:
name = "ASYNCCLK";
reg = ARIZONA_ASYNC_CLOCK_1;
clk = &priv->asyncclk;
clk_freq = clearwater_get_sysclk_setting(freq);
break;
case ARIZONA_CLK_OPCLK:
case ARIZONA_CLK_ASYNC_OPCLK:
return arizona_set_opclk(codec, clk_id, freq);
case ARIZONA_CLK_DSPCLK:
name = "DSPCLK";
reg = CLEARWATER_DSP_CLOCK_1;
mask = ARIZONA_SYSCLK_SRC_MASK;
reg2 = CLEARWATER_DSP_CLOCK_2;
clk = &priv->dspclk;
ret = moon_get_dspclk_setting(freq, &val2);
break;
default:
return -EINVAL;
}
break;
}
if (reg2) {
if (ret < 0) {
dev_err(arizona->dev, "Failed to get clk setting for %dHZ\n",
freq);
return ret;
}
ret = regmap_write(arizona->regmap,
reg2, val2);
if (ret != 0) {
dev_err(arizona->dev,
"Failed to set dsp freq to %d\n", val2);
return ret;
}
} else {
if (clk_freq < 0) {
dev_err(arizona->dev, "Failed to get clk setting for %dHZ\n",
freq);
return ret;
}