summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/oss/pcm_oss.c41
-rw-r--r--sound/core/oss/pcm_plugin.c14
-rw-r--r--sound/core/pcm.c2
-rw-r--r--sound/core/pcm_lib.c4
-rw-r--r--sound/core/pcm_misc.c19
-rw-r--r--sound/core/pcm_native.c9
-rw-r--r--sound/core/rawmidi.c15
-rw-r--r--sound/core/seq/seq_timer.c2
-rw-r--r--sound/drivers/aloop.c98
-rw-r--r--sound/hda/ext/hdac_ext_bus.c2
-rw-r--r--sound/hda/hdac_i915.c2
-rw-r--r--sound/pci/hda/patch_conexant.c29
-rw-r--r--sound/pci/hda/patch_hdmi.c6
-rw-r--r--sound/pci/hda/patch_realtek.c57
-rw-r--r--sound/soc/amd/acp-pcm-dma.c42
-rw-r--r--sound/soc/atmel/Kconfig2
-rw-r--r--sound/soc/atmel/atmel-classd.c6
-rw-r--r--sound/soc/au1x/ac97c.c6
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c20
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c6
-rw-r--r--sound/soc/codecs/88pm860x-codec.c9
-rw-r--r--sound/soc/codecs/Kconfig26
-rw-r--r--sound/soc/codecs/Makefile9
-rw-r--r--sound/soc/codecs/cq93vc.c10
-rw-r--r--sound/soc/codecs/cs35l32.c18
-rw-r--r--sound/soc/codecs/cs35l34.c19
-rw-r--r--sound/soc/codecs/cs42l52.c13
-rw-r--r--sound/soc/codecs/cs42l56.c13
-rw-r--r--sound/soc/codecs/cs42l73.c15
-rw-r--r--sound/soc/codecs/cs47l24.c12
-rw-r--r--sound/soc/codecs/cx20442.c46
-rw-r--r--sound/soc/codecs/da7213.c7
-rw-r--r--sound/soc/codecs/da7218.c11
-rw-r--r--sound/soc/codecs/dmic.c24
-rw-r--r--sound/soc/codecs/hdac_hdmi.c358
-rw-r--r--sound/soc/codecs/max98373.c976
-rw-r--r--sound/soc/codecs/max98373.h212
-rw-r--r--sound/soc/codecs/max98926.c2
-rw-r--r--sound/soc/codecs/max98927.c1
-rw-r--r--sound/soc/codecs/mc13783.c9
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c10
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c4
-rw-r--r--sound/soc/codecs/nau8540.c98
-rw-r--r--sound/soc/codecs/nau8540.h20
-rw-r--r--sound/soc/codecs/nau8824.c18
-rw-r--r--sound/soc/codecs/nau8825.c102
-rw-r--r--sound/soc/codecs/nau8825.h3
-rw-r--r--sound/soc/codecs/pcm186x-i2c.c69
-rw-r--r--sound/soc/codecs/pcm186x-spi.c69
-rw-r--r--sound/soc/codecs/pcm186x.c719
-rw-r--r--sound/soc/codecs/pcm186x.h220
-rw-r--r--sound/soc/codecs/pcm512x-spi.c4
-rw-r--r--sound/soc/codecs/rl6231.c93
-rw-r--r--sound/soc/codecs/rt5514-spi.c16
-rw-r--r--sound/soc/codecs/rt5514.c87
-rw-r--r--sound/soc/codecs/rt5514.h5
-rw-r--r--sound/soc/codecs/rt5645.c189
-rw-r--r--sound/soc/codecs/rt5645.h6
-rw-r--r--sound/soc/codecs/rt5663.c4
-rw-r--r--sound/soc/codecs/rt5663.h4
-rw-r--r--sound/soc/codecs/sgtl5000.c5
-rw-r--r--sound/soc/codecs/si476x.c9
-rw-r--r--sound/soc/codecs/sn95031.c936
-rw-r--r--sound/soc/codecs/sn95031.h133
-rw-r--r--sound/soc/codecs/spdif_receiver.c5
-rw-r--r--sound/soc/codecs/spdif_transmitter.c5
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h2
-rw-r--r--sound/soc/codecs/twl4030.c4
-rw-r--r--sound/soc/codecs/wm2200.c9
-rw-r--r--sound/soc/codecs/wm_adsp.c12
-rw-r--r--sound/soc/davinci/davinci-mcasp.c19
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c1
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c4
-rw-r--r--sound/soc/fsl/fsl_asrc.h6
-rw-r--r--sound/soc/fsl/fsl_dma.c4
-rw-r--r--sound/soc/fsl/fsl_ssi.c1393
-rw-r--r--sound/soc/fsl/fsl_ssi.h427
-rw-r--r--sound/soc/fsl/fsl_ssi_dbg.c59
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c1
-rw-r--r--sound/soc/intel/Kconfig115
-rw-r--r--sound/soc/intel/Makefile2
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c3
-rw-r--r--sound/soc/intel/atom/sst/sst_stream.c8
-rw-r--r--sound/soc/intel/boards/Kconfig195
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c4
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c26
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c4
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c50
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c13
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c4
-rw-r--r--sound/soc/intel/boards/haswell.c2
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c4
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c4
-rw-r--r--sound/soc/intel/boards/mfld_machine.c428
-rw-r--r--sound/soc/intel/common/sst-dsp.c4
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c2
-rw-r--r--sound/soc/intel/skylake/cnl-sst.c2
-rw-r--r--sound/soc/intel/skylake/skl-i2s.h64
-rw-r--r--sound/soc/intel/skylake/skl-messages.c22
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c173
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c14
-rw-r--r--sound/soc/intel/skylake/skl-ssp-clk.h79
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c14
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h4
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst.c2
-rw-r--r--sound/soc/intel/skylake/skl-topology.c47
-rw-r--r--sound/soc/intel/skylake/skl.c150
-rw-r--r--sound/soc/intel/skylake/skl.h22
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c552
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h15
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-common.h87
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c213
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-reg.h42
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c2
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c25
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c11
-rw-r--r--sound/soc/omap/ams-delta.c4
-rw-r--r--sound/soc/qcom/apq8016_sbc.c10
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c3
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c11
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c18
-rw-r--r--sound/soc/samsung/bells.c40
-rw-r--r--sound/soc/sh/rcar/adg.c6
-rw-r--r--sound/soc/sh/rcar/core.c147
-rw-r--r--sound/soc/sh/rcar/dma.c104
-rw-r--r--sound/soc/sh/rcar/rsnd.h15
-rw-r--r--sound/soc/sh/rcar/ssi.c161
-rw-r--r--sound/soc/sh/rcar/ssiu.c5
-rw-r--r--sound/soc/soc-acpi.c73
-rw-r--r--sound/soc/soc-compress.c4
-rw-r--r--sound/soc/soc-core.c143
-rw-r--r--sound/soc/soc-io.c6
-rw-r--r--sound/soc/soc-ops.c4
-rw-r--r--sound/soc/stm/Kconfig12
-rw-r--r--sound/soc/stm/Makefile3
-rw-r--r--sound/soc/stm/stm32_adfsdm.c347
-rw-r--r--sound/soc/stm/stm32_sai.c114
-rw-r--r--sound/soc/sunxi/sun4i-codec.c29
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c57
-rw-r--r--sound/usb/mixer.c30
-rw-r--r--sound/usb/quirks.c7
145 files changed, 6272 insertions, 4451 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index e49f448..c2db7e9 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -455,7 +455,6 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
v = snd_pcm_hw_param_last(pcm, params, var, dir);
else
v = snd_pcm_hw_param_first(pcm, params, var, dir);
- snd_BUG_ON(v < 0);
return v;
}
@@ -1335,8 +1334,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
- mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
@@ -1380,14 +1382,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
xfer += tmp;
if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
- break;
+ tmp = -EAGAIN;
}
- }
- mutex_unlock(&runtime->oss.params_lock);
- return xfer;
-
err:
- mutex_unlock(&runtime->oss.params_lock);
+ mutex_unlock(&runtime->oss.params_lock);
+ if (tmp < 0)
+ break;
+ if (signal_pending(current)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
+ tmp = 0;
+ }
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
@@ -1435,8 +1441,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
- mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
if (runtime->oss.buffer_used == 0) {
tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
@@ -1467,12 +1476,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
bytes -= tmp;
xfer += tmp;
}
- }
- mutex_unlock(&runtime->oss.params_lock);
- return xfer;
-
err:
- mutex_unlock(&runtime->oss.params_lock);
+ mutex_unlock(&runtime->oss.params_lock);
+ if (tmp < 0)
+ break;
+ if (signal_pending(current)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
+ tmp = 0;
+ }
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index cadc937..85a56af 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -592,18 +592,26 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
snd_pcm_sframes_t frames = size;
plugin = snd_pcm_plug_first(plug);
- while (plugin && frames > 0) {
+ while (plugin) {
+ if (frames <= 0)
+ return frames;
if ((next = plugin->next) != NULL) {
snd_pcm_sframes_t frames1 = frames;
- if (plugin->dst_frames)
+ if (plugin->dst_frames) {
frames1 = plugin->dst_frames(plugin, frames);
+ if (frames1 <= 0)
+ return frames1;
+ }
if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
return err;
}
if (err != frames1) {
frames = err;
- if (plugin->src_frames)
+ if (plugin->src_frames) {
frames = plugin->src_frames(plugin, frames1);
+ if (frames <= 0)
+ return frames;
+ }
}
} else
dst_channels = NULL;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 9070f27..09ee8c6 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -153,7 +153,9 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
err = -ENXIO;
goto _error;
}
+ mutex_lock(&pcm->open_mutex);
err = snd_pcm_info_user(substream, info);
+ mutex_unlock(&pcm->open_mutex);
_error:
mutex_unlock(&register_mutex);
return err;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 10e7ef7..db7894b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1632,7 +1632,7 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
return changed;
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
- if (snd_BUG_ON(err < 0))
+ if (err < 0)
return err;
}
return snd_pcm_hw_param_value(params, var, dir);
@@ -1678,7 +1678,7 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
return changed;
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
- if (snd_BUG_ON(err < 0))
+ if (err < 0)
return err;
}
return snd_pcm_hw_param_value(params, var, dir);
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 9be8102..c4eb561 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -163,13 +163,30 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
.width = 32, .phys = 32, .le = 0, .signd = 0,
.silence = { 0x69, 0x69, 0x69, 0x69 },
},
- /* FIXME: the following three formats are not defined properly yet */
+ /* FIXME: the following two formats are not defined properly yet */
[SNDRV_PCM_FORMAT_MPEG] = {
.le = -1, .signd = -1,
},
[SNDRV_PCM_FORMAT_GSM] = {
.le = -1, .signd = -1,
},
+ [SNDRV_PCM_FORMAT_S20_LE] = {
+ .width = 20, .phys = 32, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S20_BE] = {
+ .width = 20, .phys = 32, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U20_LE] = {
+ .width = 20, .phys = 32, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x00, 0x08, 0x00 },
+ },
+ [SNDRV_PCM_FORMAT_U20_BE] = {
+ .width = 20, .phys = 32, .le = 0, .signd = 0,
+ .silence = { 0x00, 0x08, 0x00, 0x00 },
+ },
+ /* FIXME: the following format is not defined properly yet */
[SNDRV_PCM_FORMAT_SPECIAL] = {
.le = -1, .signd = -1,
},
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a4d92e4..f087725 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2580,7 +2580,7 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
return ret < 0 ? ret : frames;
}
-/* decrease the appl_ptr; returns the processed frames or a negative error */
+/* decrease the appl_ptr; returns the processed frames or zero for error */
static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames,
snd_pcm_sframes_t avail)
@@ -2597,7 +2597,12 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
if (appl_ptr < 0)
appl_ptr += runtime->boundary;
ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
- return ret < 0 ? ret : frames;
+ /* NOTE: we return zero for errors because PulseAudio gets depressed
+ * upon receiving an error from rewind ioctl and stops processing
+ * any longer. Returning zero means that no rewind is done, so
+ * it's not absolutely wrong to answer like that.
+ */
+ return ret < 0 ? 0 : frames;
}
static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index b3b353d..f055ca1 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -579,15 +579,14 @@ static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream,
return 0;
}
-int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
+static int __snd_rawmidi_info_select(struct snd_card *card,
+ struct snd_rawmidi_info *info)
{
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *pstr;
struct snd_rawmidi_substream *substream;
- mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, info->device);
- mutex_unlock(&register_mutex);
if (!rmidi)
return -ENXIO;
if (info->stream < 0 || info->stream > 1)
@@ -603,6 +602,16 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
}
return -ENXIO;
}
+
+int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
+{
+ int ret;
+
+ mutex_lock(&register_mutex);
+ ret = __snd_rawmidi_info_select(card, info);
+ mutex_unlock(&register_mutex);
+ return ret;
+}
EXPORT_SYMBOL(snd_rawmidi_info_select);
static int snd_rawmidi_info_select_user(struct snd_card *card,
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 37d9cfb..b80985f 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -355,7 +355,7 @@ static int initialize_timer(struct snd_seq_timer *tmr)
unsigned long freq;
t = tmr->timeri->timer;
- if (snd_BUG_ON(!t))
+ if (!t)
return -EINVAL;
freq = tmr->preferred_resolution;
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index afac886..0333143 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -39,6 +39,7 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/initval.h>
@@ -305,19 +306,6 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}
-static void params_change_substream(struct loopback_pcm *dpcm,
- struct snd_pcm_runtime *runtime)
-{
- struct snd_pcm_runtime *dst_runtime;
-
- if (dpcm == NULL || dpcm->substream == NULL)
- return;
- dst_runtime = dpcm->substream->runtime;
- if (dst_runtime == NULL)
- return;
- dst_runtime->hw = dpcm->cable->hw;
-}
-
static void params_change(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -329,10 +317,6 @@ static void params_change(struct snd_pcm_substream *substream)
cable->hw.rate_max = runtime->rate;
cable->hw.channels_min = runtime->channels;
cable->hw.channels_max = runtime->channels;
- params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
- runtime);
- params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
- runtime);
}
static int loopback_prepare(struct snd_pcm_substream *substream)
@@ -620,26 +604,29 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream)
static int rule_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
+ struct loopback_pcm *dpcm = rule->private;
+ struct loopback_cable *cable = dpcm->cable;
+ struct snd_mask m;
- struct snd_pcm_hardware *hw = rule->private;
- struct snd_mask *maskp = hw_param_mask(params, rule->var);
-
- maskp->bits[0] &= (u_int32_t)hw->formats;
- maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
- memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
- if (! maskp->bits[0] && ! maskp->bits[1])
- return -EINVAL;
- return 0;
+ snd_mask_none(&m);
+ mutex_lock(&dpcm->loopback->cable_lock);
+ m.bits[0] = (u_int32_t)cable->hw.formats;
+ m.bits[1] = (u_int32_t)(cable->hw.formats >> 32);
+ mutex_unlock(&dpcm->loopback->cable_lock);
+ return snd_mask_refine(hw_param_mask(params, rule->var), &m);
}
static int rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
- struct snd_pcm_hardware *hw = rule->private;
+ struct loopback_pcm *dpcm = rule->private;
+ struct loopback_cable *cable = dpcm->cable;
struct snd_interval t;
- t.min = hw->rate_min;
- t.max = hw->rate_max;
+ mutex_lock(&dpcm->loopback->cable_lock);
+ t.min = cable->hw.rate_min;
+ t.max = cable->hw.rate_max;
+ mutex_unlock(&dpcm->loopback->cable_lock);
t.openmin = t.openmax = 0;
t.integer = 0;
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
@@ -648,22 +635,44 @@ static int rule_rate(struct snd_pcm_hw_params *params,
static int rule_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
- struct snd_pcm_hardware *hw = rule->private;
+ struct loopback_pcm *dpcm = rule->private;
+ struct loopback_cable *cable = dpcm->cable;
struct snd_interval t;
- t.min = hw->channels_min;
- t.max = hw->channels_max;
+ mutex_lock(&dpcm->loopback->cable_lock);
+ t.min = cable->hw.channels_min;
+ t.max = cable->hw.channels_max;
+ mutex_unlock(&dpcm->loopback->cable_lock);
t.openmin = t.openmax = 0;
t.integer = 0;
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
+static void free_cable(struct snd_pcm_substream *substream)
+{
+ struct loopback *loopback = substream->private_data;
+ int dev = get_cable_index(substream);
+ struct loopback_cable *cable;
+
+ cable = loopback->cables[substream->number][dev];
+ if (!cable)
+ return;
+ if (cable->streams[!substream->stream]) {
+ /* other stream is still alive */
+ cable->streams[substream->stream] = NULL;
+ } else {
+ /* free the cable */
+ loopback->cables[substream->number][dev] = NULL;
+ kfree(cable);
+ }
+}
+
static int loopback_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct loopback *loopback = substream->private_data;
struct loopback_pcm *dpcm;
- struct loopback_cable *cable;
+ struct loopback_cable *cable = NULL;
int err = 0;
int dev = get_cable_index(substream);
@@ -681,7 +690,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
if (!cable) {
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
if (!cable) {
- kfree(dpcm);
err = -ENOMEM;
goto unlock;
}
@@ -699,19 +707,19 @@ static int loopback_open(struct snd_pcm_substream *substream)
/* are cached -> they do not reflect the actual state */
err = snd_pcm_hw_rule_add(runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
- rule_format, &runtime->hw,
+ rule_format, dpcm,
SNDRV_PCM_HW_PARAM_FORMAT, -1);
if (err < 0)
goto unlock;
err = snd_pcm_hw_rule_add(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
- rule_rate, &runtime->hw,
+ rule_rate, dpcm,
SNDRV_PCM_HW_PARAM_RATE, -1);
if (err < 0)
goto unlock;
err = snd_pcm_hw_rule_add(runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
- rule_channels, &runtime->hw,
+ rule_channels, dpcm,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (err < 0)
goto unlock;
@@ -723,6 +731,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
else
runtime->hw = cable->hw;
unlock:
+ if (err < 0) {
+ free_cable(substream);
+ kfree(dpcm);
+ }
mutex_unlock(&loopback->cable_lock);
return err;
}
@@ -731,20 +743,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
{
struct loopback *loopback = substream->private_data;
struct loopback_pcm *dpcm = substream->runtime->private_data;
- struct loopback_cable *cable;
- int dev = get_cable_index(substream);
loopback_timer_stop(dpcm);
mutex_lock(&loopback->cable_lock);
- cable = loopback->cables[substream->number][dev];
- if (cable->streams[!substream->stream]) {
- /* other stream is still alive */
- cable->streams[substream->stream] = NULL;
- } else {
- /* free the cable */
- loopback->cables[substream->number][dev] = NULL;
- kfree(cable);
- }
+ free_cable(substream);
mutex_unlock(&loopback->cable_lock);
return 0;
}
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index 31b510c..0daf313 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -146,7 +146,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
if (!edev)
return -ENOMEM;
- hdev = &edev->hdac;
+ hdev = &edev->hdev;
edev->ebus = ebus;
snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index 038a180..cbe818e 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -325,7 +325,7 @@ static int hdac_component_master_match(struct device *dev, void *data)
*/
int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops)
{
- if (WARN_ON(!hdac_acomp))
+ if (!hdac_acomp)
return -ENODEV;
hdac_acomp->audio_ops = aops;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index a81aacf..37e1cf8 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -271,6 +271,8 @@ enum {
CXT_FIXUP_HP_SPECTRE,
CXT_FIXUP_HP_GATE_MIC,
CXT_FIXUP_MUTE_LED_GPIO,
+ CXT_FIXUP_HEADSET_MIC,
+ CXT_FIXUP_HP_MIC_NO_PRESENCE,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -350,6 +352,18 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec,
}
}
+static void cxt_fixup_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct conexant_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ break;
+ }
+}
+
/* OPLC XO 1.5 fixup */
/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
@@ -880,6 +894,19 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_mute_led_gpio,
},
+ [CXT_FIXUP_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_headset_mic,
+ },
+ [CXT_FIXUP_HP_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x02a1113c },
+ { }
+ },
+ .chained = true,
+ .chain_id = CXT_FIXUP_HEADSET_MIC,
+ },
};
static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -934,6 +961,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index c19c81d..b4f1b6e 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -55,10 +55,11 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b)
#define is_geminilake(codec) (((codec)->core.vendor_id == 0x8086280d) || \
((codec)->core.vendor_id == 0x80862800))
+#define is_cannonlake(codec) ((codec)->core.vendor_id == 0x8086280c)
#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
|| is_skylake(codec) || is_broxton(codec) \
- || is_kabylake(codec)) || is_geminilake(codec)
-
+ || is_kabylake(codec)) || is_geminilake(codec) \
+ || is_cannonlake(codec)
#define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
#define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec))
@@ -3841,6 +3842,7 @@ HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi),
HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 921a10e..8fd2d9c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -324,21 +324,24 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0292:
alc_update_coef_idx(codec, 0x4, 1<<15, 0);
break;
- case 0x10ec0215:
case 0x10ec0225:
+ case 0x10ec0295:
+ case 0x10ec0299:
+ alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+ /* fallthrough */
+ case 0x10ec0215:
case 0x10ec0233:
case 0x10ec0236:
case 0x10ec0255:
case 0x10ec0256:
+ case 0x10ec0257:
case 0x10ec0282:
case 0x10ec0283:
case 0x10ec0286:
case 0x10ec0288:
case 0x10ec0285:
- case 0x10ec0295:
case 0x10ec0298:
case 0x10ec0289:
- case 0x10ec0299:
alc_update_coef_idx(codec, 0x10, 1<<9, 0);
break;
case 0x10ec0275:
@@ -2772,6 +2775,7 @@ enum {
ALC269_TYPE_ALC298,
ALC269_TYPE_ALC255,
ALC269_TYPE_ALC256,
+ ALC269_TYPE_ALC257,
ALC269_TYPE_ALC215,
ALC269_TYPE_ALC225,
ALC269_TYPE_ALC294,
@@ -2805,6 +2809,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
case ALC269_TYPE_ALC298:
case ALC269_TYPE_ALC255:
case ALC269_TYPE_ALC256:
+ case ALC269_TYPE_ALC257:
case ALC269_TYPE_ALC215:
case ALC269_TYPE_ALC225:
case ALC269_TYPE_ALC294:
@@ -5182,6 +5187,22 @@ static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
}
}
+/* Forcibly assign NID 0x03 to HP/LO while NID 0x02 to SPK for EQ */
+static void alc274_fixup_bind_dacs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static hda_nid_t preferred_pairs[] = {
+ 0x21, 0x03, 0x1b, 0x03, 0x16, 0x02,
+ 0
+ };
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+
+ spec->gen.preferred_dacs = preferred_pairs;
+}
+
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
@@ -5299,6 +5320,8 @@ enum {
ALC233_FIXUP_LENOVO_MULTI_CODECS,
ALC294_FIXUP_LENOVO_MIC_LOCATION,
ALC700_FIXUP_INTEL_REFERENCE,
+ ALC274_FIXUP_DELL_BIND_DACS,
+ ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -6109,6 +6132,21 @@ static const struct hda_fixup alc269_fixups[] = {
{}
}
},
+ [ALC274_FIXUP_DELL_BIND_DACS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc274_fixup_bind_dacs,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
+ [ALC274_FIXUP_DELL_AIO_LINEOUT_VERB] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x0401102f },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC274_FIXUP_DELL_BIND_DACS
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6292,6 +6330,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+ SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
@@ -6550,6 +6589,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x1b, 0x01011020},
{0x21, 0x02211010}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ {0x12, 0x90a60130},
+ {0x14, 0x90170110},
+ {0x1b, 0x01011020},
+ {0x21, 0x0221101f}),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60160},
{0x14, 0x90170120},
{0x21, 0x02211030}),
@@ -6575,7 +6619,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x14, 0x90170110},
{0x1b, 0x90a70130},
{0x21, 0x03211020}),
- SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
{0x12, 0xb7a60130},
{0x13, 0xb8a61140},
{0x16, 0x90170110},
@@ -6867,6 +6911,10 @@ static int patch_alc269(struct hda_codec *codec)
spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
break;
+ case 0x10ec0257:
+ spec->codec_variant = ALC269_TYPE_ALC257;
+ spec->gen.mixer_nid = 0;
+ break;
case 0x10ec0215:
case 0x10ec0285:
case 0x10ec0289:
@@ -7914,6 +7962,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
+ HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 9f521a5..c33a512 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -850,6 +850,9 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
+ if (!rtd)
+ return -EINVAL;
+
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
@@ -875,6 +878,8 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
+ if (!rtd)
+ return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
PLAYBACK_START_DMA_DESCR_CH12,
@@ -1051,6 +1056,11 @@ static int acp_audio_probe(struct platform_device *pdev)
struct resource *res;
const u32 *pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -ENODEV;
+ }
+
audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
GFP_KERNEL);
if (audio_drv_data == NULL)
@@ -1058,6 +1068,8 @@ static int acp_audio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(audio_drv_data->acp_mmio))
+ return PTR_ERR(audio_drv_data->acp_mmio);
/* The following members gets populated in device 'open'
* function. Till then interrupts are disabled in 'acp_init'
@@ -1084,7 +1096,11 @@ static int acp_audio_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, audio_drv_data);
/* Initialize the ACP */
- acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type);
+ status = acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type);
+ if (status) {
+ dev_err(&pdev->dev, "ACP Init failed status:%d\n", status);
+ return status;
+ }
status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
if (status != 0) {
@@ -1101,9 +1117,12 @@ static int acp_audio_probe(struct platform_device *pdev)
static int acp_audio_remove(struct platform_device *pdev)
{
+ int status;
struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev);
- acp_deinit(adata->acp_mmio);
+ status = acp_deinit(adata->acp_mmio);
+ if (status)
+ dev_err(&pdev->dev, "ACP Deinit failed status:%d\n", status);
snd_soc_unregister_platform(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1113,9 +1132,14 @@ static int acp_audio_remove(struct platform_device *pdev)
static int acp_pcm_resume(struct device *dev)
{
u16 bank;
+ int status;
struct audio_drv_data *adata = dev_get_drvdata(dev);
- acp_init(adata->acp_mmio, adata->asic_type);
+ status = acp_init(adata->acp_mmio, adata->asic_type);
+ if (status) {
+ dev_err(dev, "ACP Init failed status:%d\n", status);
+ return status;
+ }
if (adata->play_stream && adata->play_stream->runtime) {
/* For Stoney, Memory gating is disabled,i.e SRAM Banks
@@ -1147,18 +1171,26 @@ static int acp_pcm_resume(struct device *dev)
static int acp_pcm_runtime_suspend(struct device *dev)
{
+ int status;
struct audio_drv_data *adata = dev_get_drvdata(dev);
- acp_deinit(adata->acp_mmio);
+ status = acp_deinit(adata->acp_mmio);
+ if (status)
+ dev_err(dev, "ACP Deinit failed status:%d\n", status);
acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static int acp_pcm_runtime_resume(struct device *dev)
{
+ int status;
struct audio_drv_data *adata = dev_get_drvdata(dev);
- acp_init(adata->acp_mmio, adata->asic_type);
+ status = acp_init(adata->acp_mmio, adata->asic_type);
+ if (status) {
+ dev_err(dev, "ACP Init failed status:%d\n", status);
+ return status;
+ }
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
return 0;
}
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 4a56f3d..dcee145 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -64,7 +64,7 @@ config SND_AT91_SOC_SAM9X5_WM8731
config SND_ATMEL_SOC_CLASSD
tristate "Atmel ASoC driver for boards using CLASSD"
depends on ARCH_AT91 || COMPILE_TEST
- select SND_ATMEL_SOC_DMA
+ select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
Say Y if you want to add support for Atmel ASoC driver for boards using
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 8445edd..ebabed6 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -308,15 +308,9 @@ static int atmel_classd_codec_resume(struct snd_soc_codec *codec)
return regcache_sync(dd->regmap);
}
-static struct regmap *atmel_classd_codec_get_remap(struct device *dev)
-{
- return dev_get_regmap(dev, NULL);
-}
-
static struct snd_soc_codec_driver soc_codec_dev_classd = {
.probe = atmel_classd_codec_probe,
.resume = atmel_classd_codec_resume,
- .get_regmap = atmel_classd_codec_get_remap,
.component_driver = {
.controls = atmel_classd_snd_controls,
.num_controls = ARRAY_SIZE(atmel_classd_snd_controls),
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
index 29a97d5..66d6c52 100644
--- a/sound/soc/au1x/ac97c.c
+++ b/sound/soc/au1x/ac97c.c
@@ -91,8 +91,8 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
do {
mutex_lock(&ctx->lock);
- tmo = 5;
- while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+ tmo = 6;
+ while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo)
udelay(21); /* wait an ac97 frame time */
if (!tmo) {
pr_debug("ac97rd timeout #1\n");
@@ -105,7 +105,7 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
* poll, Forrest, poll...
*/
tmo = 0x10000;
- while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+ while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo)
asm volatile ("nop");
data = RD(ctx, AC97_CMDRESP);
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 2e449d7..d5f73a8 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -130,6 +130,7 @@ struct bcm2835_i2s_dev {
struct regmap *i2s_regmap;
struct clk *clk;
bool clk_prepared;
+ int clk_rate;
};
static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
@@ -419,10 +420,19 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
}
/* Clock should only be set up here if CPU is clock master */
- if (bit_clock_master) {
- ret = clk_set_rate(dev->clk, bclk_rate);
- if (ret)
- return ret;
+ if (bit_clock_master &&
+ (!dev->clk_prepared || dev->clk_rate != bclk_rate)) {
+ if (dev->clk_prepared)
+ bcm2835_i2s_stop_clock(dev);
+
+ if (dev->clk_rate != bclk_rate) {
+ ret = clk_set_rate(dev->clk, bclk_rate);
+ if (ret)
+ return ret;
+ dev->clk_rate = bclk_rate;
+ }
+
+ bcm2835_i2s_start_clock(dev);
}
/* Setup the frame format */
@@ -618,8 +628,6 @@ static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream,
struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
uint32_t cs_reg;
- bcm2835_i2s_start_clock(dev);
-
/*
* Clear both FIFOs if the one that should be started
* is not empty at the moment. This should only happen
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index bbf7a92..cd5a939 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -365,7 +365,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
{
struct ep93xx_ac97_info *info;
struct resource *res;
- unsigned int irq;
+ int irq;
int ret;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -378,8 +378,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
- if (!irq)
- return -ENODEV;
+ if (irq <= 0)
+ return irq < 0 ? irq : -ENODEV;
ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
IRQF_TRIGGER_HIGH, pdev->name, info);
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 848c5fe..be8ea72 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -1319,6 +1319,7 @@ static int pm860x_probe(struct snd_soc_codec *codec)
int i, ret;
pm860x->codec = codec;
+ snd_soc_codec_init_regmap(codec, pm860x->regmap);
for (i = 0; i < 4; i++) {
ret = request_threaded_irq(pm860x->irq[i], NULL,
@@ -1348,18 +1349,10 @@ static int pm860x_remove(struct snd_soc_codec *codec)
return 0;
}
-static struct regmap *pm860x_get_regmap(struct device *dev)
-{
- struct pm860x_priv *pm860x = dev_get_drvdata(dev);
-
- return pm860x->regmap;
-}
-
static const struct snd_soc_codec_driver soc_codec_dev_pm860x = {
.probe = pm860x_probe,
.remove = pm860x_remove,
.set_bias_level = pm860x_set_bias_level,
- .get_regmap = pm860x_get_regmap,
.component_driver = {
.controls = pm860x_snd_controls,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index a42ddbc..f7723a9 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -95,6 +95,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX98925 if I2C
select SND_SOC_MAX98926 if I2C
select SND_SOC_MAX98927 if I2C
+ select SND_SOC_MAX98373 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9860 if I2C
select SND_SOC_MAX9768 if I2C
@@ -109,6 +110,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM179X_I2C if I2C
select SND_SOC_PCM179X_SPI if SPI_MASTER
+ select SND_SOC_PCM186X_I2C if I2C
+ select SND_SOC_PCM186X_SPI if SPI_MASTER
select SND_SOC_PCM3008
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
@@ -133,7 +136,6 @@ config SND_SOC_ALL_CODECS
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
- select SND_SOC_SN95031 if INTEL_SCU_IPC
select SND_SOC_SPDIF
select SND_SOC_SSM2518 if I2C
select SND_SOC_SSM2602_SPI if SPI_MASTER
@@ -623,6 +625,10 @@ config SND_SOC_MAX98927
tristate "Maxim Integrated MAX98927 Speaker Amplifier"
depends on I2C
+config SND_SOC_MAX98373
+ tristate "Maxim Integrated MAX98373 Speaker Amplifier"
+ depends on I2C
+
config SND_SOC_MAX9850
tristate
@@ -661,6 +667,21 @@ config SND_SOC_PCM179X_SPI
Enable support for Texas Instruments PCM179x CODEC.
Select this if your PCM179x is connected via an SPI bus.
+config SND_SOC_PCM186X
+ tristate
+
+config SND_SOC_PCM186X_I2C
+ tristate "Texas Instruments PCM186x CODECs - I2C"
+ depends on I2C
+ select SND_SOC_PCM186X
+ select REGMAP_I2C
+
+config SND_SOC_PCM186X_SPI
+ tristate "Texas Instruments PCM186x CODECs - SPI"
+ depends on SPI_MASTER
+ select SND_SOC_PCM186X
+ select REGMAP_SPI
+
config SND_SOC_PCM3008
tristate
@@ -818,9 +839,6 @@ config SND_SOC_SIRF_AUDIO_CODEC
tristate "SiRF SoC internal audio codec"
select REGMAP_MMIO
-config SND_SOC_SN95031
- tristate
-
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0001069..d8a4a42 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -90,6 +90,7 @@ snd-soc-max9867-objs := max9867.o
snd-soc-max98925-objs := max98925.o
snd-soc-max98926-objs := max98926.o
snd-soc-max98927-objs := max98927.o
+snd-soc-max98373-objs := max98373.o
snd-soc-max9850-objs := max9850.o
snd-soc-max9860-objs := max9860.o
snd-soc-mc13783-objs := mc13783.o
@@ -105,6 +106,9 @@ snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm179x-codec-objs := pcm179x.o
snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o
snd-soc-pcm179x-spi-objs := pcm179x-spi.o
+snd-soc-pcm186x-objs := pcm186x.o
+snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
+snd-soc-pcm186x-spi-objs := pcm186x-spi.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-pcm3168a-objs := pcm3168a.o
snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
@@ -140,7 +144,6 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
snd-soc-si476x-objs := si476x.o
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
-snd-soc-sn95031-objs := sn95031.o
snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o
snd-soc-ssm2518-objs := ssm2518.o
@@ -330,6 +333,7 @@ obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o
+obj-$(CONFIG_SND_SOC_MAX98373) += snd-soc-max98373.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
@@ -345,6 +349,9 @@ obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o
obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o
+obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o
+obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 6ed2cc3..3bf9365 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -121,17 +121,19 @@ static struct snd_soc_dai_driver cq93vc_dai = {
.ops = &cq93vc_dai_ops,
};
-static struct regmap *cq93vc_get_regmap(struct device *dev)
+static int cq93vc_probe(struct snd_soc_component *component)
{
- struct davinci_vc *davinci_vc = dev->platform_data;
+ struct davinci_vc *davinci_vc = component->dev->platform_data;
- return davinci_vc->regmap;
+ snd_soc_component_init_regmap(component, davinci_vc->regmap);
+
+ return 0;
}
static const struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
.set_bias_level = cq93vc_set_bias_level,
- .get_regmap = cq93vc_get_regmap,
.component_driver = {
+ .probe = cq93vc_probe,
.controls = cq93vc_snd_controls,
.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
},
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 7e98062..bc3a72e 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -355,13 +355,9 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
unsigned int devid = 0;
unsigned int reg;
-
- cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private),
- GFP_KERNEL);
- if (!cs35l32) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
+ cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l32), GFP_KERNEL);
+ if (!cs35l32)
return -ENOMEM;
- }
i2c_set_clientdata(i2c_client, cs35l32);
@@ -375,13 +371,11 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
if (pdata) {
cs35l32->pdata = *pdata;
} else {
- pdata = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs35l32_platform_data),
- GFP_KERNEL);
- if (!pdata) {
- dev_err(&i2c_client->dev, "could not allocate pdata\n");
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+ GFP_KERNEL);
+ if (!pdata)
return -ENOMEM;
- }
+
if (i2c_client->dev.of_node) {
ret = cs35l32_handle_of_data(i2c_client,
&cs35l32->pdata);
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 1e05026..0600d52 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -1004,13 +1004,9 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client,
unsigned int devid = 0;
unsigned int reg;
- cs35l34 = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs35l34_private),
- GFP_KERNEL);
- if (!cs35l34) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
+ cs35l34 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l34), GFP_KERNEL);
+ if (!cs35l34)
return -ENOMEM;
- }
i2c_set_clientdata(i2c_client, cs35l34);
cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap);
@@ -1044,14 +1040,11 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client,
if (pdata) {
cs35l34->pdata = *pdata;
} else {
- pdata = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs35l34_platform_data),
- GFP_KERNEL);
- if (!pdata) {
- dev_err(&i2c_client->dev,
- "could not allocate pdata\n");
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+ GFP_KERNEL);
+ if (!pdata)
return -ENOMEM;
- }
+
if (i2c_client->dev.of_node) {
ret = cs35l34_handle_of_data(i2c_client, pdata);
if (ret != 0)
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 0d9c4a5..9731e5d 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -1100,8 +1100,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
unsigned int reg;
u32 val32;
- cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
- GFP_KERNEL);
+ cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l52), GFP_KERNEL);
if (cs42l52 == NULL)
return -ENOMEM;
cs42l52->dev = &i2c_client->dev;
@@ -1115,13 +1114,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
if (pdata) {
cs42l52->pdata = *pdata;
} else {
- pdata = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs42l52_platform_data),
- GFP_KERNEL);
- if (!pdata) {
- dev_err(&i2c_client->dev, "could not allocate pdata\n");
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+ GFP_KERNEL);
+ if (!pdata)
return -ENOMEM;
- }
+
if (i2c_client->dev.of_node) {
if (of_property_read_bool(i2c_client->dev.of_node,
"cirrus,mica-differential-cfg"))
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index cb6ca85..fd7b8d3 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -1190,9 +1190,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
unsigned int alpha_rev, metal_rev;
unsigned int reg;
- cs42l56 = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs42l56_private),
- GFP_KERNEL);
+ cs42l56 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l56), GFP_KERNEL);
if (cs42l56 == NULL)
return -ENOMEM;
cs42l56->dev = &i2c_client->dev;
@@ -1207,14 +1205,11 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
if (pdata) {
cs42l56->pdata = *pdata;
} else {
- pdata = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs42l56_platform_data),
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
GFP_KERNEL);
- if (!pdata) {
- dev_err(&i2c_client->dev,
- "could not allocate pdata\n");
+ if (!pdata)
return -ENOMEM;
- }
+
if (i2c_client->dev.of_node) {
ret = cs42l56_handle_of_data(i2c_client,
&cs42l56->pdata);
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 3df2c47..aebaa97 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1289,8 +1289,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
unsigned int reg;
u32 val32;
- cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private),
- GFP_KERNEL);
+ cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l73), GFP_KERNEL);
if (!cs42l73)
return -ENOMEM;
@@ -1304,13 +1303,11 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
if (pdata) {
cs42l73->pdata = *pdata;
} else {
- pdata = devm_kzalloc(&i2c_client->dev,
- sizeof(struct cs42l73_platform_data),
- GFP_KERNEL);
- if (!pdata) {
- dev_err(&i2c_client->dev, "could not allocate pdata\n");
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+ GFP_KERNEL);
+ if (!pdata)
return -ENOMEM;
- }
+
if (i2c_client->dev.of_node) {
if (of_property_read_u32(i2c_client->dev.of_node,
"chgfreq", &val32) >= 0)
@@ -1358,7 +1355,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg);
if (ret < 0) {
dev_err(&i2c_client->dev, "Get Revision ID failed\n");
- return ret;;
+ return ret;
}
dev_info(&i2c_client->dev,
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 94c0209..be27506 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -1120,9 +1120,11 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct arizona *arizona = priv->core.arizona;
int ret;
- priv->core.arizona->dapm = dapm;
+ arizona->dapm = dapm;
+ snd_soc_codec_init_regmap(codec, arizona->regmap);
ret = arizona_init_spk(codec);
if (ret < 0)
@@ -1175,17 +1177,9 @@ static unsigned int cs47l24_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_4L,
};
-static struct regmap *cs47l24_get_regmap(struct device *dev)
-{
- struct cs47l24_priv *priv = dev_get_drvdata(dev);
-
- return priv->core.arizona->regmap;
-}
-
static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
.probe = cs47l24_codec_probe,
.remove = cs47l24_codec_remove,
- .get_regmap = cs47l24_get_regmap,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 46b1fbb..95bb10b 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -26,8 +26,9 @@
struct cx20442_priv {
- void *control_data;
+ struct tty_struct *tty;
struct regulator *por;
+ u8 reg_cache;
};
#define CX20442_PM 0x0
@@ -89,14 +90,14 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
};
static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
+ unsigned int reg)
{
- u8 *reg_cache = codec->reg_cache;
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
- if (reg >= codec->driver->reg_cache_size)
+ if (reg >= 1)
return -EINVAL;
- return reg_cache[reg];
+ return cx20442->reg_cache;
}
enum v253_vls {
@@ -156,20 +157,19 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
- u8 *reg_cache = codec->reg_cache;
int vls, vsp, old, len;
char buf[18];
- if (reg >= codec->driver->reg_cache_size)
+ if (reg >= 1)
return -EINVAL;
- /* hw_write and control_data pointers required for talking to the modem
+ /* tty and write pointers required for talking to the modem
* are expected to be set by the line discipline initialization code */
- if (!codec->hw_write || !cx20442->control_data)
+ if (!cx20442->tty || !cx20442->tty->ops->write)
return -EIO;
- old = reg_cache[reg];
- reg_cache[reg] = value;
+ old = cx20442->reg_cache;
+ cx20442->reg_cache = value;
vls = cx20442_pm_to_v253_vls(value);
if (vls < 0)
@@ -194,13 +194,12 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
return -ENOMEM;
dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
- if (codec->hw_write(cx20442->control_data, buf, len) != len)
+ if (cx20442->tty->ops->write(cx20442->tty, buf, len) != len)
return -EIO;
return 0;
}
-
/*
* Line discpline related code
*
@@ -252,8 +251,7 @@ static void v253_close(struct tty_struct *tty)
cx20442 = snd_soc_codec_get_drvdata(codec);
/* Prevent the codec driver from further accessing the modem */
- codec->hw_write = NULL;
- cx20442->control_data = NULL;
+ cx20442->tty = NULL;
codec->component.card->pop_time = 0;
}
@@ -276,12 +274,11 @@ static void v253_receive(struct tty_struct *tty,
cx20442 = snd_soc_codec_get_drvdata(codec);
- if (!cx20442->control_data) {
+ if (!cx20442->tty) {
/* First modem response, complete setup procedure */
/* Set up codec driver access to modem controls */
- cx20442->control_data = tty;
- codec->hw_write = (hw_write_t)tty->ops->write;
+ cx20442->tty = tty;
codec->component.card->pop_time = 1;
}
}
@@ -367,10 +364,9 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
cx20442->por = regulator_get(codec->dev, "POR");
if (IS_ERR(cx20442->por))
dev_warn(codec->dev, "failed to get the regulator");
- cx20442->control_data = NULL;
+ cx20442->tty = NULL;
snd_soc_codec_set_drvdata(codec, cx20442);
- codec->hw_write = NULL;
codec->component.card->pop_time = 0;
return 0;
@@ -381,8 +377,8 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
{
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
- if (cx20442->control_data) {
- struct tty_struct *tty = cx20442->control_data;
+ if (cx20442->tty) {
+ struct tty_struct *tty = cx20442->tty;
tty_hangup(tty);
}
@@ -396,17 +392,13 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
return 0;
}
-static const u8 cx20442_reg;
-
static const struct snd_soc_codec_driver cx20442_codec_dev = {
.probe = cx20442_codec_probe,
.remove = cx20442_codec_remove,
.set_bias_level = cx20442_set_bias_level,
- .reg_cache_default = &cx20442_reg,
- .reg_cache_size = 1,
- .reg_word_size = sizeof(u8),
.read = cx20442_read_reg_cache,
.write = cx20442_write,
+
.component_driver = {
.dapm_widgets = cx20442_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 41d9b1d..b2b4e90 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1654,10 +1654,8 @@ static struct da7213_platform_data
u32 fw_val32;
pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_warn(codec->dev, "Failed to allocate memory for pdata\n");
+ if (!pdata)
return NULL;
- }
if (device_property_read_u32(dev, "dlg,micbias1-lvl", &fw_val32) >= 0)
pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, fw_val32);
@@ -1855,8 +1853,7 @@ static int da7213_i2c_probe(struct i2c_client *i2c,
struct da7213_priv *da7213;
int ret;
- da7213 = devm_kzalloc(&i2c->dev, sizeof(struct da7213_priv),
- GFP_KERNEL);
+ da7213 = devm_kzalloc(&i2c->dev, sizeof(*da7213), GFP_KERNEL);
if (!da7213)
return -ENOMEM;
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index b2d42ec..96c644a 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -2455,10 +2455,8 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
u32 of_val32;
pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_warn(codec->dev, "Failed to allocate memory for pdata\n");
+ if (!pdata)
return NULL;
- }
if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0)
pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32);
@@ -2520,15 +2518,13 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
}
if (da7218->dev_id == DA7218_DEV_ID) {
- hpldet_np = of_find_node_by_name(np, "da7218_hpldet");
+ hpldet_np = of_get_child_by_name(np, "da7218_hpldet");
if (!hpldet_np)
return pdata;
hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata),
GFP_KERNEL);
if (!hpldet_pdata) {
- dev_warn(codec->dev,
- "Failed to allocate memory for hpldet pdata\n");
of_node_put(hpldet_np);
return pdata;
}
@@ -3273,8 +3269,7 @@ static int da7218_i2c_probe(struct i2c_client *i2c,
struct da7218_priv *da7218;
int ret;
- da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv),
- GFP_KERNEL);
+ da7218 = devm_kzalloc(&i2c->dev, sizeof(*da7218), GFP_KERNEL);
if (!da7218)
return -ENOMEM;
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index b88a1ee..c88f974 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -107,8 +107,30 @@ static const struct snd_soc_codec_driver soc_dmic = {
static int dmic_dev_probe(struct platform_device *pdev)
{
+ int err;
+ u32 chans;
+ struct snd_soc_dai_driver *dai_drv = &dmic_dai;
+
+ if (pdev->dev.of_node) {
+ err = of_property_read_u32(pdev->dev.of_node, "num-channels", &chans);
+ if (err && (err != -ENOENT))
+ return err;
+
+ if (!err) {
+ if (chans < 1 || chans > 8)
+ return -EINVAL;
+
+ dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+
+ memcpy(dai_drv, &dmic_dai, sizeof(*dai_drv));
+ dai_drv->capture.channels_max = chans;
+ }
+ }
+
return snd_soc_register_codec(&pdev->dev,
- &soc_dmic, &dmic_dai, 1);
+ &soc_dmic, dai_drv, 1);
}
static int dmic_dev_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index f3b4f4d..dba6f4c 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -136,8 +136,11 @@ struct hdac_hdmi_priv {
struct mutex pin_mutex;
struct hdac_chmap chmap;
struct hdac_hdmi_drv_data *drv_data;
+ struct snd_soc_dai_driver *dai_drv;
};
+#define hdev_to_hdmi_priv(_hdev) ((to_ehdac_device(_hdev))->private_data)
+
static struct hdac_hdmi_pcm *
hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
struct hdac_hdmi_cvt *cvt)
@@ -169,7 +172,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
* ports.
*/
if (pcm->jack_event == 0) {
- dev_dbg(&edev->hdac.dev,
+ dev_dbg(&edev->hdev.dev,
"jack report for pcm=%d\n",
pcm->pcm_id);
snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT,
@@ -195,18 +198,18 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
/*
* Get the no devices that can be connected to a port on the Pin widget.
*/
-static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid)
+static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid)
{
unsigned int caps;
unsigned int type, param;
- caps = get_wcaps(&hdac->hdac, nid);
+ caps = get_wcaps(&edev->hdev, nid);
type = get_wcaps_type(caps);
if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
return 0;
- param = snd_hdac_read_parm_uncached(&hdac->hdac, nid,
+ param = snd_hdac_read_parm_uncached(&edev->hdev, nid,
AC_PAR_DEVLIST_LEN);
if (param == -1)
return param;
@@ -219,10 +222,10 @@ static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid)
* id selected on the pin. Return 0 means the first port entry
* is selected or MST is not supported.
*/
-static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac,
+static int hdac_hdmi_port_select_get(struct hdac_ext_device *edev,
struct hdac_hdmi_port *port)
{
- return snd_hdac_codec_read(&hdac->hdac, port->pin->nid,
+ return snd_hdac_codec_read(&edev->hdev, port->pin->nid,
0, AC_VERB_GET_DEVICE_SEL, 0);
}
@@ -230,7 +233,7 @@ static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac,
* Sets the selected port entry for the configuring Pin widget verb.
* returns error if port set is not equal to port get otherwise success
*/
-static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac,
+static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev,
struct hdac_hdmi_port *port)
{
int num_ports;
@@ -239,7 +242,7 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac,
return 0;
/* AC_PAR_DEVLIST_LEN is 0 based. */
- num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid);
+ num_ports = hdac_hdmi_get_port_len(edev, port->pin->nid);
if (num_ports < 0)
return -EIO;
@@ -250,13 +253,13 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac,
if (num_ports + 1 < port->id)
return 0;
- snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
AC_VERB_SET_DEVICE_SEL, port->id);
- if (port->id != hdac_hdmi_port_select_get(hdac, port))
+ if (port->id != hdac_hdmi_port_select_get(edev, port))
return -EIO;
- dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id);
+ dev_dbg(&edev->hdev.dev, "Selected the port=%d\n", port->id);
return 0;
}
@@ -276,9 +279,9 @@ static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
{
- struct hdac_device *hdac = dev_to_hdac_dev(dev);
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
- return to_ehdac_device(hdac);
+ return to_ehdac_device(hdev);
}
static unsigned int sad_format(const u8 *sad)
@@ -321,14 +324,14 @@ format_constraint:
}
static void
-hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
+hdac_hdmi_set_dip_index(struct hdac_ext_device *edev, hda_nid_t pin_nid,
int packet_index, int byte_index)
{
int val;
val = (packet_index << 5) | (byte_index & 0x1f);
- snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ snd_hdac_codec_write(&edev->hdev, pin_nid, 0,
AC_VERB_SET_HDMI_DIP_INDEX, val);
}
@@ -344,14 +347,14 @@ struct dp_audio_infoframe {
u8 LFEPBL01_LSV36_DM_INH7;
};
-static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port)
{
uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
struct hdmi_audio_infoframe frame;
struct hdac_hdmi_pin *pin = port->pin;
struct dp_audio_infoframe dp_ai;
- struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_cvt *cvt = pcm->cvt;
u8 *dip;
int ret;
@@ -360,11 +363,11 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
u8 conn_type;
int channels, ca;
- ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc,
+ ca = snd_hdac_channel_allocation(&edev->hdev, port->eld.info.spk_alloc,
pcm->channels, pcm->chmap_set, true, pcm->chmap);
channels = snd_hdac_get_active_channels(ca);
- hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels);
+ hdmi->chmap.ops.set_channel_count(&edev->hdev, cvt->nid, channels);
snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
pcm->channels, pcm->chmap, pcm->chmap_set);
@@ -397,32 +400,32 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
break;
default:
- dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n",
+ dev_err(&edev->hdev.dev, "Invalid connection type: %d\n",
conn_type);
return -EIO;
}
/* stop infoframe transmission */
- hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0);
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
+ snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
/* Fill infoframe. Index auto-incremented */
- hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0);
+ hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
for (i = 0; i < sizeof(buffer); i++)
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, buffer[i]);
} else {
for (i = 0; i < sizeof(dp_ai); i++)
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
}
/* Start infoframe */
- hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0);
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
+ snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
return 0;
@@ -433,11 +436,11 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_pcm *pcm;
- dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask);
+ dev_dbg(&edev->hdev.dev, "%s: strm_tag: %d\n", __func__, tx_mask);
dai_map = &hdmi->dai_map[dai->id];
@@ -452,8 +455,8 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
{
- struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_port *port;
struct hdac_hdmi_pcm *pcm;
@@ -466,7 +469,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
return -ENODEV;
if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
- dev_err(&hdac->hdac.dev,
+ dev_err(&edev->hdev.dev,
"device is not configured for this pin:port%d:%d\n",
port->pin->nid, port->id);
return -ENODEV;
@@ -486,28 +489,28 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac,
+static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev,
struct hdac_hdmi_pin *pin,
struct hdac_hdmi_port *port)
{
- if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
- dev_warn(&hdac->hdac.dev,
+ if (!(get_wcaps(&edev->hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
+ dev_warn(&edev->hdev.dev,
"HDMI: pin %d wcaps %#x does not support connection list\n",
- pin->nid, get_wcaps(&hdac->hdac, pin->nid));
+ pin->nid, get_wcaps(&edev->hdev, pin->nid));
return -EINVAL;
}
- if (hdac_hdmi_port_select_set(hdac, port) < 0)
+ if (hdac_hdmi_port_select_set(edev, port) < 0)
return -EIO;
- port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
+ port->num_mux_nids = snd_hdac_get_connections(&edev->hdev, pin->nid,
port->mux_nids, HDA_MAX_CONNECTIONS);
if (port->num_mux_nids == 0)
- dev_warn(&hdac->hdac.dev,
+ dev_warn(&edev->hdev.dev,
"No connections found for pin:port %d:%d\n",
pin->nid, port->id);
- dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n",
+ dev_dbg(&edev->hdev.dev, "num_mux_nids %d for pin:port %d:%d\n",
port->num_mux_nids, pin->nid, port->id);
return port->num_mux_nids;
@@ -565,8 +568,8 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_port *port;
@@ -575,7 +578,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id];
cvt = dai_map->cvt;
- port = hdac_hdmi_get_port_from_cvt(hdac, hdmi, cvt);
+ port = hdac_hdmi_get_port_from_cvt(edev, hdmi, cvt);
/*
* To make PA and other userland happy.
@@ -586,7 +589,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
if ((!port->eld.monitor_present) ||
(!port->eld.eld_valid)) {
- dev_warn(&hdac->hdac.dev,
+ dev_warn(&edev->hdev.dev,
"Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n",
port->eld.monitor_present, port->eld.eld_valid,
port->pin->nid, port->id);
@@ -608,8 +611,8 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_pcm *pcm;
@@ -630,14 +633,13 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
}
static int
-hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
+hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
{
unsigned int chans;
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
int err;
- chans = get_wcaps(hdac, cvt->nid);
+ chans = get_wcaps(hdev, cvt->nid);
chans = get_wcaps_channels(chans);
cvt->params.channels_min = 2;
@@ -646,12 +648,12 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
if (chans > hdmi->chmap.channels_max)
hdmi->chmap.channels_max = chans;
- err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
+ err = snd_hdac_query_supported_pcm(hdev, cvt->nid,
&cvt->params.rates,
&cvt->params.formats,
&cvt->params.maxbps);
if (err < 0)
- dev_err(&hdac->dev,
+ dev_err(&hdev->dev,
"Failed to query pcm params for nid %d: %d\n",
cvt->nid, err);
@@ -696,7 +698,7 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
struct hdac_hdmi_port *port)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pcm *pcm = NULL;
struct hdac_hdmi_port *p;
@@ -716,9 +718,9 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
hda_nid_t nid, unsigned int pwr_state)
{
- if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) {
- if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state))
- snd_hdac_codec_write(&edev->hdac, nid, 0,
+ if (get_wcaps(&edev->hdev, nid) & AC_WCAP_POWER) {
+ if (!snd_hdac_check_power_state(&edev->hdev, nid, pwr_state))
+ snd_hdac_codec_write(&edev->hdev, nid, 0,
AC_VERB_SET_POWER_STATE, pwr_state);
}
}
@@ -726,8 +728,8 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
static void hdac_hdmi_set_amp(struct hdac_ext_device *edev,
hda_nid_t nid, int val)
{
- if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP)
- snd_hdac_codec_write(&edev->hdac, nid, 0,
+ if (get_wcaps(&edev->hdev, nid) & AC_WCAP_OUT_AMP)
+ snd_hdac_codec_write(&edev->hdev, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, val);
}
@@ -739,7 +741,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
struct hdac_hdmi_pcm *pcm;
- dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n",
+ dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
__func__, w->name, event);
pcm = hdac_hdmi_get_pcm(edev, port);
@@ -755,7 +757,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0);
/* Enable out path for this pin widget */
- snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE);
@@ -766,7 +768,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE);
/* Disable out path for this pin widget */
- snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3);
@@ -782,10 +784,10 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
{
struct hdac_hdmi_cvt *cvt = w->priv;
struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pcm *pcm;
- dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n",
+ dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
__func__, w->name, event);
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt);
@@ -797,23 +799,23 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0);
/* Enable transmission */
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, 1);
/* Category Code (CC) to zero */
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, 0);
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, pcm->format);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
AC_VERB_SET_CHANNEL_STREAMID, 0);
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, 0);
hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3);
@@ -831,7 +833,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
int mux_idx;
- dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n",
+ dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
__func__, w->name, event);
if (!kc)
@@ -844,7 +846,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
return -EIO;
if (mux_idx > 0) {
- snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0,
+ snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
}
@@ -864,7 +866,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_context *dapm = w->dapm;
struct hdac_hdmi_port *port = w->priv;
struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pcm *pcm = NULL;
const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
@@ -922,7 +924,7 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
struct snd_soc_dapm_widget *widget,
const char *widget_name)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pin *pin = port->pin;
struct snd_kcontrol_new *kc;
struct hdac_hdmi_cvt *cvt;
@@ -934,17 +936,17 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
int i = 0;
int num_items = hdmi->num_cvt + 1;
- kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL);
+ kc = devm_kzalloc(&edev->hdev.dev, sizeof(*kc), GFP_KERNEL);
if (!kc)
return -ENOMEM;
- se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL);
+ se = devm_kzalloc(&edev->hdev.dev, sizeof(*se), GFP_KERNEL);
if (!se)
return -ENOMEM;
snprintf(kc_name, NAME_SIZE, "Pin %d port %d Input",
pin->nid, port->id);
- kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL);
+ kc->name = devm_kstrdup(&edev->hdev.dev, kc_name, GFP_KERNEL);
if (!kc->name)
return -ENOMEM;
@@ -962,24 +964,24 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
se->mask = roundup_pow_of_two(se->items) - 1;
sprintf(mux_items, "NONE");
- items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
+ items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL);
if (!items[i])
return -ENOMEM;
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
i++;
sprintf(mux_items, "cvt %d", cvt->nid);
- items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
+ items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL);
if (!items[i])
return -ENOMEM;
}
- se->texts = devm_kmemdup(&edev->hdac.dev, items,
+ se->texts = devm_kmemdup(&edev->hdev.dev, items,
(num_items * sizeof(char *)), GFP_KERNEL);
if (!se->texts)
return -ENOMEM;
- return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget,
+ return hdac_hdmi_fill_widget_info(&edev->hdev.dev, widget,
snd_soc_dapm_mux, port, widget_name, NULL, kc, 1,
hdac_hdmi_pin_mux_widget_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG);
@@ -990,7 +992,7 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
struct snd_soc_dapm_widget *widgets,
struct snd_soc_dapm_route *route, int rindex)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
const struct snd_kcontrol_new *kc;
struct soc_enum *se;
int mux_index = hdmi->num_cvt + hdmi->num_ports;
@@ -1033,8 +1035,8 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
struct snd_soc_dapm_widget *widgets;
struct snd_soc_dapm_route *route;
struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct snd_soc_dai_driver *dai_drv = hdmi->dai_drv;
char widget_name[NAME_SIZE];
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_pin *pin;
@@ -1134,7 +1136,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_cvt *cvt;
int dai_id = 0;
@@ -1150,7 +1152,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
dai_id++;
if (dai_id == HDA_MAX_CVTS) {
- dev_warn(&edev->hdac.dev,
+ dev_warn(&edev->hdev.dev,
"Max dais supported: %d\n", dai_id);
break;
}
@@ -1161,7 +1163,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_cvt *cvt;
char name[NAME_SIZE];
@@ -1176,7 +1178,7 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
list_add_tail(&cvt->head, &hdmi->cvt_list);
hdmi->num_cvt++;
- return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
+ return hdac_hdmi_query_cvt_params(&edev->hdev, cvt);
}
static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
@@ -1188,7 +1190,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
>> DRM_ELD_VER_SHIFT;
if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
- dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver);
+ dev_err(&edev->hdev.dev, "HDMI: Unknown ELD version %d\n", ver);
return -EINVAL;
}
@@ -1196,7 +1198,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
if (mnl > ELD_MAX_MNL) {
- dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl);
+ dev_err(&edev->hdev.dev, "HDMI: MNL Invalid %d\n", mnl);
return -EINVAL;
}
@@ -1209,7 +1211,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
struct hdac_hdmi_port *port)
{
struct hdac_ext_device *edev = pin->edev;
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pcm *pcm;
int size = 0;
int port_id = -1;
@@ -1227,7 +1229,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
if (pin->mst_capable)
port_id = port->id;
- size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, port_id,
+ size = snd_hdac_acomp_get_eld(&edev->hdev, pin->nid, port_id,
&port->eld.monitor_present,
port->eld.eld_buffer,
ELD_MAX_SIZE);
@@ -1250,7 +1252,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n",
+ dev_err(&edev->hdev.dev, "%s: disconnect for pin:port %d:%d\n",
__func__, pin->nid, port->id);
/*
@@ -1304,7 +1306,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi,
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pin *pin;
int ret;
@@ -1333,40 +1335,38 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
-static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
+static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
{
unsigned int vendor_param;
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
- vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
+ vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
- vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
+ vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
}
-static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
+static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev)
{
unsigned int vendor_param;
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
- vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
+ vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return;
/* enable DP1.2 mode */
vendor_param |= INTEL_EN_DP12;
- vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
+ vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
@@ -1384,7 +1384,7 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
* Each converter can support a stream independently. So a dai is created
* based on the number of converter queried.
*/
-static int hdac_hdmi_create_dais(struct hdac_device *hdac,
+static int hdac_hdmi_create_dais(struct hdac_device *hdev,
struct snd_soc_dai_driver **dais,
struct hdac_hdmi_priv *hdmi, int num_dais)
{
@@ -1397,20 +1397,20 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac,
u64 formats;
int ret;
- hdmi_dais = devm_kzalloc(&hdac->dev,
+ hdmi_dais = devm_kzalloc(&hdev->dev,
(sizeof(*hdmi_dais) * num_dais),
GFP_KERNEL);
if (!hdmi_dais)
return -ENOMEM;
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
- ret = snd_hdac_query_supported_pcm(hdac, cvt->nid,
+ ret = snd_hdac_query_supported_pcm(hdev, cvt->nid,
&rates, &formats, &bps);
if (ret)
return ret;
sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
- hdmi_dais[i].name = devm_kstrdup(&hdac->dev,
+ hdmi_dais[i].name = devm_kstrdup(&hdev->dev,
dai_name, GFP_KERNEL);
if (!hdmi_dais[i].name)
@@ -1418,7 +1418,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac,
snprintf(name, sizeof(name), "hifi%d", i+1);
hdmi_dais[i].playback.stream_name =
- devm_kstrdup(&hdac->dev, name, GFP_KERNEL);
+ devm_kstrdup(&hdev->dev, name, GFP_KERNEL);
if (!hdmi_dais[i].playback.stream_name)
return -ENOMEM;
@@ -1438,6 +1438,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac,
}
*dais = hdmi_dais;
+ hdmi->dai_drv = hdmi_dais;
return 0;
}
@@ -1451,29 +1452,26 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
{
hda_nid_t nid;
int i, num_nodes;
- struct hdac_device *hdac = &edev->hdac;
- struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_cvt *temp_cvt, *cvt_next;
struct hdac_hdmi_pin *temp_pin, *pin_next;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = &edev->hdev;
int ret;
- hdac_hdmi_skl_enable_all_pins(hdac);
- hdac_hdmi_skl_enable_dp12(hdac);
+ hdac_hdmi_skl_enable_all_pins(hdev);
+ hdac_hdmi_skl_enable_dp12(hdev);
- num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
+ num_nodes = snd_hdac_get_sub_nodes(hdev, hdev->afg, &nid);
if (!nid || num_nodes <= 0) {
- dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
+ dev_warn(&hdev->dev, "HDMI: failed to get afg sub nodes\n");
return -EINVAL;
}
- hdac->num_nodes = num_nodes;
- hdac->start_nid = nid;
-
- for (i = 0; i < hdac->num_nodes; i++, nid++) {
+ for (i = 0; i < num_nodes; i++, nid++) {
unsigned int caps;
unsigned int type;
- caps = get_wcaps(hdac, nid);
+ caps = get_wcaps(hdev, nid);
type = get_wcaps_type(caps);
if (!(caps & AC_WCAP_DIGITAL))
@@ -1495,16 +1493,14 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
}
}
- hdac->end_nid = nid;
-
if (!hdmi->num_pin || !hdmi->num_cvt) {
ret = -EIO;
goto free_widgets;
}
- ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt);
+ ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt);
if (ret) {
- dev_err(&hdac->dev, "Failed to create dais with err: %d\n",
+ dev_err(&hdev->dev, "Failed to create dais with err: %d\n",
ret);
goto free_widgets;
}
@@ -1537,7 +1533,7 @@ free_widgets:
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{
struct hdac_ext_device *edev = aptr;
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pin *pin = NULL;
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_codec *codec = edev->scodec;
@@ -1546,7 +1542,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
/* Don't know how this mapping is derived */
hda_nid_t pin_nid = port + 0x04;
- dev_dbg(&edev->hdac.dev, "%s: for pin:%d port=%d\n", __func__,
+ dev_dbg(&edev->hdev.dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
/*
@@ -1559,7 +1555,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
SNDRV_CTL_POWER_D0)
return;
- if (atomic_read(&edev->hdac.in_pm))
+ if (atomic_read(&edev->hdev.in_pm))
return;
list_for_each_entry(pin, &hdmi->pin_list, head) {
@@ -1614,7 +1610,7 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card,
char *name;
int i = 0, j;
struct snd_soc_codec *codec = edev->scodec;
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
kc = devm_kcalloc(codec->dev, hdmi->num_ports,
sizeof(*kc), GFP_KERNEL);
@@ -1652,7 +1648,7 @@ int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
struct snd_soc_dapm_context *dapm)
{
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pin *pin;
struct snd_soc_dapm_widget *widgets;
struct snd_soc_dapm_route *route;
@@ -1728,7 +1724,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
{
struct snd_soc_codec *codec = dai->codec;
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pcm *pcm;
struct snd_pcm *snd_pcm;
int err;
@@ -1750,7 +1746,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
if (snd_pcm) {
err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
if (err < 0) {
- dev_err(&edev->hdac.dev,
+ dev_err(&edev->hdev.dev,
"chmap control add failed with err: %d for pcm: %d\n",
err, device);
kfree(pcm);
@@ -1791,7 +1787,7 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
static int hdmi_codec_probe(struct snd_soc_codec *codec)
{
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(&codec->component);
struct hdac_ext_link *hlink = NULL;
@@ -1803,9 +1799,9 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
* hold the ref while we probe, also no need to drop the ref on
* exit, we call pm_runtime_suspend() so that will do for us
*/
- hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
+ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev));
if (!hlink) {
- dev_err(&edev->hdac.dev, "hdac link not found\n");
+ dev_err(&edev->hdev.dev, "hdac link not found\n");
return -EIO;
}
@@ -1818,7 +1814,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
aops.audio_ptr = edev;
ret = snd_hdac_i915_register_notifier(&aops);
if (ret < 0) {
- dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
+ dev_err(&edev->hdev.dev, "notifier register failed: err: %d\n",
ret);
return ret;
}
@@ -1831,9 +1827,9 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
* hdac_device core already sets the state to active and calls
* get_noresume. So enable runtime and set the device to suspend.
*/
- pm_runtime_enable(&edev->hdac.dev);
- pm_runtime_put(&edev->hdac.dev);
- pm_runtime_suspend(&edev->hdac.dev);
+ pm_runtime_enable(&edev->hdev.dev);
+ pm_runtime_put(&edev->hdev.dev);
+ pm_runtime_suspend(&edev->hdev.dev);
return 0;
}
@@ -1842,7 +1838,7 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec)
{
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
- pm_runtime_disable(&edev->hdac.dev);
+ pm_runtime_disable(&edev->hdev.dev);
return 0;
}
@@ -1850,9 +1846,9 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec)
static int hdmi_codec_prepare(struct device *dev)
{
struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_device *hdac = &edev->hdac;
+ struct hdac_device *hdev = &edev->hdev;
- pm_runtime_get_sync(&edev->hdac.dev);
+ pm_runtime_get_sync(&edev->hdev.dev);
/*
* Power down afg.
@@ -1861,7 +1857,7 @@ static int hdmi_codec_prepare(struct device *dev)
* is received. So setting power state is ensured without using loop
* to read the state.
*/
- snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+ snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D3);
return 0;
@@ -1870,15 +1866,15 @@ static int hdmi_codec_prepare(struct device *dev)
static void hdmi_codec_complete(struct device *dev)
{
struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct hdac_device *hdac = &edev->hdac;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = &edev->hdev;
/* Power up afg */
- snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+ snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D0);
- hdac_hdmi_skl_enable_all_pins(&edev->hdac);
- hdac_hdmi_skl_enable_dp12(&edev->hdac);
+ hdac_hdmi_skl_enable_all_pins(&edev->hdev);
+ hdac_hdmi_skl_enable_dp12(&edev->hdev);
/*
* As the ELD notify callback request is not entertained while the
@@ -1888,7 +1884,7 @@ static void hdmi_codec_complete(struct device *dev)
*/
hdac_hdmi_present_sense_all_pins(edev, hdmi, false);
- pm_runtime_put_sync(&edev->hdac.dev);
+ pm_runtime_put_sync(&edev->hdev.dev);
}
#else
#define hdmi_codec_prepare NULL
@@ -1901,21 +1897,20 @@ static const struct snd_soc_codec_driver hdmi_hda_codec = {
.idle_bias_off = true,
};
-static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
+static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx,
unsigned char *chmap)
{
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap));
}
-static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
+static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
unsigned char *chmap, int prepared)
{
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_ext_device *edev = to_ehdac_device(hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_port *port;
@@ -1934,10 +1929,9 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
mutex_unlock(&pcm->lock);
}
-static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
+static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx)
{
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
if (!pcm)
@@ -1949,10 +1943,9 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
return true;
}
-static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
+static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
{
- struct hdac_ext_device *edev = to_ehdac_device(hdac);
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_port *port;
@@ -1983,30 +1976,30 @@ static struct hdac_hdmi_drv_data intel_drv_data = {
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{
- struct hdac_device *codec = &edev->hdac;
+ struct hdac_device *hdev = &edev->hdev;
struct hdac_hdmi_priv *hdmi_priv;
struct snd_soc_dai_driver *hdmi_dais = NULL;
struct hdac_ext_link *hlink = NULL;
int num_dais = 0;
int ret = 0;
- struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver);
- const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv);
+ struct hdac_driver *hdrv = drv_to_hdac_driver(hdev->dev.driver);
+ const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
+ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev));
if (!hlink) {
- dev_err(&edev->hdac.dev, "hdac link not found\n");
+ dev_err(&edev->hdev.dev, "hdac link not found\n");
return -EIO;
}
snd_hdac_ext_bus_link_get(edev->ebus, hlink);
- hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
+ hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
if (hdmi_priv == NULL)
return -ENOMEM;
edev->private_data = hdmi_priv;
- snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
+ snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
@@ -2021,7 +2014,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
else
hdmi_priv->drv_data = &intel_drv_data;
- dev_set_drvdata(&codec->dev, edev);
+ dev_set_drvdata(&hdev->dev, edev);
INIT_LIST_HEAD(&hdmi_priv->pin_list);
INIT_LIST_HEAD(&hdmi_priv->cvt_list);
@@ -2032,9 +2025,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
* Turned off in the runtime_suspend during the first explicit
* pm_runtime_suspend call.
*/
- ret = snd_hdac_display_power(edev->hdac.bus, true);
+ ret = snd_hdac_display_power(edev->hdev.bus, true);
if (ret < 0) {
- dev_err(&edev->hdac.dev,
+ dev_err(&edev->hdev.dev,
"Cannot turn on display power on i915 err: %d\n",
ret);
return ret;
@@ -2042,13 +2035,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
if (ret < 0) {
- dev_err(&codec->dev,
+ dev_err(&hdev->dev,
"Failed in parse and map nid with err: %d\n", ret);
return ret;
}
+ snd_hdac_refresh_widgets(hdev, true);
/* ASoC specific initialization */
- ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
+ ret = snd_soc_register_codec(&hdev->dev, &hdmi_hda_codec,
hdmi_dais, num_dais);
snd_hdac_ext_bus_link_put(edev->ebus, hlink);
@@ -2058,14 +2052,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
{
- struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
struct hdac_hdmi_pcm *pcm, *pcm_next;
struct hdac_hdmi_port *port, *port_next;
int i;
- snd_soc_unregister_codec(&edev->hdac.dev);
+ snd_soc_unregister_codec(&edev->hdev.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
pcm->cvt = NULL;
@@ -2101,8 +2095,8 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
static int hdac_hdmi_runtime_suspend(struct device *dev)
{
struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_device *hdac = &edev->hdac;
- struct hdac_bus *bus = hdac->bus;
+ struct hdac_device *hdev = &edev->hdev;
+ struct hdac_bus *bus = hdev->bus;
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink = NULL;
int err;
@@ -2120,7 +2114,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
* is received. So setting power state is ensured without using loop
* to read the state.
*/
- snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+ snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D3);
err = snd_hdac_display_power(bus, false);
if (err < 0) {
@@ -2142,8 +2136,8 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
static int hdac_hdmi_runtime_resume(struct device *dev)
{
struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_device *hdac = &edev->hdac;
- struct hdac_bus *bus = hdac->bus;
+ struct hdac_device *hdev = &edev->hdev;
+ struct hdac_bus *bus = hdev->bus;
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink = NULL;
int err;
@@ -2168,11 +2162,11 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
return err;
}
- hdac_hdmi_skl_enable_all_pins(&edev->hdac);
- hdac_hdmi_skl_enable_dp12(&edev->hdac);
+ hdac_hdmi_skl_enable_all_pins(&edev->hdev);
+ hdac_hdmi_skl_enable_dp12(&edev->hdev);
/* Power up afg */
- snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE,
+ snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D0);
return 0;
@@ -2192,6 +2186,8 @@ static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
+ HDA_CODEC_EXT_ENTRY(0x8086280c, 0x100000, "Cannonlake HDMI",
+ &intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
{}
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
new file mode 100644
index 0000000..31b0864
--- /dev/null
+++ b/sound/soc/codecs/max98373.c
@@ -0,0 +1,976 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2017, Maxim Integrated */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/tlv.h>
+#include "max98373.h"
+
+static struct reg_default max98373_reg[] = {
+ {MAX98373_R2000_SW_RESET, 0x00},
+ {MAX98373_R2001_INT_RAW1, 0x00},
+ {MAX98373_R2002_INT_RAW2, 0x00},
+ {MAX98373_R2003_INT_RAW3, 0x00},
+ {MAX98373_R2004_INT_STATE1, 0x00},
+ {MAX98373_R2005_INT_STATE2, 0x00},
+ {MAX98373_R2006_INT_STATE3, 0x00},
+ {MAX98373_R2007_INT_FLAG1, 0x00},
+ {MAX98373_R2008_INT_FLAG2, 0x00},
+ {MAX98373_R2009_INT_FLAG3, 0x00},
+ {MAX98373_R200A_INT_EN1, 0x00},
+ {MAX98373_R200B_INT_EN2, 0x00},
+ {MAX98373_R200C_INT_EN3, 0x00},
+ {MAX98373_R200D_INT_FLAG_CLR1, 0x00},
+ {MAX98373_R200E_INT_FLAG_CLR2, 0x00},
+ {MAX98373_R200F_INT_FLAG_CLR3, 0x00},
+ {MAX98373_R2010_IRQ_CTRL, 0x00},
+ {MAX98373_R2014_THERM_WARN_THRESH, 0x10},
+ {MAX98373_R2015_THERM_SHDN_THRESH, 0x27},
+ {MAX98373_R2016_THERM_HYSTERESIS, 0x01},
+ {MAX98373_R2017_THERM_FOLDBACK_SET, 0xC0},
+ {MAX98373_R2018_THERM_FOLDBACK_EN, 0x00},
+ {MAX98373_R201E_PIN_DRIVE_STRENGTH, 0x55},
+ {MAX98373_R2020_PCM_TX_HIZ_EN_1, 0xFE},
+ {MAX98373_R2021_PCM_TX_HIZ_EN_2, 0xFF},
+ {MAX98373_R2022_PCM_TX_SRC_1, 0x00},
+ {MAX98373_R2023_PCM_TX_SRC_2, 0x00},
+ {MAX98373_R2024_PCM_DATA_FMT_CFG, 0xC0},
+ {MAX98373_R2025_AUDIO_IF_MODE, 0x00},
+ {MAX98373_R2026_PCM_CLOCK_RATIO, 0x04},
+ {MAX98373_R2027_PCM_SR_SETUP_1, 0x08},
+ {MAX98373_R2028_PCM_SR_SETUP_2, 0x88},
+ {MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, 0x00},
+ {MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2, 0x00},
+ {MAX98373_R202B_PCM_RX_EN, 0x00},
+ {MAX98373_R202C_PCM_TX_EN, 0x00},
+ {MAX98373_R202E_ICC_RX_CH_EN_1, 0x00},
+ {MAX98373_R202F_ICC_RX_CH_EN_2, 0x00},
+ {MAX98373_R2030_ICC_TX_HIZ_EN_1, 0xFF},
+ {MAX98373_R2031_ICC_TX_HIZ_EN_2, 0xFF},
+ {MAX98373_R2032_ICC_LINK_EN_CFG, 0x30},
+ {MAX98373_R2034_ICC_TX_CNTL, 0x00},
+ {MAX98373_R2035_ICC_TX_EN, 0x00},
+ {MAX98373_R2036_SOUNDWIRE_CTRL, 0x05},
+ {MAX98373_R203D_AMP_DIG_VOL_CTRL, 0x00},
+ {MAX98373_R203E_AMP_PATH_GAIN, 0x08},
+ {MAX98373_R203F_AMP_DSP_CFG, 0x02},
+ {MAX98373_R2040_TONE_GEN_CFG, 0x00},
+ {MAX98373_R2041_AMP_CFG, 0x03},
+ {MAX98373_R2042_AMP_EDGE_RATE_CFG, 0x00},
+ {MAX98373_R2043_AMP_EN, 0x00},
+ {MAX98373_R2046_IV_SENSE_ADC_DSP_CFG, 0x04},
+ {MAX98373_R2047_IV_SENSE_ADC_EN, 0x00},
+ {MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0x00},
+ {MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, 0x00},
+ {MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, 0x00},
+ {MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0x00},
+ {MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0x00},
+ {MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0x00},
+ {MAX98373_R2090_BDE_LVL_HOLD, 0x00},
+ {MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0x00},
+ {MAX98373_R2092_BDE_CLIPPER_MODE, 0x00},
+ {MAX98373_R2097_BDE_L1_THRESH, 0x00},
+ {MAX98373_R2098_BDE_L2_THRESH, 0x00},
+ {MAX98373_R2099_BDE_L3_THRESH, 0x00},
+ {MAX98373_R209A_BDE_L4_THRESH, 0x00},
+ {MAX98373_R209B_BDE_THRESH_HYST, 0x00},
+ {MAX98373_R20A8_BDE_L1_CFG_1, 0x00},
+ {MAX98373_R20A9_BDE_L1_CFG_2, 0x00},
+ {MAX98373_R20AA_BDE_L1_CFG_3, 0x00},
+ {MAX98373_R20AB_BDE_L2_CFG_1, 0x00},
+ {MAX98373_R20AC_BDE_L2_CFG_2, 0x00},
+ {MAX98373_R20AD_BDE_L2_CFG_3, 0x00},
+ {MAX98373_R20AE_BDE_L3_CFG_1, 0x00},
+ {MAX98373_R20AF_BDE_L3_CFG_2, 0x00},
+ {MAX98373_R20B0_BDE_L3_CFG_3, 0x00},
+ {MAX98373_R20B1_BDE_L4_CFG_1, 0x00},
+ {MAX98373_R20B2_BDE_L4_CFG_2, 0x00},
+ {MAX98373_R20B3_BDE_L4_CFG_3, 0x00},
+ {MAX98373_R20B4_BDE_INFINITE_HOLD_RELEASE, 0x00},
+ {MAX98373_R20B5_BDE_EN, 0x00},
+ {MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0x00},
+ {MAX98373_R20D1_DHT_CFG, 0x01},
+ {MAX98373_R20D2_DHT_ATTACK_CFG, 0x02},
+ {MAX98373_R20D3_DHT_RELEASE_CFG, 0x03},
+ {MAX98373_R20D4_DHT_EN, 0x00},
+ {MAX98373_R20E0_LIMITER_THRESH_CFG, 0x00},
+ {MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0x00},
+ {MAX98373_R20E2_LIMITER_EN, 0x00},
+ {MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, 0x00},
+ {MAX98373_R20FF_GLOBAL_SHDN, 0x00},
+ {MAX98373_R21FF_REV_ID, 0x42},
+};
+
+static int max98373_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+ unsigned int format = 0;
+ unsigned int invert = 0;
+
+ dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ invert = MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE;
+ break;
+ default:
+ dev_err(codec->dev, "DAI invert mode unsupported\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2026_PCM_CLOCK_RATIO,
+ MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE,
+ invert);
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format = MAX98373_PCM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format = MAX98373_PCM_FORMAT_LJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ format = MAX98373_PCM_FORMAT_TDM_MODE1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ format = MAX98373_PCM_FORMAT_TDM_MODE0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2024_PCM_DATA_FMT_CFG,
+ MAX98373_PCM_MODE_CFG_FORMAT_MASK,
+ format << MAX98373_PCM_MODE_CFG_FORMAT_SHIFT);
+
+ return 0;
+}
+
+/* BCLKs per LRCLK */
+static const int bclk_sel_table[] = {
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
+};
+
+static int max98373_get_bclk_sel(int bclk)
+{
+ int i;
+ /* match BCLKs per LRCLK */
+ for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
+ if (bclk_sel_table[i] == bclk)
+ return i + 2;
+ }
+ return 0;
+}
+
+static int max98373_set_clock(struct snd_soc_codec *codec,
+ struct snd_pcm_hw_params *params)
+{
+ struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+ /* BCLK/LRCLK ratio calculation */
+ int blr_clk_ratio = params_channels(params) * max98373->ch_size;
+ int value;
+
+ if (!max98373->tdm_mode) {
+ /* BCLK configuration */
+ value = max98373_get_bclk_sel(blr_clk_ratio);
+ if (!value) {
+ dev_err(codec->dev, "format unsupported %d\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2026_PCM_CLOCK_RATIO,
+ MAX98373_PCM_CLK_SETUP_BSEL_MASK,
+ value);
+ }
+ return 0;
+}
+
+static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sampling_rate = 0;
+ unsigned int chan_sz = 0;
+
+ /* pcm mode configuration */
+ switch (snd_pcm_format_width(params_format(params))) {
+ case 16:
+ chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(codec->dev, "format unsupported %d\n",
+ params_format(params));
+ goto err;
+ }
+
+ max98373->ch_size = snd_pcm_format_width(params_format(params));
+
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2024_PCM_DATA_FMT_CFG,
+ MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+ dev_dbg(codec->dev, "format supported %d",
+ params_format(params));
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 8000:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_8000;
+ break;
+ case 11025:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_11025;
+ break;
+ case 12000:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_12000;
+ break;
+ case 16000:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_16000;
+ break;
+ case 22050:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_22050;
+ break;
+ case 24000:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_24000;
+ break;
+ case 32000:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_32000;
+ break;
+ case 44100:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_44100;
+ break;
+ case 48000:
+ sampling_rate = MAX98373_PCM_SR_SET1_SR_48000;
+ break;
+ default:
+ dev_err(codec->dev, "rate %d not supported\n",
+ params_rate(params));
+ goto err;
+ }
+
+ /* set DAI_SR to correct LRCLK frequency */
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2027_PCM_SR_SETUP_1,
+ MAX98373_PCM_SR_SET1_SR_MASK,
+ sampling_rate);
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2028_PCM_SR_SETUP_2,
+ MAX98373_PCM_SR_SET2_SR_MASK,
+ sampling_rate << MAX98373_PCM_SR_SET2_SR_SHIFT);
+
+ /* set sampling rate of IV */
+ if (max98373->interleave_mode &&
+ sampling_rate > MAX98373_PCM_SR_SET1_SR_16000)
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2028_PCM_SR_SETUP_2,
+ MAX98373_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate - 3);
+ else
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2028_PCM_SR_SETUP_2,
+ MAX98373_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate);
+
+ return max98373_set_clock(codec, params);
+err:
+ return -EINVAL;
+}
+
+static int max98373_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+ int bsel = 0;
+ unsigned int chan_sz = 0;
+ unsigned int mask;
+ int x, slot_found;
+
+ if (!tx_mask && !rx_mask && !slots && !slot_width)
+ max98373->tdm_mode = false;
+ else
+ max98373->tdm_mode = true;
+
+ /* BCLK configuration */
+ bsel = max98373_get_bclk_sel(slots * slot_width);
+ if (bsel == 0) {
+ dev_err(codec->dev, "BCLK %d not supported\n",
+ slots * slot_width);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2026_PCM_CLOCK_RATIO,
+ MAX98373_PCM_CLK_SETUP_BSEL_MASK,
+ bsel);
+
+ /* Channel size configuration */
+ switch (slot_width) {
+ case 16:
+ chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(codec->dev, "format unsupported %d\n",
+ slot_width);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2024_PCM_DATA_FMT_CFG,
+ MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+ /* Rx slot configuration */
+ slot_found = 0;
+ mask = rx_mask;
+ for (x = 0 ; x < 16 ; x++, mask >>= 1) {
+ if (mask & 0x1) {
+ if (slot_found == 0)
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
+ MAX98373_PCM_TO_SPK_CH0_SRC_MASK, x);
+ else
+ regmap_write(max98373->regmap,
+ MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2,
+ x);
+ slot_found++;
+ if (slot_found > 1)
+ break;
+ }
+ }
+
+ /* Tx slot Hi-Z configuration */
+ regmap_write(max98373->regmap,
+ MAX98373_R2020_PCM_TX_HIZ_EN_1,
+ ~tx_mask & 0xFF);
+ regmap_write(max98373->regmap,
+ MAX98373_R2021_PCM_TX_HIZ_EN_2,
+ (~tx_mask & 0xFF00) >> 8);
+
+ return 0;
+}
+
+#define MAX98373_RATES SNDRV_PCM_RATE_8000_96000
+
+#define MAX98373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops max98373_dai_ops = {
+ .set_fmt = max98373_dai_set_fmt,
+ .hw_params = max98373_dai_hw_params,
+ .set_tdm_slot = max98373_dai_tdm_slot,
+};
+
+static int max98373_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R20FF_GLOBAL_SHDN,
+ MAX98373_GLOBAL_EN_MASK, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R20FF_GLOBAL_SHDN,
+ MAX98373_GLOBAL_EN_MASK, 0);
+ max98373->tdm_mode = 0;
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static const char * const max98373_switch_text[] = {
+ "Left", "Right", "LeftRight"};
+
+static const struct soc_enum dai_sel_enum =
+ SOC_ENUM_SINGLE(MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
+ MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+ 3, max98373_switch_text);
+
+static const struct snd_kcontrol_new max98373_dai_controls =
+ SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+
+static const struct snd_kcontrol_new max98373_vi_control =
+ SOC_DAPM_SINGLE("Switch", MAX98373_R202C_PCM_TX_EN, 0, 1, 0);
+
+static const struct snd_kcontrol_new max98373_spkfb_control =
+ SOC_DAPM_SINGLE("Switch", MAX98373_R2043_AMP_EN, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget max98373_dapm_widgets[] = {
+SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
+ MAX98373_R202B_PCM_RX_EN, 0, 0, max98373_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
+ &max98373_dai_controls),
+SND_SOC_DAPM_OUTPUT("BE_OUT"),
+SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
+ MAX98373_R2047_IV_SENSE_ADC_EN, 0, 0),
+SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
+ MAX98373_R2047_IV_SENSE_ADC_EN, 1, 0),
+SND_SOC_DAPM_AIF_OUT("Speaker FB Sense", "HiFi Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
+ &max98373_vi_control),
+SND_SOC_DAPM_SWITCH("SpkFB Sense", SND_SOC_NOPM, 0, 0,
+ &max98373_spkfb_control),
+SND_SOC_DAPM_SIGGEN("VMON"),
+SND_SOC_DAPM_SIGGEN("IMON"),
+SND_SOC_DAPM_SIGGEN("FBMON"),
+};
+
+static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0);
+static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv,
+ 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
+ 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_spkgain_max_tlv,
+ 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_dht_step_size_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(25, 25, 0),
+ 2, 4, TLV_DB_SCALE_ITEM(100, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv,
+ 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0),
+ 2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0),
+ 8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0),
+ 10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0),
+ 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0),
+ 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv,
+ 0, 15, TLV_DB_SCALE_ITEM(0, -100, 0),
+);
+
+static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
+ 0, 60, TLV_DB_SCALE_ITEM(0, -25, 0),
+);
+
+static bool max98373_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98373_R2001_INT_RAW1 ... MAX98373_R200C_INT_EN3:
+ case MAX98373_R2010_IRQ_CTRL:
+ case MAX98373_R2014_THERM_WARN_THRESH
+ ... MAX98373_R2018_THERM_FOLDBACK_EN:
+ case MAX98373_R201E_PIN_DRIVE_STRENGTH
+ ... MAX98373_R2036_SOUNDWIRE_CTRL:
+ case MAX98373_R203D_AMP_DIG_VOL_CTRL ... MAX98373_R2043_AMP_EN:
+ case MAX98373_R2046_IV_SENSE_ADC_DSP_CFG
+ ... MAX98373_R2047_IV_SENSE_ADC_EN:
+ case MAX98373_R2051_MEAS_ADC_SAMPLING_RATE
+ ... MAX98373_R2056_MEAS_ADC_PVDD_CH_EN:
+ case MAX98373_R2090_BDE_LVL_HOLD ... MAX98373_R2092_BDE_CLIPPER_MODE:
+ case MAX98373_R2097_BDE_L1_THRESH
+ ... MAX98373_R209B_BDE_THRESH_HYST:
+ case MAX98373_R20A8_BDE_L1_CFG_1 ... MAX98373_R20B3_BDE_L4_CFG_3:
+ case MAX98373_R20B5_BDE_EN ... MAX98373_R20B6_BDE_CUR_STATE_READBACK:
+ case MAX98373_R20D1_DHT_CFG ... MAX98373_R20D4_DHT_EN:
+ case MAX98373_R20E0_LIMITER_THRESH_CFG ... MAX98373_R20E2_LIMITER_EN:
+ case MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG
+ ... MAX98373_R20FF_GLOBAL_SHDN:
+ case MAX98373_R21FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+};
+
+static bool max98373_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98373_R2000_SW_RESET ... MAX98373_R2009_INT_FLAG3:
+ case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK:
+ case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK:
+ case MAX98373_R20B6_BDE_CUR_STATE_READBACK:
+ case MAX98373_R21FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char * const max98373_output_voltage_lvl_text[] = {
+ "5.43V", "6.09V", "6.83V", "7.67V", "8.60V",
+ "9.65V", "10.83V", "12.15V", "13.63V", "15.29V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_out_volt_enum,
+ MAX98373_R203E_AMP_PATH_GAIN, 0,
+ max98373_output_voltage_lvl_text);
+
+static const char * const max98373_dht_attack_rate_text[] = {
+ "17.5us", "35us", "70us", "140us",
+ "280us", "560us", "1120us", "2240us"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_dht_attack_rate_enum,
+ MAX98373_R20D2_DHT_ATTACK_CFG, 0,
+ max98373_dht_attack_rate_text);
+
+static const char * const max98373_dht_release_rate_text[] = {
+ "45ms", "225ms", "450ms", "1150ms",
+ "2250ms", "3100ms", "4500ms", "6750ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_dht_release_rate_enum,
+ MAX98373_R20D3_DHT_RELEASE_CFG, 0,
+ max98373_dht_release_rate_text);
+
+static const char * const max98373_limiter_attack_rate_text[] = {
+ "10us", "20us", "40us", "80us",
+ "160us", "320us", "640us", "1.28ms",
+ "2.56ms", "5.12ms", "10.24ms", "20.48ms",
+ "40.96ms", "81.92ms", "16.384ms", "32.768ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_limiter_attack_rate_enum,
+ MAX98373_R20E1_LIMITER_ATK_REL_RATES, 4,
+ max98373_limiter_attack_rate_text);
+
+static const char * const max98373_limiter_release_rate_text[] = {
+ "40us", "80us", "160us", "320us",
+ "640us", "1.28ms", "2.56ms", "5.120ms",
+ "10.24ms", "20.48ms", "40.96ms", "81.92ms",
+ "163.84ms", "327.68ms", "655.36ms", "1310.72ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_limiter_release_rate_enum,
+ MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0,
+ max98373_limiter_release_rate_text);
+
+static const char * const max98373_ADC_samplerate_text[] = {
+ "333kHz", "192kHz", "64kHz", "48kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
+ MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
+ max98373_ADC_samplerate_text);
+
+static const struct snd_kcontrol_new max98373_snd_controls[] = {
+SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
+ MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
+SOC_SINGLE("Volume Location Switch", MAX98373_R203F_AMP_DSP_CFG,
+ MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
+SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG,
+ MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
+SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG,
+ MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
+SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
+ MAX98373_CLOCK_MON_SHIFT, 1, 0),
+SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
+ MAX98373_AMP_DSP_CFG_DITH_SHIFT, 1, 0),
+SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG,
+ MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL,
+ 0, 0x7F, 0, max98373_digital_tlv),
+SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN,
+ MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv),
+SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN,
+ MAX98373_FS_GAIN_MAX_SHIFT, 9, 0, max98373_spkgain_max_tlv),
+SOC_ENUM("Output Voltage", max98373_out_volt_enum),
+/* Dynamic Headroom Tracking */
+SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN,
+ MAX98373_DHT_EN_SHIFT, 1, 0),
+SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG,
+ MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv),
+SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG,
+ MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv),
+SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG,
+ MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
+SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG,
+ MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
+SOC_ENUM("DHT Attack Rate", max98373_dht_attack_rate_enum),
+SOC_ENUM("DHT Release Rate", max98373_dht_release_rate_enum),
+/* ADC configuration */
+SOC_SINGLE("ADC PVDD CH Switch", MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0, 1, 0),
+SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
+ MAX98373_FLT_EN_SHIFT, 1, 0),
+SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
+ MAX98373_FLT_EN_SHIFT, 1, 0),
+SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
+SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
+SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
+ 0, 0x3, 0),
+SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
+ 0, 0x3, 0),
+SOC_ENUM("ADC SampleRate", max98373_adc_samplerate_enum),
+/* Brownout Detection Engine */
+SOC_SINGLE("BDE Switch", MAX98373_R20B5_BDE_EN, MAX98373_BDE_EN_SHIFT, 1, 0),
+SOC_SINGLE("BDE LVL4 Mute Switch", MAX98373_R20B2_BDE_L4_CFG_2,
+ MAX98373_LVL4_MUTE_EN_SHIFT, 1, 0),
+SOC_SINGLE("BDE LVL4 Hold Switch", MAX98373_R20B2_BDE_L4_CFG_2,
+ MAX98373_LVL4_HOLD_EN_SHIFT, 1, 0),
+SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
+SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
+SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
+SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
+SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0),
+SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0),
+SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3,
+ 0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1,
+ 0, 0xF, 0, max98373_limiter_thresh_tlv),
+SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1,
+ 0, 0xF, 0, max98373_limiter_thresh_tlv),
+SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1,
+ 0, 0xF, 0, max98373_limiter_thresh_tlv),
+SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1,
+ 0, 0xF, 0, max98373_limiter_thresh_tlv),
+/* Limiter */
+SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN,
+ MAX98373_LIMITER_EN_SHIFT, 1, 0),
+SOC_SINGLE("Limiter Src Switch", MAX98373_R20E0_LIMITER_THRESH_CFG,
+ MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Limiter Thresh Volume", MAX98373_R20E0_LIMITER_THRESH_CFG,
+ MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv),
+SOC_ENUM("Limiter Attack Rate", max98373_limiter_attack_rate_enum),
+SOC_ENUM("Limiter Release Rate", max98373_limiter_release_rate_enum),
+};
+
+static const struct snd_soc_dapm_route max98373_audio_map[] = {
+ /* Plabyack */
+ {"DAI Sel Mux", "Left", "Amp Enable"},
+ {"DAI Sel Mux", "Right", "Amp Enable"},
+ {"DAI Sel Mux", "LeftRight", "Amp Enable"},
+ {"BE_OUT", NULL, "DAI Sel Mux"},
+ /* Capture */
+ { "VI Sense", "Switch", "VMON" },
+ { "VI Sense", "Switch", "IMON" },
+ { "SpkFB Sense", "Switch", "FBMON" },
+ { "Voltage Sense", NULL, "VI Sense" },
+ { "Current Sense", NULL, "VI Sense" },
+ { "Speaker FB Sense", NULL, "SpkFB Sense" },
+};
+
+static struct snd_soc_dai_driver max98373_dai[] = {
+ {
+ .name = "max98373-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98373_RATES,
+ .formats = MAX98373_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98373_RATES,
+ .formats = MAX98373_FORMATS,
+ },
+ .ops = &max98373_dai_ops,
+ }
+};
+
+static int max98373_probe(struct snd_soc_codec *codec)
+{
+ struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+
+ codec->control_data = max98373->regmap;
+
+ /* Software Reset */
+ regmap_write(max98373->regmap,
+ MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
+
+ /* IV default slot configuration */
+ regmap_write(max98373->regmap,
+ MAX98373_R2020_PCM_TX_HIZ_EN_1,
+ 0xFF);
+ regmap_write(max98373->regmap,
+ MAX98373_R2021_PCM_TX_HIZ_EN_2,
+ 0xFF);
+ /* L/R mix configuration */
+ regmap_write(max98373->regmap,
+ MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
+ 0x80);
+ regmap_write(max98373->regmap,
+ MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2,
+ 0x1);
+ /* Set inital volume (0dB) */
+ regmap_write(max98373->regmap,
+ MAX98373_R203D_AMP_DIG_VOL_CTRL,
+ 0x00);
+ regmap_write(max98373->regmap,
+ MAX98373_R203E_AMP_PATH_GAIN,
+ 0x00);
+ /* Enable DC blocker */
+ regmap_write(max98373->regmap,
+ MAX98373_R203F_AMP_DSP_CFG,
+ 0x3);
+ /* Enable IMON VMON DC blocker */
+ regmap_write(max98373->regmap,
+ MAX98373_R2046_IV_SENSE_ADC_DSP_CFG,
+ 0x7);
+ /* voltage, current slot configuration */
+ regmap_write(max98373->regmap,
+ MAX98373_R2022_PCM_TX_SRC_1,
+ (max98373->i_slot << MAX98373_PCM_TX_CH_SRC_A_I_SHIFT |
+ max98373->v_slot) & 0xFF);
+ if (max98373->v_slot < 8)
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2020_PCM_TX_HIZ_EN_1,
+ 1 << max98373->v_slot, 0);
+ else
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2021_PCM_TX_HIZ_EN_2,
+ 1 << (max98373->v_slot - 8), 0);
+
+ if (max98373->i_slot < 8)
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2020_PCM_TX_HIZ_EN_1,
+ 1 << max98373->i_slot, 0);
+ else
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2021_PCM_TX_HIZ_EN_2,
+ 1 << (max98373->i_slot - 8), 0);
+
+ /* speaker feedback slot configuration */
+ regmap_write(max98373->regmap,
+ MAX98373_R2023_PCM_TX_SRC_2,
+ max98373->spkfb_slot & 0xFF);
+
+ /* Set interleave mode */
+ if (max98373->interleave_mode)
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2024_PCM_DATA_FMT_CFG,
+ MAX98373_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98373_PCM_TX_CH_INTERLEAVE_MASK);
+
+ /* Speaker enable */
+ regmap_update_bits(max98373->regmap,
+ MAX98373_R2043_AMP_EN,
+ MAX98373_SPK_EN_MASK, 1);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max98373_suspend(struct device *dev)
+{
+ struct max98373_priv *max98373 = dev_get_drvdata(dev);
+
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return 0;
+}
+static int max98373_resume(struct device *dev)
+{
+ struct max98373_priv *max98373 = dev_get_drvdata(dev);
+
+ regmap_write(max98373->regmap,
+ MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
+ regcache_cache_only(max98373->regmap, false);
+ regcache_sync(max98373->regmap);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops max98373_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
+};
+
+static const struct snd_soc_codec_driver soc_codec_dev_max98373 = {
+ .probe = max98373_probe,
+ .component_driver = {
+ .controls = max98373_snd_controls,
+ .num_controls = ARRAY_SIZE(max98373_snd_controls),
+ .dapm_widgets = max98373_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets),
+ .dapm_routes = max98373_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98373_audio_map),
+ },
+};
+
+static const struct regmap_config max98373_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = MAX98373_R21FF_REV_ID,
+ .reg_defaults = max98373_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98373_reg),
+ .readable_reg = max98373_readable_register,
+ .volatile_reg = max98373_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static void max98373_slot_config(struct i2c_client *i2c,
+ struct max98373_priv *max98373)
+{
+ int value;
+ struct device *dev = &i2c->dev;
+
+ if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
+ max98373->v_slot = value & 0xF;
+ else
+ max98373->v_slot = 0;
+
+ if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
+ max98373->i_slot = value & 0xF;
+ else
+ max98373->i_slot = 1;
+
+ if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
+ max98373->spkfb_slot = value & 0xF;
+ else
+ max98373->spkfb_slot = 2;
+}
+
+static int max98373_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+
+ int ret = 0;
+ int reg = 0;
+ struct max98373_priv *max98373 = NULL;
+
+ max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL);
+
+ if (!max98373) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ i2c_set_clientdata(i2c, max98373);
+
+ /* update interleave mode info */
+ if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode"))
+ max98373->interleave_mode = 1;
+ else
+ max98373->interleave_mode = 0;
+
+
+ /* regmap initialization */
+ max98373->regmap
+ = devm_regmap_init_i2c(i2c, &max98373_regmap);
+ if (IS_ERR(max98373->regmap)) {
+ ret = PTR_ERR(max98373->regmap);
+ dev_err(&i2c->dev,
+ "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ /* Check Revision ID */
+ ret = regmap_read(max98373->regmap,
+ MAX98373_R21FF_REV_ID, &reg);
+ if (ret < 0) {
+ dev_err(&i2c->dev,
+ "Failed to read: 0x%02X\n", MAX98373_R21FF_REV_ID);
+ return ret;
+ }
+ dev_info(&i2c->dev, "MAX98373 revisionID: 0x%02X\n", reg);
+
+ /* voltage/current slot configuration */
+ max98373_slot_config(i2c, max98373);
+
+ /* codec registeration */
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98373,
+ max98373_dai, ARRAY_SIZE(max98373_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+
+ return ret;
+}
+
+static int max98373_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id max98373_i2c_id[] = {
+ { "max98373", 0},
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98373_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max98373_of_match[] = {
+ { .compatible = "maxim,max98373", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max98373_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98373_acpi_match[] = {
+ { "MX98373", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, max98373_acpi_match);
+#endif
+
+static struct i2c_driver max98373_i2c_driver = {
+ .driver = {
+ .name = "max98373",
+ .of_match_table = of_match_ptr(max98373_of_match),
+ .acpi_match_table = ACPI_PTR(max98373_acpi_match),
+ .pm = &max98373_pm,
+ },
+ .probe = max98373_i2c_probe,
+ .remove = max98373_i2c_remove,
+ .id_table = max98373_i2c_id,
+};
+
+module_i2c_driver(max98373_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98373 driver");
+MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h
new file mode 100644
index 0000000..d0b359d
--- /dev/null
+++ b/sound/soc/codecs/max98373.h
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2017, Maxim Integrated */
+#ifndef _MAX98373_H
+#define _MAX98373_H
+
+#define MAX98373_R2000_SW_RESET 0x2000
+#define MAX98373_R2001_INT_RAW1 0x2001
+#define MAX98373_R2002_INT_RAW2 0x2002
+#define MAX98373_R2003_INT_RAW3 0x2003
+#define MAX98373_R2004_INT_STATE1 0x2004
+#define MAX98373_R2005_INT_STATE2 0x2005
+#define MAX98373_R2006_INT_STATE3 0x2006
+#define MAX98373_R2007_INT_FLAG1 0x2007
+#define MAX98373_R2008_INT_FLAG2 0x2008
+#define MAX98373_R2009_INT_FLAG3 0x2009
+#define MAX98373_R200A_INT_EN1 0x200A
+#define MAX98373_R200B_INT_EN2 0x200B
+#define MAX98373_R200C_INT_EN3 0x200C
+#define MAX98373_R200D_INT_FLAG_CLR1 0x200D
+#define MAX98373_R200E_INT_FLAG_CLR2 0x200E
+#define MAX98373_R200F_INT_FLAG_CLR3 0x200F
+#define MAX98373_R2010_IRQ_CTRL 0x2010
+#define MAX98373_R2014_THERM_WARN_THRESH 0x2014
+#define MAX98373_R2015_THERM_SHDN_THRESH 0x2015
+#define MAX98373_R2016_THERM_HYSTERESIS 0x2016
+#define MAX98373_R2017_THERM_FOLDBACK_SET 0x2017
+#define MAX98373_R2018_THERM_FOLDBACK_EN 0x2018
+#define MAX98373_R201E_PIN_DRIVE_STRENGTH 0x201E
+#define MAX98373_R2020_PCM_TX_HIZ_EN_1 0x2020
+#define MAX98373_R2021_PCM_TX_HIZ_EN_2 0x2021
+#define MAX98373_R2022_PCM_TX_SRC_1 0x2022
+#define MAX98373_R2023_PCM_TX_SRC_2 0x2023
+#define MAX98373_R2024_PCM_DATA_FMT_CFG 0x2024
+#define MAX98373_R2025_AUDIO_IF_MODE 0x2025
+#define MAX98373_R2026_PCM_CLOCK_RATIO 0x2026
+#define MAX98373_R2027_PCM_SR_SETUP_1 0x2027
+#define MAX98373_R2028_PCM_SR_SETUP_2 0x2028
+#define MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 0x2029
+#define MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2 0x202A
+#define MAX98373_R202B_PCM_RX_EN 0x202B
+#define MAX98373_R202C_PCM_TX_EN 0x202C
+#define MAX98373_R202E_ICC_RX_CH_EN_1 0x202E
+#define MAX98373_R202F_ICC_RX_CH_EN_2 0x202F
+#define MAX98373_R2030_ICC_TX_HIZ_EN_1 0x2030
+#define MAX98373_R2031_ICC_TX_HIZ_EN_2 0x2031
+#define MAX98373_R2032_ICC_LINK_EN_CFG 0x2032
+#define MAX98373_R2034_ICC_TX_CNTL 0x2034
+#define MAX98373_R2035_ICC_TX_EN 0x2035
+#define MAX98373_R2036_SOUNDWIRE_CTRL 0x2036
+#define MAX98373_R203D_AMP_DIG_VOL_CTRL 0x203D
+#define MAX98373_R203E_AMP_PATH_GAIN 0x203E
+#define MAX98373_R203F_AMP_DSP_CFG 0x203F
+#define MAX98373_R2040_TONE_GEN_CFG 0x2040
+#define MAX98373_R2041_AMP_CFG 0x2041
+#define MAX98373_R2042_AMP_EDGE_RATE_CFG 0x2042
+#define MAX98373_R2043_AMP_EN 0x2043
+#define MAX98373_R2046_IV_SENSE_ADC_DSP_CFG 0x2046
+#define MAX98373_R2047_IV_SENSE_ADC_EN 0x2047
+#define MAX98373_R2051_MEAS_ADC_SAMPLING_RATE 0x2051
+#define MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG 0x2052
+#define MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG 0x2053
+#define MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK 0x2054
+#define MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK 0x2055
+#define MAX98373_R2056_MEAS_ADC_PVDD_CH_EN 0x2056
+#define MAX98373_R2090_BDE_LVL_HOLD 0x2090
+#define MAX98373_R2091_BDE_GAIN_ATK_REL_RATE 0x2091
+#define MAX98373_R2092_BDE_CLIPPER_MODE 0x2092
+#define MAX98373_R2097_BDE_L1_THRESH 0x2097
+#define MAX98373_R2098_BDE_L2_THRESH 0x2098
+#define MAX98373_R2099_BDE_L3_THRESH 0x2099
+#define MAX98373_R209A_BDE_L4_THRESH 0x209A
+#define MAX98373_R209B_BDE_THRESH_HYST 0x209B
+#define MAX98373_R20A8_BDE_L1_CFG_1 0x20A8
+#define MAX98373_R20A9_BDE_L1_CFG_2 0x20A9
+#define MAX98373_R20AA_BDE_L1_CFG_3 0x20AA
+#define MAX98373_R20AB_BDE_L2_CFG_1 0x20AB
+#define MAX98373_R20AC_BDE_L2_CFG_2 0x20AC
+#define MAX98373_R20AD_BDE_L2_CFG_3 0x20AD
+#define MAX98373_R20AE_BDE_L3_CFG_1 0x20AE
+#define MAX98373_R20AF_BDE_L3_CFG_2 0x20AF
+#define MAX98373_R20B0_BDE_L3_CFG_3 0x20B0
+#define MAX98373_R20B1_BDE_L4_CFG_1 0x20B1
+#define MAX98373_R20B2_BDE_L4_CFG_2 0x20B2
+#define MAX98373_R20B3_BDE_L4_CFG_3 0x20B3
+#define MAX98373_R20B4_BDE_INFINITE_HOLD_RELEASE 0x20B4
+#define MAX98373_R20B5_BDE_EN 0x20B5
+#define MAX98373_R20B6_BDE_CUR_STATE_READBACK 0x20B6
+#define MAX98373_R20D1_DHT_CFG 0x20D1
+#define MAX98373_R20D2_DHT_ATTACK_CFG 0x20D2
+#define MAX98373_R20D3_DHT_RELEASE_CFG 0x20D3
+#define MAX98373_R20D4_DHT_EN 0x20D4
+#define MAX98373_R20E0_LIMITER_THRESH_CFG 0x20E0
+#define MAX98373_R20E1_LIMITER_ATK_REL_RATES 0x20E1
+#define MAX98373_R20E2_LIMITER_EN 0x20E2
+#define MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG 0x20FE
+#define MAX98373_R20FF_GLOBAL_SHDN 0x20FF
+#define MAX98373_R21FF_REV_ID 0x21FF
+
+/* MAX98373_R2022_PCM_TX_SRC_1 */
+#define MAX98373_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98373_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98373_R2024_PCM_DATA_FMT_CFG */
+#define MAX98373_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+#define MAX98373_PCM_MODE_CFG_FORMAT_SHIFT (3)
+#define MAX98373_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 2)
+#define MAX98373_PCM_FORMAT_I2S (0x0 << 0)
+#define MAX98373_PCM_FORMAT_LJ (0x1 << 0)
+#define MAX98373_PCM_FORMAT_TDM_MODE0 (0x3 << 0)
+#define MAX98373_PCM_FORMAT_TDM_MODE1 (0x4 << 0)
+#define MAX98373_PCM_FORMAT_TDM_MODE2 (0x5 << 0)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98373_R2026_PCM_CLOCK_RATIO */
+#define MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 4)
+#define MAX98373_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98373_R2027_PCM_SR_SETUP_1 */
+#define MAX98373_PCM_SR_SET1_SR_MASK (0xF << 0)
+#define MAX98373_PCM_SR_SET1_SR_8000 (0x0 << 0)
+#define MAX98373_PCM_SR_SET1_SR_11025 (0x1 << 0)
+#define MAX98373_PCM_SR_SET1_SR_12000 (0x2 << 0)
+#define MAX98373_PCM_SR_SET1_SR_16000 (0x3 << 0)
+#define MAX98373_PCM_SR_SET1_SR_22050 (0x4 << 0)
+#define MAX98373_PCM_SR_SET1_SR_24000 (0x5 << 0)
+#define MAX98373_PCM_SR_SET1_SR_32000 (0x6 << 0)
+#define MAX98373_PCM_SR_SET1_SR_44100 (0x7 << 0)
+#define MAX98373_PCM_SR_SET1_SR_48000 (0x8 << 0)
+
+/* MAX98373_R2028_PCM_SR_SETUP_2 */
+#define MAX98373_PCM_SR_SET2_SR_MASK (0xF << 4)
+#define MAX98373_PCM_SR_SET2_SR_SHIFT (4)
+#define MAX98373_PCM_SR_SET2_IVADC_SR_MASK (0xF << 0)
+
+/* MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 */
+#define MAX98373_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
+#define MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
+#define MAX98373_PCM_TO_SPK_CH0_SRC_MASK (0xF << 0)
+
+/* MAX98373_R203E_AMP_PATH_GAIN */
+#define MAX98373_SPK_DIGI_GAIN_MASK (0xF << 4)
+#define MAX98373_SPK_DIGI_GAIN_SHIFT (4)
+#define MAX98373_FS_GAIN_MAX_MASK (0xF << 0)
+#define MAX98373_FS_GAIN_MAX_SHIFT (0)
+
+/* MAX98373_R203F_AMP_DSP_CFG */
+#define MAX98373_AMP_DSP_CFG_DCBLK_SHIFT (0)
+#define MAX98373_AMP_DSP_CFG_DITH_SHIFT (1)
+#define MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT (2)
+#define MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT (3)
+#define MAX98373_AMP_DSP_CFG_DAC_INV_SHIFT (5)
+#define MAX98373_AMP_VOL_SEL_SHIFT (7)
+
+/* MAX98373_R2043_AMP_EN */
+#define MAX98373_SPKFB_EN_MASK (0x1 << 1)
+#define MAX98373_SPK_EN_MASK (0x1 << 0)
+#define MAX98373_SPKFB_EN_SHIFT (1)
+
+/*MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG */
+#define MAX98373_FLT_EN_SHIFT (4)
+
+/* MAX98373_R20B2_BDE_L4_CFG_2 */
+#define MAX98373_LVL4_MUTE_EN_SHIFT (7)
+#define MAX98373_LVL4_HOLD_EN_SHIFT (6)
+
+/* MAX98373_R20B5_BDE_EN */
+#define MAX98373_BDE_EN_SHIFT (0)
+
+/* MAX98373_R20D1_DHT_CFG */
+#define MAX98373_DHT_SPK_GAIN_MIN_SHIFT (4)
+#define MAX98373_DHT_ROT_PNT_SHIFT (0)
+
+/* MAX98373_R20D2_DHT_ATTACK_CFG */
+#define MAX98373_DHT_ATTACK_STEP_SHIFT (3)
+#define MAX98373_DHT_ATTACK_RATE_SHIFT (0)
+
+/* MAX98373_R20D3_DHT_RELEASE_CFG */
+#define MAX98373_DHT_RELEASE_STEP_SHIFT (3)
+#define MAX98373_DHT_RELEASE_RATE_SHIFT (0)
+
+/* MAX98373_R20D4_DHT_EN */
+#define MAX98373_DHT_EN_SHIFT (0)
+
+/* MAX98373_R20E0_LIMITER_THRESH_CFG */
+#define MAX98373_LIMITER_THRESH_SHIFT (2)
+#define MAX98373_LIMITER_THRESH_SRC_SHIFT (0)
+
+/* MAX98373_R20E2_LIMITER_EN */
+#define MAX98373_LIMITER_EN_SHIFT (0)
+
+/* MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG */
+#define MAX98373_CLOCK_MON_SHIFT (0)
+
+/* MAX98373_R20FF_GLOBAL_SHDN */
+#define MAX98373_GLOBAL_EN_MASK (0x1 << 0)
+
+/* MAX98373_R2000_SW_RESET */
+#define MAX98373_SOFT_RESET (0x1 << 0)
+
+struct max98373_priv {
+ struct regmap *regmap;
+ unsigned int v_slot;
+ unsigned int i_slot;
+ unsigned int spkfb_slot;
+ bool interleave_mode;
+ unsigned int ch_size;
+ bool tdm_mode;
+};
+#endif
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 03d07bf..7b1d1b0 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -490,7 +490,7 @@ static int max98926_probe(struct snd_soc_codec *codec)
struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec);
max98926->codec = codec;
- codec->control_data = max98926->regmap;
+
/* Hi-Z all the slots */
regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0);
return 0;
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index a1d3935..f701fdc 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -682,7 +682,6 @@ static int max98927_probe(struct snd_soc_codec *codec)
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
max98927->codec = codec;
- codec->control_data = max98927->regmap;
/* Software Reset */
regmap_write(max98927->regmap,
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 4fd8d1d..be7a45f 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -610,6 +610,9 @@ static int mc13783_probe(struct snd_soc_codec *codec)
{
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+ snd_soc_codec_init_regmap(codec,
+ dev_get_regmap(codec->dev->parent, NULL));
+
/* these are the reset values */
mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A);
@@ -728,15 +731,9 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
}
};
-static struct regmap *mc13783_get_regmap(struct device *dev)
-{
- return dev_get_regmap(dev->parent, NULL);
-}
-
static const struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
.probe = mc13783_probe,
.remove = mc13783_remove,
- .get_regmap = mc13783_get_regmap,
.component_driver = {
.controls = mc13783_control_list,
.num_controls = ARRAY_SIZE(mc13783_control_list),
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index 5f3c42c..44062bb 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -267,7 +267,7 @@
#define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S32_LE)
static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
@@ -712,6 +712,8 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
return err;
}
+ snd_soc_codec_init_regmap(codec,
+ dev_get_regmap(codec->dev->parent, NULL));
snd_soc_codec_set_drvdata(codec, priv);
priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1);
priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE);
@@ -943,11 +945,6 @@ static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
return 0;
}
-static struct regmap *pm8916_get_regmap(struct device *dev)
-{
- return dev_get_regmap(dev->parent, NULL);
-}
-
static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
{
struct pm8916_wcd_analog_priv *priv = arg;
@@ -1082,7 +1079,6 @@ static const struct snd_soc_codec_driver pm8916_wcd_analog = {
.probe = pm8916_wcd_analog_probe,
.remove = pm8916_wcd_analog_remove,
.set_jack = pm8916_wcd_analog_set_jack,
- .get_regmap = pm8916_get_regmap,
.component_driver = {
.controls = pm8916_wcd_analog_snd_controls,
.num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls),
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index a10a724..13354d6 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -194,7 +194,7 @@
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_48000)
#define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S32_LE)
struct msm8916_wcd_digital_priv {
struct clk *ahbclk, *mclk;
@@ -645,7 +645,7 @@ static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
RX_I2S_CTL_RX_I2S_MODE_MASK,
RX_I2S_CTL_RX_I2S_MODE_16);
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S32_LE:
snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
TX_I2S_CTL_TX_I2S_MODE_MASK,
TX_I2S_CTL_TX_I2S_MODE_32);
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index f9c9933..b08fb7e 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -233,6 +233,41 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new digital_ch1_mux =
SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
+static int adc_power_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ msleep(300);
+ /* DO12 and DO34 pad output enable */
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+ NAU8540_I2S_DO12_TRI, 0);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+ NAU8540_I2S_DO34_TRI, 0);
+ } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+ NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+ NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
+ }
+ return 0;
+}
+
+static int aiftx_power_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0001);
+ regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0000);
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0),
@@ -247,14 +282,18 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0),
SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0),
- SND_SOC_DAPM_ADC("ADC1", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 0, 0),
- SND_SOC_DAPM_ADC("ADC2", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 1, 0),
- SND_SOC_DAPM_ADC("ADC3", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 2, 0),
- SND_SOC_DAPM_ADC("ADC4", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 3, 0),
+ SND_SOC_DAPM_ADC_E("ADC1", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0),
@@ -270,7 +309,8 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
SND_SOC_DAPM_MUX("Digital CH1 Mux",
SND_SOC_NOPM, 0, 0, &digital_ch1_mux),
- SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT_E("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0,
+ aiftx_power_control, SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
@@ -575,7 +615,8 @@ static void nau8540_fll_apply(struct regmap *regmap,
NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK,
NAU8540_CLK_SRC_MCLK | fll_param->mclk_src);
regmap_update_bits(regmap, NAU8540_REG_FLL1,
- NAU8540_FLL_RATIO_MASK, fll_param->ratio);
+ NAU8540_FLL_RATIO_MASK | NAU8540_ICTRL_LATCH_MASK,
+ fll_param->ratio | (0x6 << NAU8540_ICTRL_LATCH_SFT));
/* FLL 16-bit fractional input */
regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac);
/* FLL 10-bit integer input */
@@ -596,13 +637,14 @@ static void nau8540_fll_apply(struct regmap *regmap,
NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
NAU8540_FLL_FTR_SW_FILTER);
regmap_update_bits(regmap, NAU8540_REG_FLL6,
- NAU8540_SDM_EN, NAU8540_SDM_EN);
+ NAU8540_SDM_EN | NAU8540_CUTOFF500,
+ NAU8540_SDM_EN | NAU8540_CUTOFF500);
} else {
regmap_update_bits(regmap, NAU8540_REG_FLL5,
NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU);
- regmap_update_bits(regmap,
- NAU8540_REG_FLL6, NAU8540_SDM_EN, 0);
+ regmap_update_bits(regmap, NAU8540_REG_FLL6,
+ NAU8540_SDM_EN | NAU8540_CUTOFF500, 0);
}
}
@@ -617,17 +659,22 @@ static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
switch (pll_id) {
case NAU8540_CLK_FLL_MCLK:
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
- NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK);
+ NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+ NAU8540_FLL_CLK_SRC_MCLK | 0);
break;
case NAU8540_CLK_FLL_BLK:
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
- NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK);
+ NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+ NAU8540_FLL_CLK_SRC_BLK |
+ (0xf << NAU8540_GAIN_ERR_SFT));
break;
case NAU8540_CLK_FLL_FS:
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
- NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS);
+ NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+ NAU8540_FLL_CLK_SRC_FS |
+ (0xf << NAU8540_GAIN_ERR_SFT));
break;
default:
@@ -710,9 +757,24 @@ static void nau8540_init_regs(struct nau8540 *nau8540)
regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN,
NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN);
- /* ADC OSR selection, CLK_ADC = Fs * OSR */
+ /* ADC OSR selection, CLK_ADC = Fs * OSR;
+ * Channel time alignment enable.
+ */
regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
- NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64);
+ NAU8540_CH_SYNC | NAU8540_ADC_OSR_MASK,
+ NAU8540_CH_SYNC | NAU8540_ADC_OSR_64);
+ /* PGA input mode selection */
+ regmap_update_bits(regmap, NAU8540_REG_FEPGA1,
+ NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT,
+ NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT);
+ regmap_update_bits(regmap, NAU8540_REG_FEPGA2,
+ NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT,
+ NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT);
+ /* DO12 and DO34 pad output disable */
+ regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL1,
+ NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
+ regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL2,
+ NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
}
static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h
index 5db5b22..732b490 100644
--- a/sound/soc/codecs/nau8540.h
+++ b/sound/soc/codecs/nau8540.h
@@ -100,9 +100,13 @@
#define NAU8540_CLK_MCLK_SRC_MASK 0xf
/* FLL1 (0x04) */
+#define NAU8540_ICTRL_LATCH_SFT 10
+#define NAU8540_ICTRL_LATCH_MASK (0x7 << NAU8540_ICTRL_LATCH_SFT)
#define NAU8540_FLL_RATIO_MASK 0x7f
/* FLL3 (0x06) */
+#define NAU8540_GAIN_ERR_SFT 12
+#define NAU8540_GAIN_ERR_MASK (0xf << NAU8540_GAIN_ERR_SFT)
#define NAU8540_FLL_CLK_SRC_SFT 10
#define NAU8540_FLL_CLK_SRC_MASK (0x3 << NAU8540_FLL_CLK_SRC_SFT)
#define NAU8540_FLL_CLK_SRC_MCLK (0 << NAU8540_FLL_CLK_SRC_SFT)
@@ -127,6 +131,7 @@
/* FLL6 (0x9) */
#define NAU8540_DCO_EN (0x1 << 15)
#define NAU8540_SDM_EN (0x1 << 14)
+#define NAU8540_CUTOFF500 (0x1 << 13)
/* PCM_CTRL0 (0x10) */
#define NAU8540_I2S_BP_SFT 7
@@ -146,6 +151,7 @@
#define NAU8540_I2S_DF_PCM_AB 0x3
/* PCM_CTRL1 (0x11) */
+#define NAU8540_I2S_DO12_TRI (0x1 << 15)
#define NAU8540_I2S_LRC_DIV_SFT 12
#define NAU8540_I2S_LRC_DIV_MASK (0x3 << NAU8540_I2S_LRC_DIV_SFT)
#define NAU8540_I2S_DO12_OE (0x1 << 4)
@@ -156,6 +162,7 @@
#define NAU8540_I2S_BLK_DIV_MASK 0x7
/* PCM_CTRL1 (0x12) */
+#define NAU8540_I2S_DO34_TRI (0x1 << 15)
#define NAU8540_I2S_DO34_OE (0x1 << 11)
#define NAU8540_I2S_TSLOT_L_MASK 0x3ff
@@ -165,6 +172,7 @@
#define NAU8540_TDM_TX_MASK 0xf
/* ADC_SAMPLE_RATE (0x3A) */
+#define NAU8540_CH_SYNC (0x1 << 14)
#define NAU8540_ADC_OSR_MASK 0x3
#define NAU8540_ADC_OSR_256 0x3
#define NAU8540_ADC_OSR_128 0x2
@@ -183,6 +191,18 @@
#define NAU8540_PRECHARGE_DIS (0x1 << 13)
#define NAU8540_GLOBAL_BIAS_EN (0x1 << 12)
+/* FEPGA1 (0x69) */
+#define NAU8540_FEPGA1_MODCH2_SHT_SFT 7
+#define NAU8540_FEPGA1_MODCH2_SHT (0x1 << NAU8540_FEPGA1_MODCH2_SHT_SFT)
+#define NAU8540_FEPGA1_MODCH1_SHT_SFT 3
+#define NAU8540_FEPGA1_MODCH1_SHT (0x1 << NAU8540_FEPGA1_MODCH1_SHT_SFT)
+
+/* FEPGA2 (0x6A) */
+#define NAU8540_FEPGA2_MODCH4_SHT_SFT 7
+#define NAU8540_FEPGA2_MODCH4_SHT (0x1 << NAU8540_FEPGA2_MODCH4_SHT_SFT)
+#define NAU8540_FEPGA2_MODCH3_SHT_SFT 3
+#define NAU8540_FEPGA2_MODCH3_SHT (0x1 << NAU8540_FEPGA2_MODCH3_SHT_SFT)
+
/* System Clock Source */
enum {
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 0240759..088e0ce 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -43,7 +43,7 @@ static bool nau8824_is_jack_inserted(struct nau8824 *nau8824);
/* the parameter threshold of FLL */
#define NAU_FREF_MAX 13500000
-#define NAU_FVCO_MAX 124000000
+#define NAU_FVCO_MAX 100000000
#define NAU_FVCO_MIN 90000000
/* scaling for mclk from sysclk_src output */
@@ -811,7 +811,8 @@ static void nau8824_eject_jack(struct nau8824 *nau8824)
NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
/* Close clock for jack type detection at manual mode */
- nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+ if (dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
}
static void nau8824_jdet_work(struct work_struct *work)
@@ -843,6 +844,11 @@ static void nau8824_jdet_work(struct work_struct *work)
event_mask |= SND_JACK_HEADSET;
snd_soc_jack_report(nau8824->jack, event, event_mask);
+ /* Enable short key press and release interruption. */
+ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+ NAU8824_IRQ_KEY_RELEASE_DIS |
+ NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+
nau8824_sema_release(nau8824);
}
@@ -850,15 +856,15 @@ static void nau8824_setup_auto_irq(struct nau8824 *nau8824)
{
struct regmap *regmap = nau8824->regmap;
- /* Enable jack ejection, short key press and release interruption. */
+ /* Enable jack ejection interruption. */
regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1,
NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN,
NAU8824_IRQ_EJECT_EN);
regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
- NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_KEY_RELEASE_DIS |
- NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+ NAU8824_IRQ_EJECT_DIS, 0);
/* Enable internal VCO needed for interruptions */
- nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
+ if (nau8824->dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
NAU8824_JD_SLEEP_MODE, 0);
}
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 714ce17..a1b697b 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -194,10 +194,10 @@ static const struct reg_default nau8825_reg_defaults[] = {
/* register backup table when cross talk detection */
static struct reg_default nau8825_xtalk_baktab[] = {
- { NAU8825_REG_ADC_DGAIN_CTRL, 0 },
+ { NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf },
{ NAU8825_REG_HSVOL_CTRL, 0 },
- { NAU8825_REG_DACL_CTRL, 0 },
- { NAU8825_REG_DACR_CTRL, 0 },
+ { NAU8825_REG_DACL_CTRL, 0x00cf },
+ { NAU8825_REG_DACR_CTRL, 0x02cf },
};
static const unsigned short logtable[256] = {
@@ -245,13 +245,14 @@ static const unsigned short logtable[256] = {
* tasks are allowed to acquire the semaphore, calling this function will
* put the task to sleep. If the semaphore is not released within the
* specified number of jiffies, this function returns.
- * Acquires the semaphore without jiffies. If no more tasks are allowed
- * to acquire the semaphore, calling this function will put the task to
- * sleep until the semaphore is released.
* If the semaphore is not released within the specified number of jiffies,
- * this function returns -ETIME.
- * If the sleep is interrupted by a signal, this function will return -EINTR.
- * It returns 0 if the semaphore was acquired successfully.
+ * this function returns -ETIME. If the sleep is interrupted by a signal,
+ * this function will return -EINTR. It returns 0 if the semaphore was
+ * acquired successfully.
+ *
+ * Acquires the semaphore without jiffies. Try to acquire the semaphore
+ * atomically. Returns 0 if the semaphore has been acquired successfully
+ * or 1 if it it cannot be acquired.
*/
static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
{
@@ -262,8 +263,8 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
if (ret < 0)
dev_warn(nau8825->dev, "Acquire semaphore timeout\n");
} else {
- ret = down_interruptible(&nau8825->xtalk_sem);
- if (ret < 0)
+ ret = down_trylock(&nau8825->xtalk_sem);
+ if (ret)
dev_warn(nau8825->dev, "Acquire semaphore fail\n");
}
@@ -454,22 +455,32 @@ static void nau8825_xtalk_backup(struct nau8825 *nau8825)
{
int i;
+ if (nau8825->xtalk_baktab_initialized)
+ return;
+
/* Backup some register values to backup table */
for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++)
regmap_read(nau8825->regmap, nau8825_xtalk_baktab[i].reg,
&nau8825_xtalk_baktab[i].def);
+
+ nau8825->xtalk_baktab_initialized = true;
}
-static void nau8825_xtalk_restore(struct nau8825 *nau8825)
+static void nau8825_xtalk_restore(struct nau8825 *nau8825, bool cause_cancel)
{
int i, volume;
+ if (!nau8825->xtalk_baktab_initialized)
+ return;
+
/* Restore register values from backup table; When the driver restores
- * the headphone volumem, it needs recover to original level gradually
- * with 3dB per step for less pop noise.
+ * the headphone volume in XTALK_DONE state, it needs recover to
+ * original level gradually with 3dB per step for less pop noise.
+ * Otherwise, the restore should do ASAP.
*/
for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) {
- if (nau8825_xtalk_baktab[i].reg == NAU8825_REG_HSVOL_CTRL) {
+ if (!cause_cancel && nau8825_xtalk_baktab[i].reg ==
+ NAU8825_REG_HSVOL_CTRL) {
/* Ramping up the volume change to reduce pop noise */
volume = nau8825_xtalk_baktab[i].def &
NAU8825_HPR_VOL_MASK;
@@ -479,6 +490,8 @@ static void nau8825_xtalk_restore(struct nau8825 *nau8825)
regmap_write(nau8825->regmap, nau8825_xtalk_baktab[i].reg,
nau8825_xtalk_baktab[i].def);
}
+
+ nau8825->xtalk_baktab_initialized = false;
}
static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825)
@@ -644,7 +657,7 @@ static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825)
NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, 0);
}
-static void nau8825_xtalk_clean(struct nau8825 *nau8825)
+static void nau8825_xtalk_clean(struct nau8825 *nau8825, bool cause_cancel)
{
/* Enable internal VCO needed for interruptions */
nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
@@ -660,7 +673,7 @@ static void nau8825_xtalk_clean(struct nau8825 *nau8825)
NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE);
/* Restore value of specific register for cross talk */
- nau8825_xtalk_restore(nau8825);
+ nau8825_xtalk_restore(nau8825, cause_cancel);
}
static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol)
@@ -779,7 +792,7 @@ static void nau8825_xtalk_measure(struct nau8825 *nau8825)
dev_dbg(nau8825->dev, "cross talk sidetone: %x\n", sidetone);
regmap_write(nau8825->regmap, NAU8825_REG_DAC_DGAIN_CTRL,
(sidetone << 8) | sidetone);
- nau8825_xtalk_clean(nau8825);
+ nau8825_xtalk_clean(nau8825, false);
nau8825->xtalk_state = NAU8825_XTALK_DONE;
break;
default:
@@ -815,13 +828,14 @@ static void nau8825_xtalk_work(struct work_struct *work)
static void nau8825_xtalk_cancel(struct nau8825 *nau8825)
{
- /* If the xtalk_protect is true, that means the process is still
- * on going. The driver forces to cancel the cross talk task and
+ /* If the crosstalk is eanbled and the process is on going,
+ * the driver forces to cancel the crosstalk task and
* restores the configuration to original status.
*/
- if (nau8825->xtalk_protect) {
+ if (nau8825->xtalk_enable && nau8825->xtalk_state !=
+ NAU8825_XTALK_DONE) {
cancel_work_sync(&nau8825->xtalk_work);
- nau8825_xtalk_clean(nau8825);
+ nau8825_xtalk_clean(nau8825, true);
}
/* Reset parameters for cross talk suppression function */
nau8825_sema_reset(nau8825);
@@ -905,6 +919,7 @@ static int nau8825_adc_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ msleep(125);
regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL,
NAU8825_ENABLE_ADC, NAU8825_ENABLE_ADC);
break;
@@ -1245,8 +1260,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr);
osr &= NAU8825_DAC_OVERSAMPLE_MASK;
if (nau8825_clock_check(nau8825, substream->stream,
- params_rate(params), osr))
+ params_rate(params), osr)) {
+ nau8825_sema_release(nau8825);
return -EINVAL;
+ }
regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
NAU8825_CLK_DAC_SRC_MASK,
osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT);
@@ -1254,8 +1271,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr);
osr &= NAU8825_ADC_SYNC_DOWN_MASK;
if (nau8825_clock_check(nau8825, substream->stream,
- params_rate(params), osr))
+ params_rate(params), osr)) {
+ nau8825_sema_release(nau8825);
return -EINVAL;
+ }
regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
NAU8825_CLK_ADC_SRC_MASK,
osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT);
@@ -1272,8 +1291,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
bclk_div = 1;
else if (bclk_fs <= 128)
bclk_div = 0;
- else
+ else {
+ nau8825_sema_release(nau8825);
return -EINVAL;
+ }
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK,
((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div);
@@ -1293,6 +1314,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
val_len |= NAU8825_I2S_DL_32;
break;
default:
+ nau8825_sema_release(nau8825);
return -EINVAL;
}
@@ -1311,8 +1333,6 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
unsigned int ctrl1_val = 0, ctrl2_val = 0;
- nau8825_sema_acquire(nau8825, 3 * HZ);
-
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
ctrl2_val |= NAU8825_I2S_MS_MASTER;
@@ -1354,6 +1374,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
+ nau8825_sema_acquire(nau8825, 3 * HZ);
+
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK |
NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK,
@@ -1686,7 +1708,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
} else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
if (nau8825_is_jack_inserted(regmap)) {
event |= nau8825_jack_insert(nau8825);
- if (!nau8825->xtalk_bypass && !nau8825->high_imped) {
+ if (nau8825->xtalk_enable && !nau8825->high_imped) {
/* Apply the cross talk suppression in the
* headset without high impedance.
*/
@@ -1700,12 +1722,15 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
int ret;
nau8825->xtalk_protect = true;
ret = nau8825_sema_acquire(nau8825, 0);
- if (ret < 0)
+ if (ret)
nau8825->xtalk_protect = false;
}
/* Startup cross talk detection process */
- nau8825->xtalk_state = NAU8825_XTALK_PREPARE;
- schedule_work(&nau8825->xtalk_work);
+ if (nau8825->xtalk_protect) {
+ nau8825->xtalk_state =
+ NAU8825_XTALK_PREPARE;
+ schedule_work(&nau8825->xtalk_work);
+ }
} else {
/* The cross talk suppression shouldn't apply
* in the headset with high impedance. Thus,
@@ -1732,7 +1757,9 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
nau8825->xtalk_event_mask = event_mask;
}
} else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) {
- schedule_work(&nau8825->xtalk_work);
+ /* crosstalk detection enable and process on going */
+ if (nau8825->xtalk_enable && nau8825->xtalk_protect)
+ schedule_work(&nau8825->xtalk_work);
clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ;
} else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) ==
NAU8825_JACK_INSERTION_DETECTED) {
@@ -2381,7 +2408,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
regcache_sync(nau8825->regmap);
nau8825->xtalk_protect = true;
ret = nau8825_sema_acquire(nau8825, 0);
- if (ret < 0)
+ if (ret)
nau8825->xtalk_protect = false;
enable_irq(nau8825->irq);
@@ -2440,8 +2467,8 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825)
nau8825->jack_insert_debounce);
dev_dbg(dev, "jack-eject-debounce: %d\n",
nau8825->jack_eject_debounce);
- dev_dbg(dev, "crosstalk-bypass: %d\n",
- nau8825->xtalk_bypass);
+ dev_dbg(dev, "crosstalk-enable: %d\n",
+ nau8825->xtalk_enable);
}
static int nau8825_read_device_properties(struct device *dev,
@@ -2506,8 +2533,8 @@ static int nau8825_read_device_properties(struct device *dev,
&nau8825->jack_eject_debounce);
if (ret)
nau8825->jack_eject_debounce = 0;
- nau8825->xtalk_bypass = device_property_read_bool(dev,
- "nuvoton,crosstalk-bypass");
+ nau8825->xtalk_enable = device_property_read_bool(dev,
+ "nuvoton,crosstalk-enable");
nau8825->mclk = devm_clk_get(dev, "mclk");
if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
@@ -2568,6 +2595,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c,
*/
nau8825->xtalk_state = NAU8825_XTALK_DONE;
nau8825->xtalk_protect = false;
+ nau8825->xtalk_baktab_initialized = false;
sema_init(&nau8825->xtalk_sem, 1);
INIT_WORK(&nau8825->xtalk_work, nau8825_xtalk_work);
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index 8aee5c86..f7e7321 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -476,7 +476,8 @@ struct nau8825 {
int xtalk_event_mask;
bool xtalk_protect;
int imp_rms[NAU8825_XTALK_IMM];
- int xtalk_bypass;
+ int xtalk_enable;
+ bool xtalk_baktab_initialized; /* True if initialized. */
};
int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c
new file mode 100644
index 0000000..5436212
--- /dev/null
+++ b/sound/soc/codecs/pcm186x-i2c.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC - I2C
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ * Andreas Dannenberg <dannenberg@ti.com>
+ * Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "pcm186x.h"
+
+static const struct of_device_id pcm186x_of_match[] = {
+ { .compatible = "ti,pcm1862", .data = (void *)PCM1862 },
+ { .compatible = "ti,pcm1863", .data = (void *)PCM1863 },
+ { .compatible = "ti,pcm1864", .data = (void *)PCM1864 },
+ { .compatible = "ti,pcm1865", .data = (void *)PCM1865 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm186x_of_match);
+
+static int pcm186x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ const enum pcm186x_type type = (enum pcm186x_type)id->driver_data;
+ int irq = i2c->irq;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(i2c, &pcm186x_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcm186x_probe(&i2c->dev, type, irq, regmap);
+}
+
+static int pcm186x_i2c_remove(struct i2c_client *i2c)
+{
+ pcm186x_remove(&i2c->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id pcm186x_i2c_id[] = {
+ { "pcm1862", PCM1862 },
+ { "pcm1863", PCM1863 },
+ { "pcm1864", PCM1864 },
+ { "pcm1865", PCM1865 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id);
+
+static struct i2c_driver pcm186x_i2c_driver = {
+ .probe = pcm186x_i2c_probe,
+ .remove = pcm186x_i2c_remove,
+ .id_table = pcm186x_i2c_id,
+ .driver = {
+ .name = "pcm186x",
+ .of_match_table = pcm186x_of_match,
+ },
+};
+module_i2c_driver(pcm186x_i2c_driver);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("PCM186x Universal Audio ADC I2C Interface Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x-spi.c b/sound/soc/codecs/pcm186x-spi.c
new file mode 100644
index 0000000..2366f8e
--- /dev/null
+++ b/sound/soc/codecs/pcm186x-spi.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC - SPI
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ * Andreas Dannenberg <dannenberg@ti.com>
+ * Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "pcm186x.h"
+
+static const struct of_device_id pcm186x_of_match[] = {
+ { .compatible = "ti,pcm1862", .data = (void *)PCM1862 },
+ { .compatible = "ti,pcm1863", .data = (void *)PCM1863 },
+ { .compatible = "ti,pcm1864", .data = (void *)PCM1864 },
+ { .compatible = "ti,pcm1865", .data = (void *)PCM1865 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm186x_of_match);
+
+static int pcm186x_spi_probe(struct spi_device *spi)
+{
+ const enum pcm186x_type type =
+ (enum pcm186x_type)spi_get_device_id(spi)->driver_data;
+ int irq = spi->irq;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &pcm186x_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcm186x_probe(&spi->dev, type, irq, regmap);
+}
+
+static int pcm186x_spi_remove(struct spi_device *spi)
+{
+ pcm186x_remove(&spi->dev);
+
+ return 0;
+}
+
+static const struct spi_device_id pcm186x_spi_id[] = {
+ { "pcm1862", PCM1862 },
+ { "pcm1863", PCM1863 },
+ { "pcm1864", PCM1864 },
+ { "pcm1865", PCM1865 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, pcm186x_spi_id);
+
+static struct spi_driver pcm186x_spi_driver = {
+ .probe = pcm186x_spi_probe,
+ .remove = pcm186x_spi_remove,
+ .id_table = pcm186x_spi_id,
+ .driver = {
+ .name = "pcm186x",
+ .of_match_table = pcm186x_of_match,
+ },
+};
+module_spi_driver(pcm186x_spi_driver);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("PCM186x Universal Audio ADC SPI Interface Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
new file mode 100644
index 0000000..cdb5142
--- /dev/null
+++ b/sound/soc/codecs/pcm186x.c
@@ -0,0 +1,719 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ * Andreas Dannenberg <dannenberg@ti.com>
+ * Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "pcm186x.h"
+
+static const char * const pcm186x_supply_names[] = {
+ "avdd", /* Analog power supply. Connect to 3.3-V supply. */
+ "dvdd", /* Digital power supply. Connect to 3.3-V supply. */
+ "iovdd", /* I/O power supply. Connect to 3.3-V or 1.8-V. */
+};
+#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
+
+struct pcm186x_priv {
+ struct regmap *regmap;
+ struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES];
+ unsigned int sysclk;
+ unsigned int tdm_offset;
+ bool is_tdm_mode;
+ bool is_master_mode;
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 4000, 50);
+
+static const struct snd_kcontrol_new pcm1863_snd_controls[] = {
+ SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L,
+ PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
+ pcm186x_pga_tlv),
+};
+
+static const struct snd_kcontrol_new pcm1865_snd_controls[] = {
+ SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L,
+ PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
+ pcm186x_pga_tlv),
+ SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L,
+ PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0,
+ pcm186x_pga_tlv),
+};
+
+static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x20, 0x30
+};
+
+static const char * const pcm186x_adcl_input_channel_sel_text[] = {
+ "No Select",
+ "VINL1[SE]", /* Default for ADC1L */
+ "VINL2[SE]", /* Default for ADC2L */
+ "VINL2[SE] + VINL1[SE]",
+ "VINL3[SE]",
+ "VINL3[SE] + VINL1[SE]",
+ "VINL3[SE] + VINL2[SE]",
+ "VINL3[SE] + VINL2[SE] + VINL1[SE]",
+ "VINL4[SE]",
+ "VINL4[SE] + VINL1[SE]",
+ "VINL4[SE] + VINL2[SE]",
+ "VINL4[SE] + VINL2[SE] + VINL1[SE]",
+ "VINL4[SE] + VINL3[SE]",
+ "VINL4[SE] + VINL3[SE] + VINL1[SE]",
+ "VINL4[SE] + VINL3[SE] + VINL2[SE]",
+ "VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]",
+ "{VIN1P, VIN1M}[DIFF]",
+ "{VIN4P, VIN4M}[DIFF]",
+ "{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
+};
+
+static const char * const pcm186x_adcr_input_channel_sel_text[] = {
+ "No Select",
+ "VINR1[SE]", /* Default for ADC1R */
+ "VINR2[SE]", /* Default for ADC2R */
+ "VINR2[SE] + VINR1[SE]",
+ "VINR3[SE]",
+ "VINR3[SE] + VINR1[SE]",
+ "VINR3[SE] + VINR2[SE]",
+ "VINR3[SE] + VINR2[SE] + VINR1[SE]",
+ "VINR4[SE]",
+ "VINR4[SE] + VINR1[SE]",
+ "VINR4[SE] + VINR2[SE]",
+ "VINR4[SE] + VINR2[SE] + VINR1[SE]",
+ "VINR4[SE] + VINR3[SE]",
+ "VINR4[SE] + VINR3[SE] + VINR1[SE]",
+ "VINR4[SE] + VINR3[SE] + VINR2[SE]",
+ "VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]",
+ "{VIN2P, VIN2M}[DIFF]",
+ "{VIN3P, VIN3M}[DIFF]",
+ "{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
+};
+
+static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
+ PCM186X_ADC_INPUT_SEL_MASK,
+ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
+ pcm186x_adcl_input_channel_sel_text,
+ pcm186x_adc_input_channel_sel_value),
+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
+ PCM186X_ADC_INPUT_SEL_MASK,
+ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
+ pcm186x_adcr_input_channel_sel_text,
+ pcm186x_adc_input_channel_sel_value),
+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0,
+ PCM186X_ADC_INPUT_SEL_MASK,
+ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
+ pcm186x_adcl_input_channel_sel_text,
+ pcm186x_adc_input_channel_sel_value),
+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0,
+ PCM186X_ADC_INPUT_SEL_MASK,
+ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
+ pcm186x_adcr_input_channel_sel_text,
+ pcm186x_adc_input_channel_sel_value),
+};
+
+static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = {
+ SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]),
+ SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]),
+ SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]),
+ SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]),
+};
+
+static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("VINL1"),
+ SND_SOC_DAPM_INPUT("VINR1"),
+ SND_SOC_DAPM_INPUT("VINL2"),
+ SND_SOC_DAPM_INPUT("VINR2"),
+ SND_SOC_DAPM_INPUT("VINL3"),
+ SND_SOC_DAPM_INPUT("VINR3"),
+ SND_SOC_DAPM_INPUT("VINL4"),
+ SND_SOC_DAPM_INPUT("VINR4"),
+
+ SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0,
+ &pcm186x_adc_mux_controls[0]),
+ SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0,
+ &pcm186x_adc_mux_controls[1]),
+
+ /*
+ * Put the codec into SLEEP mode when not in use, allowing the
+ * Energysense mechanism to operate.
+ */
+ SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("VINL1"),
+ SND_SOC_DAPM_INPUT("VINR1"),
+ SND_SOC_DAPM_INPUT("VINL2"),
+ SND_SOC_DAPM_INPUT("VINR2"),
+ SND_SOC_DAPM_INPUT("VINL3"),
+ SND_SOC_DAPM_INPUT("VINR3"),
+ SND_SOC_DAPM_INPUT("VINL4"),
+ SND_SOC_DAPM_INPUT("VINR4"),
+
+ SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0,
+ &pcm186x_adc_mux_controls[0]),
+ SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0,
+ &pcm186x_adc_mux_controls[1]),
+ SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0,
+ &pcm186x_adc_mux_controls[2]),
+ SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0,
+ &pcm186x_adc_mux_controls[3]),
+
+ /*
+ * Put the codec into SLEEP mode when not in use, allowing the
+ * Energysense mechanism to operate.
+ */
+ SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1, 0),
+ SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1, 0),
+};
+
+static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = {
+ { "ADC Left Capture Source", NULL, "VINL1" },
+ { "ADC Left Capture Source", NULL, "VINR1" },
+ { "ADC Left Capture Source", NULL, "VINL2" },
+ { "ADC Left Capture Source", NULL, "VINR2" },
+ { "ADC Left Capture Source", NULL, "VINL3" },
+ { "ADC Left Capture Source", NULL, "VINR3" },
+ { "ADC Left Capture Source", NULL, "VINL4" },
+ { "ADC Left Capture Source", NULL, "VINR4" },
+
+ { "ADC", NULL, "ADC Left Capture Source" },
+
+ { "ADC Right Capture Source", NULL, "VINL1" },
+ { "ADC Right Capture Source", NULL, "VINR1" },
+ { "ADC Right Capture Source", NULL, "VINL2" },
+ { "ADC Right Capture Source", NULL, "VINR2" },
+ { "ADC Right Capture Source", NULL, "VINL3" },
+ { "ADC Right Capture Source", NULL, "VINR3" },
+ { "ADC Right Capture Source", NULL, "VINL4" },
+ { "ADC Right Capture Source", NULL, "VINR4" },
+
+ { "ADC", NULL, "ADC Right Capture Source" },
+};
+
+static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = {
+ { "ADC1 Left Capture Source", NULL, "VINL1" },
+ { "ADC1 Left Capture Source", NULL, "VINR1" },
+ { "ADC1 Left Capture Source", NULL, "VINL2" },
+ { "ADC1 Left Capture Source", NULL, "VINR2" },
+ { "ADC1 Left Capture Source", NULL, "VINL3" },
+ { "ADC1 Left Capture Source", NULL, "VINR3" },
+ { "ADC1 Left Capture Source", NULL, "VINL4" },
+ { "ADC1 Left Capture Source", NULL, "VINR4" },
+
+ { "ADC1", NULL, "ADC1 Left Capture Source" },
+
+ { "ADC1 Right Capture Source", NULL, "VINL1" },
+ { "ADC1 Right Capture Source", NULL, "VINR1" },
+ { "ADC1 Right Capture Source", NULL, "VINL2" },
+ { "ADC1 Right Capture Source", NULL, "VINR2" },
+ { "ADC1 Right Capture Source", NULL, "VINL3" },
+ { "ADC1 Right Capture Source", NULL, "VINR3" },
+ { "ADC1 Right Capture Source", NULL, "VINL4" },
+ { "ADC1 Right Capture Source", NULL, "VINR4" },
+
+ { "ADC1", NULL, "ADC1 Right Capture Source" },
+
+ { "ADC2 Left Capture Source", NULL, "VINL1" },
+ { "ADC2 Left Capture Source", NULL, "VINR1" },
+ { "ADC2 Left Capture Source", NULL, "VINL2" },
+ { "ADC2 Left Capture Source", NULL, "VINR2" },
+ { "ADC2 Left Capture Source", NULL, "VINL3" },
+ { "ADC2 Left Capture Source", NULL, "VINR3" },
+ { "ADC2 Left Capture Source", NULL, "VINL4" },
+ { "ADC2 Left Capture Source", NULL, "VINR4" },
+
+ { "ADC2", NULL, "ADC2 Left Capture Source" },
+
+ { "ADC2 Right Capture Source", NULL, "VINL1" },
+ { "ADC2 Right Capture Source", NULL, "VINR1" },
+ { "ADC2 Right Capture Source", NULL, "VINL2" },
+ { "ADC2 Right Capture Source", NULL, "VINR2" },
+ { "ADC2 Right Capture Source", NULL, "VINL3" },
+ { "ADC2 Right Capture Source", NULL, "VINR3" },
+ { "ADC2 Right Capture Source", NULL, "VINL4" },
+ { "ADC2 Right Capture Source", NULL, "VINR4" },
+
+ { "ADC2", NULL, "ADC2 Right Capture Source" },
+};
+
+static int pcm186x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+ unsigned int rate = params_rate(params);
+ unsigned int format = params_format(params);
+ unsigned int width = params_width(params);
+ unsigned int channels = params_channels(params);
+ unsigned int div_lrck;
+ unsigned int div_bck;
+ u8 tdm_tx_sel = 0;
+ u8 pcm_cfg = 0;
+
+ dev_dbg(codec->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
+ __func__, rate, format, width, channels);
+
+ switch (width) {
+ case 16:
+ pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 <<
+ PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+ PCM186X_PCM_CFG_TX_WLEN_16 <<
+ PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+ break;
+ case 20:
+ pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 <<
+ PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+ PCM186X_PCM_CFG_TX_WLEN_20 <<
+ PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+ break;
+ case 24:
+ pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 <<
+ PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+ PCM186X_PCM_CFG_TX_WLEN_24 <<
+ PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+ break;
+ case 32:
+ pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 <<
+ PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+ PCM186X_PCM_CFG_TX_WLEN_32 <<
+ PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, PCM186X_PCM_CFG,
+ PCM186X_PCM_CFG_RX_WLEN_MASK |
+ PCM186X_PCM_CFG_TX_WLEN_MASK,
+ pcm_cfg);
+
+ div_lrck = width * channels;
+
+ if (priv->is_tdm_mode) {
+ /* Select TDM transmission data */
+ switch (channels) {
+ case 2:
+ tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH;
+ break;
+ case 4:
+ tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH;
+ break;
+ case 6:
+ tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, PCM186X_TDM_TX_SEL,
+ PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
+
+ /* In DSP/TDM mode, the LRCLK divider must be 256 */
+ div_lrck = 256;
+
+ /* Configure 1/256 duty cycle for LRCK */
+ snd_soc_update_bits(codec, PCM186X_PCM_CFG,
+ PCM186X_PCM_CFG_TDM_LRCK_MODE,
+ PCM186X_PCM_CFG_TDM_LRCK_MODE);
+ }
+
+ /* Only configure clock dividers in master mode. */
+ if (priv->is_master_mode) {
+ div_bck = priv->sysclk / (div_lrck * rate);
+
+ dev_dbg(codec->dev,
+ "%s() master_clk=%u div_bck=%u div_lrck=%u\n",
+ __func__, priv->sysclk, div_bck, div_lrck);
+
+ snd_soc_write(codec, PCM186X_BCK_DIV, div_bck - 1);
+ snd_soc_write(codec, PCM186X_LRK_DIV, div_lrck - 1);
+ }
+
+ return 0;
+}
+
+static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+ u8 clk_ctrl = 0;
+ u8 pcm_cfg = 0;
+
+ dev_dbg(codec->dev, "%s() format=0x%x\n", __func__, format);
+
+ /* set master/slave audio interface */
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ if (!priv->sysclk) {
+ dev_err(codec->dev, "operating in master mode requires sysclock to be configured\n");
+ return -EINVAL;
+ }
+ clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
+ priv->is_master_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ priv->is_master_mode = false;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI master/slave interface\n");
+ return -EINVAL;
+ }
+
+ /* set interface polarity */
+ switch (format & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ dev_err(codec->dev, "Inverted DAI clocks not supported\n");
+ return -EINVAL;
+ }
+
+ /* set interface format */
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ priv->tdm_offset += 1;
+ /* Fall through... DSP_A uses the same basic config as DSP_B
+ * except we need to shift the TDM output by one BCK cycle
+ */
+ case SND_SOC_DAIFMT_DSP_B:
+ priv->is_tdm_mode = true;
+ pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, PCM186X_CLK_CTRL,
+ PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
+
+ snd_soc_write(codec, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
+
+ snd_soc_update_bits(codec, PCM186X_PCM_CFG,
+ PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
+
+ return 0;
+}
+
+static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+ unsigned int first_slot, last_slot, tdm_offset;
+
+ dev_dbg(codec->dev,
+ "%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
+ __func__, tx_mask, rx_mask, slots, slot_width);
+
+ if (!tx_mask) {
+ dev_err(codec->dev, "tdm tx mask must not be 0\n");
+ return -EINVAL;
+ }
+
+ first_slot = __ffs(tx_mask);
+ last_slot = __fls(tx_mask);
+
+ if (last_slot - first_slot != hweight32(tx_mask) - 1) {
+ dev_err(codec->dev, "tdm tx mask must be contiguous\n");
+ return -EINVAL;
+ }
+
+ tdm_offset = first_slot * slot_width;
+
+ if (tdm_offset > 255) {
+ dev_err(codec->dev, "tdm tx slot selection out of bounds\n");
+ return -EINVAL;
+ }
+
+ priv->tdm_offset = tdm_offset;
+
+ return 0;
+}
+
+static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s() clk_id=%d freq=%u dir=%d\n",
+ __func__, clk_id, freq, dir);
+
+ priv->sysclk = freq;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops pcm186x_dai_ops = {
+ .set_sysclk = pcm186x_set_dai_sysclk,
+ .set_tdm_slot = pcm186x_set_tdm_slot,
+ .set_fmt = pcm186x_set_fmt,
+ .hw_params = pcm186x_hw_params,
+};
+
+static struct snd_soc_dai_driver pcm1863_dai = {
+ .name = "pcm1863-aif",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = PCM186X_RATES,
+ .formats = PCM186X_FORMATS,
+ },
+ .ops = &pcm186x_dai_ops,
+};
+
+static struct snd_soc_dai_driver pcm1865_dai = {
+ .name = "pcm1865-aif",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = PCM186X_RATES,
+ .formats = PCM186X_FORMATS,
+ },
+ .ops = &pcm186x_dai_ops,
+};
+
+static int pcm186x_power_on(struct snd_soc_codec *codec)
+{
+ struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(priv->regmap, false);
+ ret = regcache_sync(priv->regmap);
+ if (ret) {
+ dev_err(codec->dev, "Failed to restore cache\n");
+ regcache_cache_only(priv->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ return ret;
+ }
+
+ snd_soc_update_bits(codec, PCM186X_POWER_CTRL,
+ PCM186X_PWR_CTRL_PWRDN, 0);
+
+ return 0;
+}
+
+static int pcm186x_power_off(struct snd_soc_codec *codec)
+{
+ struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ snd_soc_update_bits(codec, PCM186X_POWER_CTRL,
+ PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
+
+ regcache_cache_only(priv->regmap, true);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int pcm186x_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
+ snd_soc_codec_get_bias_level(codec), level);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+ pcm186x_power_on(codec);
+ break;
+ case SND_SOC_BIAS_OFF:
+ pcm186x_power_off(codec);
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1863 = {
+ .set_bias_level = pcm186x_set_bias_level,
+
+ .component_driver = {
+ .controls = pcm1863_snd_controls,
+ .num_controls = ARRAY_SIZE(pcm1863_snd_controls),
+ .dapm_widgets = pcm1863_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm1863_dapm_widgets),
+ .dapm_routes = pcm1863_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm1863_dapm_routes),
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1865 = {
+ .set_bias_level = pcm186x_set_bias_level,
+ .suspend_bias_off = true,
+
+ .component_driver = {
+ .controls = pcm1865_snd_controls,
+ .num_controls = ARRAY_SIZE(pcm1865_snd_controls),
+ .dapm_widgets = pcm1865_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm1865_dapm_widgets),
+ .dapm_routes = pcm1865_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm1865_dapm_routes),
+ },
+};
+
+static bool pcm186x_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PCM186X_PAGE:
+ case PCM186X_DEVICE_STATUS:
+ case PCM186X_FSAMPLE_STATUS:
+ case PCM186X_DIV_STATUS:
+ case PCM186X_CLK_STATUS:
+ case PCM186X_SUPPLY_STATUS:
+ case PCM186X_MMAP_STAT_CTRL:
+ case PCM186X_MMAP_ADDRESS:
+ return true;
+ }
+
+ return false;
+}
+
+static const struct regmap_range_cfg pcm186x_range = {
+ .name = "Pages",
+ .range_max = PCM186X_MAX_REGISTER,
+ .selector_reg = PCM186X_PAGE,
+ .selector_mask = 0xff,
+ .window_len = PCM186X_PAGE_LEN,
+};
+
+const struct regmap_config pcm186x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .volatile_reg = pcm186x_volatile,
+
+ .ranges = &pcm186x_range,
+ .num_ranges = 1,
+
+ .max_register = PCM186X_MAX_REGISTER,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(pcm186x_regmap);
+
+int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
+ struct regmap *regmap)
+{
+ struct pcm186x_priv *priv;
+ int i, ret;
+
+ priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->regmap = regmap;
+
+ for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
+ priv->supplies[i].supply = pcm186x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset device registers for a consistent power-on like state */
+ ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
+ if (ret) {
+ dev_err(dev, "failed to write device: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed disable supplies: %d\n", ret);
+ return ret;
+ }
+
+ switch (type) {
+ case PCM1865:
+ case PCM1864:
+ ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1865,
+ &pcm1865_dai, 1);
+ break;
+ case PCM1863:
+ case PCM1862:
+ default:
+ ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1863,
+ &pcm1863_dai, 1);
+ }
+ if (ret) {
+ dev_err(dev, "failed to register CODEC: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcm186x_probe);
+
+int pcm186x_remove(struct device *dev)
+{
+ snd_soc_unregister_codec(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcm186x_remove);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x.h b/sound/soc/codecs/pcm186x.h
new file mode 100644
index 0000000..b630111
--- /dev/null
+++ b/sound/soc/codecs/pcm186x.h
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ * Andreas Dannenberg <dannenberg@ti.com>
+ * Andrew F. Davis <afd@ti.com>
+ */
+
+#ifndef _PCM186X_H_
+#define _PCM186X_H_
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+enum pcm186x_type {
+ PCM1862,
+ PCM1863,
+ PCM1864,
+ PCM1865,
+};
+
+#define PCM186X_RATES SNDRV_PCM_RATE_8000_192000
+#define PCM186X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define PCM186X_PAGE_LEN 0x0100
+#define PCM186X_PAGE_BASE(n) (PCM186X_PAGE_LEN * n)
+
+/* The page selection register address is the same on all pages */
+#define PCM186X_PAGE 0
+
+/* Register Definitions - Page 0 */
+#define PCM186X_PGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 1)
+#define PCM186X_PGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 2)
+#define PCM186X_PGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 3)
+#define PCM186X_PGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 4)
+#define PCM186X_PGA_CTRL (PCM186X_PAGE_BASE(0) + 5)
+#define PCM186X_ADC1_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 6)
+#define PCM186X_ADC1_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 7)
+#define PCM186X_ADC2_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 8)
+#define PCM186X_ADC2_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 9)
+#define PCM186X_AUXADC_INPUT_SEL (PCM186X_PAGE_BASE(0) + 10)
+#define PCM186X_PCM_CFG (PCM186X_PAGE_BASE(0) + 11)
+#define PCM186X_TDM_TX_SEL (PCM186X_PAGE_BASE(0) + 12)
+#define PCM186X_TDM_TX_OFFSET (PCM186X_PAGE_BASE(0) + 13)
+#define PCM186X_TDM_RX_OFFSET (PCM186X_PAGE_BASE(0) + 14)
+#define PCM186X_DPGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 15)
+#define PCM186X_GPIO1_0_CTRL (PCM186X_PAGE_BASE(0) + 16)
+#define PCM186X_GPIO3_2_CTRL (PCM186X_PAGE_BASE(0) + 17)
+#define PCM186X_GPIO1_0_DIR_CTRL (PCM186X_PAGE_BASE(0) + 18)
+#define PCM186X_GPIO3_2_DIR_CTRL (PCM186X_PAGE_BASE(0) + 19)
+#define PCM186X_GPIO_IN_OUT (PCM186X_PAGE_BASE(0) + 20)
+#define PCM186X_GPIO_PULL_CTRL (PCM186X_PAGE_BASE(0) + 21)
+#define PCM186X_DPGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 22)
+#define PCM186X_DPGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 23)
+#define PCM186X_DPGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 24)
+#define PCM186X_DPGA_GAIN_CTRL (PCM186X_PAGE_BASE(0) + 25)
+#define PCM186X_DPGA_MIC_CTRL (PCM186X_PAGE_BASE(0) + 26)
+#define PCM186X_DIN_RESAMP_CTRL (PCM186X_PAGE_BASE(0) + 27)
+#define PCM186X_CLK_CTRL (PCM186X_PAGE_BASE(0) + 32)
+#define PCM186X_DSP1_CLK_DIV (PCM186X_PAGE_BASE(0) + 33)
+#define PCM186X_DSP2_CLK_DIV (PCM186X_PAGE_BASE(0) + 34)
+#define PCM186X_ADC_CLK_DIV (PCM186X_PAGE_BASE(0) + 35)
+#define PCM186X_PLL_SCK_DIV (PCM186X_PAGE_BASE(0) + 37)
+#define PCM186X_BCK_DIV (PCM186X_PAGE_BASE(0) + 38)
+#define PCM186X_LRK_DIV (PCM186X_PAGE_BASE(0) + 39)
+#define PCM186X_PLL_CTRL (PCM186X_PAGE_BASE(0) + 40)
+#define PCM186X_PLL_P_DIV (PCM186X_PAGE_BASE(0) + 41)
+#define PCM186X_PLL_R_DIV (PCM186X_PAGE_BASE(0) + 42)
+#define PCM186X_PLL_J_DIV (PCM186X_PAGE_BASE(0) + 43)
+#define PCM186X_PLL_D_DIV_LSB (PCM186X_PAGE_BASE(0) + 44)
+#define PCM186X_PLL_D_DIV_MSB (PCM186X_PAGE_BASE(0) + 45)
+#define PCM186X_SIGDET_MODE (PCM186X_PAGE_BASE(0) + 48)
+#define PCM186X_SIGDET_MASK (PCM186X_PAGE_BASE(0) + 49)
+#define PCM186X_SIGDET_STAT (PCM186X_PAGE_BASE(0) + 50)
+#define PCM186X_SIGDET_LOSS_TIME (PCM186X_PAGE_BASE(0) + 52)
+#define PCM186X_SIGDET_SCAN_TIME (PCM186X_PAGE_BASE(0) + 53)
+#define PCM186X_SIGDET_INT_INTVL (PCM186X_PAGE_BASE(0) + 54)
+#define PCM186X_SIGDET_DC_REF_CH1_L (PCM186X_PAGE_BASE(0) + 64)
+#define PCM186X_SIGDET_DC_DIFF_CH1_L (PCM186X_PAGE_BASE(0) + 65)
+#define PCM186X_SIGDET_DC_LEV_CH1_L (PCM186X_PAGE_BASE(0) + 66)
+#define PCM186X_SIGDET_DC_REF_CH1_R (PCM186X_PAGE_BASE(0) + 67)
+#define PCM186X_SIGDET_DC_DIFF_CH1_R (PCM186X_PAGE_BASE(0) + 68)
+#define PCM186X_SIGDET_DC_LEV_CH1_R (PCM186X_PAGE_BASE(0) + 69)
+#define PCM186X_SIGDET_DC_REF_CH2_L (PCM186X_PAGE_BASE(0) + 70)
+#define PCM186X_SIGDET_DC_DIFF_CH2_L (PCM186X_PAGE_BASE(0) + 71)
+#define PCM186X_SIGDET_DC_LEV_CH2_L (PCM186X_PAGE_BASE(0) + 72)
+#define PCM186X_SIGDET_DC_REF_CH2_R (PCM186X_PAGE_BASE(0) + 73)
+#define PCM186X_SIGDET_DC_DIFF_CH2_R (PCM186X_PAGE_BASE(0) + 74)
+#define PCM186X_SIGDET_DC_LEV_CH2_R (PCM186X_PAGE_BASE(0) + 75)
+#define PCM186X_SIGDET_DC_REF_CH3_L (PCM186X_PAGE_BASE(0) + 76)
+#define PCM186X_SIGDET_DC_DIFF_CH3_L (PCM186X_PAGE_BASE(0) + 77)
+#define PCM186X_SIGDET_DC_LEV_CH3_L (PCM186X_PAGE_BASE(0) + 78)
+#define PCM186X_SIGDET_DC_REF_CH3_R (PCM186X_PAGE_BASE(0) + 79)
+#define PCM186X_SIGDET_DC_DIFF_CH3_R (PCM186X_PAGE_BASE(0) + 80)
+#define PCM186X_SIGDET_DC_LEV_CH3_R (PCM186X_PAGE_BASE(0) + 81)
+#define PCM186X_SIGDET_DC_REF_CH4_L (PCM186X_PAGE_BASE(0) + 82)
+#define PCM186X_SIGDET_DC_DIFF_CH4_L (PCM186X_PAGE_BASE(0) + 83)
+#define PCM186X_SIGDET_DC_LEV_CH4_L (PCM186X_PAGE_BASE(0) + 84)
+#define PCM186X_SIGDET_DC_REF_CH4_R (PCM186X_PAGE_BASE(0) + 85)
+#define PCM186X_SIGDET_DC_DIFF_CH4_R (PCM186X_PAGE_BASE(0) + 86)
+#define PCM186X_SIGDET_DC_LEV_CH4_R (PCM186X_PAGE_BASE(0) + 87)
+#define PCM186X_AUXADC_DATA_CTRL (PCM186X_PAGE_BASE(0) + 88)
+#define PCM186X_AUXADC_DATA_LSB (PCM186X_PAGE_BASE(0) + 89)
+#define PCM186X_AUXADC_DATA_MSB (PCM186X_PAGE_BASE(0) + 90)
+#define PCM186X_INT_ENABLE (PCM186X_PAGE_BASE(0) + 96)
+#define PCM186X_INT_FLAG (PCM186X_PAGE_BASE(0) + 97)
+#define PCM186X_INT_POL_WIDTH (PCM186X_PAGE_BASE(0) + 98)
+#define PCM186X_POWER_CTRL (PCM186X_PAGE_BASE(0) + 112)
+#define PCM186X_FILTER_MUTE_CTRL (PCM186X_PAGE_BASE(0) + 113)
+#define PCM186X_DEVICE_STATUS (PCM186X_PAGE_BASE(0) + 114)
+#define PCM186X_FSAMPLE_STATUS (PCM186X_PAGE_BASE(0) + 115)
+#define PCM186X_DIV_STATUS (PCM186X_PAGE_BASE(0) + 116)
+#define PCM186X_CLK_STATUS (PCM186X_PAGE_BASE(0) + 117)
+#define PCM186X_SUPPLY_STATUS (PCM186X_PAGE_BASE(0) + 120)
+
+/* Register Definitions - Page 1 */
+#define PCM186X_MMAP_STAT_CTRL (PCM186X_PAGE_BASE(1) + 1)
+#define PCM186X_MMAP_ADDRESS (PCM186X_PAGE_BASE(1) + 2)
+#define PCM186X_MEM_WDATA0 (PCM186X_PAGE_BASE(1) + 4)
+#define PCM186X_MEM_WDATA1 (PCM186X_PAGE_BASE(1) + 5)
+#define PCM186X_MEM_WDATA2 (PCM186X_PAGE_BASE(1) + 6)
+#define PCM186X_MEM_WDATA3 (PCM186X_PAGE_BASE(1) + 7)
+#define PCM186X_MEM_RDATA0 (PCM186X_PAGE_BASE(1) + 8)
+#define PCM186X_MEM_RDATA1 (PCM186X_PAGE_BASE(1) + 9)
+#define PCM186X_MEM_RDATA2 (PCM186X_PAGE_BASE(1) + 10)
+#define PCM186X_MEM_RDATA3 (PCM186X_PAGE_BASE(1) + 11)
+
+/* Register Definitions - Page 3 */
+#define PCM186X_OSC_PWR_DOWN_CTRL (PCM186X_PAGE_BASE(3) + 18)
+#define PCM186X_MIC_BIAS_CTRL (PCM186X_PAGE_BASE(3) + 21)
+
+/* Register Definitions - Page 253 */
+#define PCM186X_CURR_TRIM_CTRL (PCM186X_PAGE_BASE(253) + 20)
+
+#define PCM186X_MAX_REGISTER PCM186X_CURR_TRIM_CTRL
+
+/* PCM186X_PAGE */
+#define PCM186X_RESET 0xff
+
+/* PCM186X_ADCX_INPUT_SEL_X */
+#define PCM186X_ADC_INPUT_SEL_POL BIT(7)
+#define PCM186X_ADC_INPUT_SEL_MASK GENMASK(5, 0)
+
+/* PCM186X_PCM_CFG */
+#define PCM186X_PCM_CFG_RX_WLEN_MASK GENMASK(7, 6)
+#define PCM186X_PCM_CFG_RX_WLEN_SHIFT 6
+#define PCM186X_PCM_CFG_RX_WLEN_32 0x00
+#define PCM186X_PCM_CFG_RX_WLEN_24 0x01
+#define PCM186X_PCM_CFG_RX_WLEN_20 0x02
+#define PCM186X_PCM_CFG_RX_WLEN_16 0x03
+#define PCM186X_PCM_CFG_TDM_LRCK_MODE BIT(4)
+#define PCM186X_PCM_CFG_TX_WLEN_MASK GENMASK(3, 2)
+#define PCM186X_PCM_CFG_TX_WLEN_SHIFT 2
+#define PCM186X_PCM_CFG_TX_WLEN_32 0x00
+#define PCM186X_PCM_CFG_TX_WLEN_24 0x01
+#define PCM186X_PCM_CFG_TX_WLEN_20 0x02
+#define PCM186X_PCM_CFG_TX_WLEN_16 0x03
+#define PCM186X_PCM_CFG_FMT_MASK GENMASK(1, 0)
+#define PCM186X_PCM_CFG_FMT_SHIFT 0
+#define PCM186X_PCM_CFG_FMT_I2S 0x00
+#define PCM186X_PCM_CFG_FMT_LEFTJ 0x01
+#define PCM186X_PCM_CFG_FMT_RIGHTJ 0x02
+#define PCM186X_PCM_CFG_FMT_TDM 0x03
+
+/* PCM186X_TDM_TX_SEL */
+#define PCM186X_TDM_TX_SEL_2CH 0x00
+#define PCM186X_TDM_TX_SEL_4CH 0x01
+#define PCM186X_TDM_TX_SEL_6CH 0x02
+#define PCM186X_TDM_TX_SEL_MASK 0x03
+
+/* PCM186X_CLK_CTRL */
+#define PCM186X_CLK_CTRL_SCK_XI_SEL1 BIT(7)
+#define PCM186X_CLK_CTRL_SCK_XI_SEL0 BIT(6)
+#define PCM186X_CLK_CTRL_SCK_SRC_PLL BIT(5)
+#define PCM186X_CLK_CTRL_MST_MODE BIT(4)
+#define PCM186X_CLK_CTRL_ADC_SRC_PLL BIT(3)
+#define PCM186X_CLK_CTRL_DSP2_SRC_PLL BIT(2)
+#define PCM186X_CLK_CTRL_DSP1_SRC_PLL BIT(1)
+#define PCM186X_CLK_CTRL_CLKDET_EN BIT(0)
+
+/* PCM186X_PLL_CTRL */
+#define PCM186X_PLL_CTRL_LOCK BIT(4)
+#define PCM186X_PLL_CTRL_REF_SEL BIT(1)
+#define PCM186X_PLL_CTRL_EN BIT(0)
+
+/* PCM186X_POWER_CTRL */
+#define PCM186X_PWR_CTRL_PWRDN BIT(2)
+#define PCM186X_PWR_CTRL_SLEEP BIT(1)
+#define PCM186X_PWR_CTRL_STBY BIT(0)
+
+/* PCM186X_CLK_STATUS */
+#define PCM186X_CLK_STATUS_LRCKHLT BIT(6)
+#define PCM186X_CLK_STATUS_BCKHLT BIT(5)
+#define PCM186X_CLK_STATUS_SCKHLT BIT(4)
+#define PCM186X_CLK_STATUS_LRCKERR BIT(2)
+#define PCM186X_CLK_STATUS_BCKERR BIT(1)
+#define PCM186X_CLK_STATUS_SCKERR BIT(0)
+
+/* PCM186X_SUPPLY_STATUS */
+#define PCM186X_SUPPLY_STATUS_DVDD BIT(2)
+#define PCM186X_SUPPLY_STATUS_AVDD BIT(1)
+#define PCM186X_SUPPLY_STATUS_LDO BIT(0)
+
+/* PCM186X_MMAP_STAT_CTRL */
+#define PCM186X_MMAP_STAT_DONE BIT(4)
+#define PCM186X_MMAP_STAT_BUSY BIT(2)
+#define PCM186X_MMAP_STAT_R_REQ BIT(1)
+#define PCM186X_MMAP_STAT_W_REQ BIT(0)
+
+extern const struct regmap_config pcm186x_regmap;
+
+int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
+ struct regmap *regmap);
+int pcm186x_remove(struct device *dev);
+
+#endif /* _PCM186X_H_ */
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 25c6351..7cdd2dc 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -70,3 +70,7 @@ static struct spi_driver pcm512x_spi_driver = {
};
module_spi_driver(pcm512x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c
index 974a904..7ef3b54 100644
--- a/sound/soc/codecs/rl6231.c
+++ b/sound/soc/codecs/rl6231.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/regmap.h>
+#include <linux/gcd.h>
#include "rl6231.h"
/**
@@ -106,6 +107,25 @@ static const struct pll_calc_map pll_preset_table[] = {
{19200000, 24576000, 3, 30, 3, false},
};
+static unsigned int find_best_div(unsigned int in,
+ unsigned int max, unsigned int div)
+{
+ unsigned int d;
+
+ if (in <= max)
+ return 1;
+
+ d = in / max;
+ if (in % max)
+ d++;
+
+ while (div % d != 0)
+ d++;
+
+
+ return d;
+}
+
/**
* rl6231_pll_calc - Calcualte PLL M/N/K code.
* @freq_in: external clock provided to codec.
@@ -120,9 +140,11 @@ int rl6231_pll_calc(const unsigned int freq_in,
const unsigned int freq_out, struct rl6231_pll_code *pll_code)
{
int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
- int i, k, red, n_t, pll_out, in_t, out_t;
- int n = 0, m = 0, m_t = 0;
- int red_t = abs(freq_out - freq_in);
+ int i, k, n_t;
+ int k_t, min_k, max_k, n = 0, m = 0, m_t = 0;
+ unsigned int red, pll_out, in_t, out_t, div, div_t;
+ unsigned int red_t = abs(freq_out - freq_in);
+ unsigned int f_in, f_out, f_max;
bool bypass = false;
if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
@@ -140,39 +162,52 @@ int rl6231_pll_calc(const unsigned int freq_in,
}
}
- k = 100000000 / freq_out - 2;
- if (k > RL6231_PLL_K_MAX)
- k = RL6231_PLL_K_MAX;
- for (n_t = 0; n_t <= max_n; n_t++) {
- in_t = freq_in / (k + 2);
- pll_out = freq_out / (n_t + 2);
- if (in_t < 0)
- continue;
- if (in_t == pll_out) {
- bypass = true;
- n = n_t;
- goto code_find;
- }
- red = abs(in_t - pll_out);
- if (red < red_t) {
- bypass = true;
- n = n_t;
- m = m_t;
- if (red == 0)
+ min_k = 80000000 / freq_out - 2;
+ max_k = 150000000 / freq_out - 2;
+ if (max_k > RL6231_PLL_K_MAX)
+ max_k = RL6231_PLL_K_MAX;
+ if (min_k > RL6231_PLL_K_MAX)
+ min_k = max_k = RL6231_PLL_K_MAX;
+ div_t = gcd(freq_in, freq_out);
+ f_max = 0xffffffff / RL6231_PLL_N_MAX;
+ div = find_best_div(freq_in, f_max, div_t);
+ f_in = freq_in / div;
+ f_out = freq_out / div;
+ k = min_k;
+ for (k_t = min_k; k_t <= max_k; k_t++) {
+ for (n_t = 0; n_t <= max_n; n_t++) {
+ in_t = f_in * (n_t + 2);
+ pll_out = f_out * (k_t + 2);
+ if (in_t == pll_out) {
+ bypass = true;
+ n = n_t;
+ k = k_t;
goto code_find;
- red_t = red;
- }
- for (m_t = 0; m_t <= max_m; m_t++) {
- out_t = in_t / (m_t + 2);
- red = abs(out_t - pll_out);
+ }
+ out_t = in_t / (k_t + 2);
+ red = abs(f_out - out_t);
if (red < red_t) {
- bypass = false;
+ bypass = true;
n = n_t;
- m = m_t;
+ m = 0;
+ k = k_t;
if (red == 0)
goto code_find;
red_t = red;
}
+ for (m_t = 0; m_t <= max_m; m_t++) {
+ out_t = in_t / ((m_t + 2) * (k_t + 2));
+ red = abs(f_out - out_t);
+ if (red < red_t) {
+ bypass = false;
+ n = n_t;
+ m = m_t;
+ k = k_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ }
}
}
pr_debug("Only get approximation about PLL\n");
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 2df91db..2144edc 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -289,6 +289,8 @@ static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
dev_err(&rt5514_spi->dev,
"%s Failed to reguest IRQ: %d\n", __func__,
ret);
+ else
+ device_init_wakeup(rt5514_dsp->dev, true);
}
return 0;
@@ -379,6 +381,7 @@ int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len)
return true;
}
+EXPORT_SYMBOL_GPL(rt5514_spi_burst_read);
/**
* rt5514_spi_burst_write - Write data to SPI by rt5514 address.
@@ -456,8 +459,6 @@ static int rt5514_spi_probe(struct spi_device *spi)
return ret;
}
- device_init_wakeup(&spi->dev, true);
-
return 0;
}
@@ -482,10 +483,13 @@ static int __maybe_unused rt5514_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(irq);
- if (rt5514_dsp->substream) {
- rt5514_spi_burst_read(RT5514_IRQ_CTRL, (u8 *)&buf, sizeof(buf));
- if (buf[0] & RT5514_IRQ_STATUS_BIT)
- rt5514_schedule_copy(rt5514_dsp);
+ if (rt5514_dsp) {
+ if (rt5514_dsp->substream) {
+ rt5514_spi_burst_read(RT5514_IRQ_CTRL, (u8 *)&buf,
+ sizeof(buf));
+ if (buf[0] & RT5514_IRQ_STATUS_BIT)
+ rt5514_schedule_copy(rt5514_dsp);
+ }
}
return 0;
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 2a5b5d7..198df01 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -295,6 +295,33 @@ static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static int rt5514_calibration(struct rt5514_priv *rt5514, bool on)
+{
+ if (on) {
+ regmap_write(rt5514->regmap, RT5514_ANA_CTRL_PLL3, 0x0000000a);
+ regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, 0xf,
+ 0xa);
+ regmap_update_bits(rt5514->regmap, RT5514_PWR_ANA1, 0x301,
+ 0x301);
+ regmap_write(rt5514->regmap, RT5514_PLL3_CALIB_CTRL4,
+ 0x80000000 | rt5514->pll3_cal_value);
+ regmap_write(rt5514->regmap, RT5514_PLL3_CALIB_CTRL1,
+ 0x8bb80800);
+ regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5,
+ 0xc0000000, 0x80000000);
+ regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5,
+ 0xc0000000, 0xc0000000);
+ } else {
+ regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5,
+ 0xc0000000, 0x40000000);
+ regmap_update_bits(rt5514->regmap, RT5514_PWR_ANA1, 0x301, 0);
+ regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, 0xf,
+ 0x4);
+ }
+
+ return 0;
+}
+
static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -302,6 +329,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
struct snd_soc_codec *codec = rt5514->codec;
const struct firmware *fw = NULL;
+ u8 buf[8];
if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled)
return 0;
@@ -310,6 +338,35 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
rt5514->dsp_enabled = ucontrol->value.integer.value[0];
if (rt5514->dsp_enabled) {
+ if (rt5514->pdata.dsp_calib_clk_name &&
+ !IS_ERR(rt5514->dsp_calib_clk)) {
+ if (clk_set_rate(rt5514->dsp_calib_clk,
+ rt5514->pdata.dsp_calib_clk_rate))
+ dev_err(codec->dev,
+ "Can't set rate for mclk");
+
+ if (clk_prepare_enable(rt5514->dsp_calib_clk))
+ dev_err(codec->dev,
+ "Can't enable dsp_calib_clk");
+
+ rt5514_calibration(rt5514, true);
+
+ msleep(20);
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+ rt5514_spi_burst_read(RT5514_PLL3_CALIB_CTRL6 |
+ RT5514_DSP_MAPPING,
+ (u8 *)&buf, sizeof(buf));
+#else
+ dev_err(codec->dev, "There is no SPI driver for"
+ " loading the firmware\n");
+#endif
+ rt5514->pll3_cal_value = buf[0] | buf[1] << 8 |
+ buf[2] << 16 | buf[3] << 24;
+
+ rt5514_calibration(rt5514, false);
+ clk_disable_unprepare(rt5514->dsp_calib_clk);
+ }
+
rt5514_enable_dsp_prepare(rt5514);
request_firmware(&fw, RT5514_FIRMWARE1, codec->dev);
@@ -341,6 +398,20 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
/* DSP run */
regmap_write(rt5514->i2c_regmap, 0x18002f00,
0x00055148);
+
+ if (rt5514->pdata.dsp_calib_clk_name &&
+ !IS_ERR(rt5514->dsp_calib_clk)) {
+ msleep(20);
+
+ regmap_write(rt5514->i2c_regmap, 0x1800211c,
+ rt5514->pll3_cal_value);
+ regmap_write(rt5514->i2c_regmap, 0x18002124,
+ 0x00220012);
+ regmap_write(rt5514->i2c_regmap, 0x18002124,
+ 0x80220042);
+ regmap_write(rt5514->i2c_regmap, 0x18002124,
+ 0xe0220042);
+ }
} else {
regmap_multi_reg_write(rt5514->i2c_regmap,
rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch));
@@ -496,7 +567,7 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_SUPPLY_S("DMIC CLK", 1, SND_SOC_NOPM, 0, 0,
rt5514_set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY("ADC CLK", RT5514_CLK_CTRL1,
@@ -1024,12 +1095,22 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec,
static int rt5514_probe(struct snd_soc_codec *codec)
{
struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ struct platform_device *pdev = container_of(codec->dev,
+ struct platform_device, dev);
rt5514->mclk = devm_clk_get(codec->dev, "mclk");
if (PTR_ERR(rt5514->mclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
+ if (rt5514->pdata.dsp_calib_clk_name) {
+ rt5514->dsp_calib_clk = devm_clk_get(&pdev->dev,
+ rt5514->pdata.dsp_calib_clk_name);
+ if (PTR_ERR(rt5514->dsp_calib_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ }
+
rt5514->codec = codec;
+ rt5514->pll3_cal_value = 0x0078b000;
return 0;
}
@@ -1147,6 +1228,10 @@ static int rt5514_parse_dp(struct rt5514_priv *rt5514, struct device *dev)
{
device_property_read_u32(dev, "realtek,dmic-init-delay-ms",
&rt5514->pdata.dmic_init_delay);
+ device_property_read_string(dev, "realtek,dsp-calib-clk-name",
+ &rt5514->pdata.dsp_calib_clk_name);
+ device_property_read_u32(dev, "realtek,dsp-calib-clk-rate",
+ &rt5514->pdata.dsp_calib_clk_rate);
return 0;
}
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index 2dc40e6..f0f3400 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -34,7 +34,9 @@
#define RT5514_CLK_CTRL1 0x2104
#define RT5514_CLK_CTRL2 0x2108
#define RT5514_PLL3_CALIB_CTRL1 0x2110
+#define RT5514_PLL3_CALIB_CTRL4 0x2120
#define RT5514_PLL3_CALIB_CTRL5 0x2124
+#define RT5514_PLL3_CALIB_CTRL6 0x2128
#define RT5514_DELAY_BUF_CTRL1 0x2140
#define RT5514_DELAY_BUF_CTRL3 0x2148
#define RT5514_ASRC_IN_CTRL1 0x2180
@@ -272,7 +274,7 @@ struct rt5514_priv {
struct rt5514_platform_data pdata;
struct snd_soc_codec *codec;
struct regmap *i2c_regmap, *regmap;
- struct clk *mclk;
+ struct clk *mclk, *dsp_calib_clk;
int sysclk;
int sysclk_src;
int lrck;
@@ -281,6 +283,7 @@ struct rt5514_priv {
int pll_in;
int pll_out;
int dsp_enabled;
+ unsigned int pll3_cal_value;
};
#endif /* __RT5514_H__ */
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index f020d2d..8f140c8 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -1943,6 +1943,56 @@ static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+ RT5645_MICBIAS1_POW_CTRL_SEL_MASK,
+ RT5645_MICBIAS1_POW_CTRL_SEL_M);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+ RT5645_MICBIAS1_POW_CTRL_SEL_MASK,
+ RT5645_MICBIAS1_POW_CTRL_SEL_A);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5645_set_micbias2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+ RT5645_MICBIAS2_POW_CTRL_SEL_MASK,
+ RT5645_MICBIAS2_POW_CTRL_SEL_M);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+ RT5645_MICBIAS2_POW_CTRL_SEL_MASK,
+ RT5645_MICBIAS2_POW_CTRL_SEL_A);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER,
RT5645_PWR_LDO2_BIT, 0, NULL, 0),
@@ -1980,10 +2030,12 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
/* Input Side */
/* micbias */
- SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
- RT5645_PWR_MB1_BIT, 0),
- SND_SOC_DAPM_MICBIAS("micbias2", RT5645_PWR_ANLG2,
- RT5645_PWR_MB2_BIT, 0),
+ SND_SOC_DAPM_SUPPLY("micbias1", RT5645_PWR_ANLG2,
+ RT5645_PWR_MB1_BIT, 0, rt5645_set_micbias1_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("micbias2", RT5645_PWR_ANLG2,
+ RT5645_PWR_MB2_BIT, 0, rt5645_set_micbias2_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* Input Lines */
SND_SOC_DAPM_INPUT("DMIC L1"),
SND_SOC_DAPM_INPUT("DMIC R1"),
@@ -3394,6 +3446,9 @@ static int rt5645_probe(struct snd_soc_codec *codec)
snd_soc_dapm_sync(dapm);
}
+ if (rt5645->pdata.long_name)
+ codec->component.card->long_name = rt5645->pdata.long_name;
+
rt5645->eq_param = devm_kzalloc(codec->dev,
RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s), GFP_KERNEL);
@@ -3570,63 +3625,74 @@ static const struct acpi_device_id rt5645_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
#endif
-static const struct rt5645_platform_data general_platform_data = {
+static const struct rt5645_platform_data intel_braswell_platform_data = {
.dmic1_data_pin = RT5645_DMIC1_DISABLE,
.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
.jd_mode = 3,
};
-static const struct dmi_system_id dmi_platform_intel_braswell[] = {
+static const struct rt5645_platform_data buddy_platform_data = {
+ .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
+ .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+ .jd_mode = 3,
+ .level_trigger_irq = true,
+};
+
+static const struct rt5645_platform_data gpd_win_platform_data = {
+ .jd_mode = 3,
+ .inv_jd1_1 = true,
+ .long_name = "gpd-win-pocket-rt5645",
+ /* The GPD pocket has a diff. mic, for the win this does not matter. */
+ .in2_diff = true,
+};
+
+static const struct rt5645_platform_data asus_t100ha_platform_data = {
+ .dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
+ .dmic2_data_pin = RT5645_DMIC2_DISABLE,
+ .jd_mode = 3,
+ .inv_jd1_1 = true,
+};
+
+static const struct rt5645_platform_data jd_mode3_platform_data = {
+ .jd_mode = 3,
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+ {
+ .ident = "Chrome Buddy",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
+ },
+ .driver_data = (void *)&buddy_platform_data,
+ },
{
.ident = "Intel Strago",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
},
+ .driver_data = (void *)&intel_braswell_platform_data,
},
{
.ident = "Google Chrome",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
},
+ .driver_data = (void *)&intel_braswell_platform_data,
},
{
.ident = "Google Setzer",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
},
+ .driver_data = (void *)&intel_braswell_platform_data,
},
{
.ident = "Microsoft Surface 3",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
},
+ .driver_data = (void *)&intel_braswell_platform_data,
},
- { }
-};
-
-static const struct rt5645_platform_data buddy_platform_data = {
- .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
- .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
- .jd_mode = 3,
- .level_trigger_irq = true,
-};
-
-static const struct dmi_system_id dmi_platform_intel_broadwell[] = {
- {
- .ident = "Chrome Buddy",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
- },
- },
- { }
-};
-
-static const struct rt5645_platform_data gpd_win_platform_data = {
- .jd_mode = 3,
- .inv_jd1_1 = true,
-};
-
-static const struct dmi_system_id dmi_platform_gpd_win[] = {
{
/*
* Match for the GPDwin which unfortunately uses somewhat
@@ -3637,46 +3703,38 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = {
* the same default product_name. Also the GPDwin is the
* only device to have both board_ and product_name not set.
*/
- .ident = "GPD Win",
+ .ident = "GPD Win / Pocket",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "Default string"),
DMI_MATCH(DMI_BOARD_SERIAL, "Default string"),
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
},
+ .driver_data = (void *)&gpd_win_platform_data,
},
- {}
-};
-
-static const struct rt5645_platform_data general_platform_data2 = {
- .dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
- .dmic2_data_pin = RT5645_DMIC2_DISABLE,
- .jd_mode = 3,
- .inv_jd1_1 = true,
-};
-
-static const struct dmi_system_id dmi_platform_asus_t100ha[] = {
{
.ident = "ASUS T100HAN",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
},
+ .driver_data = (void *)&asus_t100ha_platform_data,
},
- { }
-};
-
-static const struct rt5645_platform_data minix_z83_4_platform_data = {
- .jd_mode = 3,
-};
-
-static const struct dmi_system_id dmi_platform_minix_z83_4[] = {
{
.ident = "MINIX Z83-4",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"),
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
},
+ .driver_data = (void *)&jd_mode3_platform_data,
+ },
+ {
+ .ident = "Teclast X80 Pro",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X80 Pro"),
+ },
+ .driver_data = (void *)&jd_mode3_platform_data,
},
{ }
};
@@ -3684,9 +3742,9 @@ static const struct dmi_system_id dmi_platform_minix_z83_4[] = {
static bool rt5645_check_dp(struct device *dev)
{
if (device_property_present(dev, "realtek,in2-differential") ||
- device_property_present(dev, "realtek,dmic1-data-pin") ||
- device_property_present(dev, "realtek,dmic2-data-pin") ||
- device_property_present(dev, "realtek,jd-mode"))
+ device_property_present(dev, "realtek,dmic1-data-pin") ||
+ device_property_present(dev, "realtek,dmic2-data-pin") ||
+ device_property_present(dev, "realtek,jd-mode"))
return true;
return false;
@@ -3710,6 +3768,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ const struct dmi_system_id *dmi_data;
struct rt5645_priv *rt5645;
int ret, i;
unsigned int val;
@@ -3723,20 +3782,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
rt5645->i2c = i2c;
i2c_set_clientdata(i2c, rt5645);
+ dmi_data = dmi_first_match(dmi_platform_data);
+ if (dmi_data) {
+ dev_info(&i2c->dev, "Detected %s platform\n", dmi_data->ident);
+ pdata = dmi_data->driver_data;
+ }
+
if (pdata)
rt5645->pdata = *pdata;
- else if (dmi_check_system(dmi_platform_intel_broadwell))
- rt5645->pdata = buddy_platform_data;
else if (rt5645_check_dp(&i2c->dev))
rt5645_parse_dt(rt5645, &i2c->dev);
- else if (dmi_check_system(dmi_platform_intel_braswell))
- rt5645->pdata = general_platform_data;
- else if (dmi_check_system(dmi_platform_gpd_win))
- rt5645->pdata = gpd_win_platform_data;
- else if (dmi_check_system(dmi_platform_asus_t100ha))
- rt5645->pdata = general_platform_data2;
- else if (dmi_check_system(dmi_platform_minix_z83_4))
- rt5645->pdata = minix_z83_4_platform_data;
+ else
+ rt5645->pdata = jd_mode3_platform_data;
if (quirk != -1) {
rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
@@ -3823,6 +3880,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
regmap_read(regmap, RT5645_VENDOR_ID, &val);
rt5645->v_id = val & 0xff;
+ regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080);
+
ret = regmap_register_patch(rt5645->regmap, init_list,
ARRAY_SIZE(init_list));
if (ret != 0)
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index cfc5f97..940325b 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -2117,6 +2117,12 @@ enum {
#define RT5645_RXDC_SRC_STO (0x0 << 7)
#define RT5645_RXDC_SRC_MONO (0x1 << 7)
#define RT5645_RXDC_SRC_SFT (7)
+#define RT5645_MICBIAS1_POW_CTRL_SEL_MASK (0x1 << 5)
+#define RT5645_MICBIAS1_POW_CTRL_SEL_A (0x0 << 5)
+#define RT5645_MICBIAS1_POW_CTRL_SEL_M (0x1 << 5)
+#define RT5645_MICBIAS2_POW_CTRL_SEL_MASK (0x1 << 4)
+#define RT5645_MICBIAS2_POW_CTRL_SEL_A (0x0 << 4)
+#define RT5645_MICBIAS2_POW_CTRL_SEL_M (0x1 << 4)
#define RT5645_RXDP2_SEL_MASK (0x1 << 3)
#define RT5645_RXDP2_SEL_IF2 (0x0 << 3)
#define RT5645_RXDP2_SEL_ADC (0x1 << 3)
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index b036c9d..d329bf7 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -1560,6 +1560,10 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
snd_soc_update_bits(codec, RT5663_IRQ_1,
RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
+ snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+ RT5663_EM_JD_MASK, RT5663_EM_JD_RST);
+ snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+ RT5663_EM_JD_MASK, RT5663_EM_JD_NOR);
while (true) {
regmap_read(rt5663->regmap, RT5663_INT_ST_2, &val);
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
index c5a9b69..03adc80 100644
--- a/sound/soc/codecs/rt5663.h
+++ b/sound/soc/codecs/rt5663.h
@@ -1029,6 +1029,10 @@
#define RT5663_POL_EXT_JD_SHIFT 10
#define RT5663_POL_EXT_JD_EN (0x1 << 10)
#define RT5663_POL_EXT_JD_DIS (0x0 << 10)
+#define RT5663_EM_JD_MASK (0x1 << 7)
+#define RT5663_EM_JD_SHIFT 7
+#define RT5663_EM_JD_NOR (0x1 << 7)
+#define RT5663_EM_JD_RST (0x0 << 7)
/* DACREF LDO Control (0x0112)*/
#define RT5663_PWR_LDO_DACREFL_MASK (0x1 << 9)
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index f2bb4fe..633cdcf 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1332,10 +1332,13 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
sgtl5000->mclk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(sgtl5000->mclk)) {
ret = PTR_ERR(sgtl5000->mclk);
- dev_err(&client->dev, "Failed to get mclock: %d\n", ret);
/* Defer the probe to see if the clk will be provided later */
if (ret == -ENOENT)
ret = -EPROBE_DEFER;
+
+ if (ret != -EPROBE_DEFER)
+ dev_err(&client->dev, "Failed to get mclock: %d\n",
+ ret);
goto disable_regs;
}
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 354dc0d..7b91ee2 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -231,14 +231,17 @@ static struct snd_soc_dai_driver si476x_dai = {
.ops = &si476x_dai_ops,
};
-static struct regmap *si476x_get_regmap(struct device *dev)
+static int si476x_probe(struct snd_soc_component *component)
{
- return dev_get_regmap(dev->parent, NULL);
+ snd_soc_component_init_regmap(component,
+ dev_get_regmap(component->dev->parent, NULL));
+
+ return 0;
}
static const struct snd_soc_codec_driver soc_codec_dev_si476x = {
- .get_regmap = si476x_get_regmap,
.component_driver = {
+ .probe = si476x_probe,
.dapm_widgets = si476x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
.dapm_routes = si476x_dapm_routes,
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
deleted file mode 100644
index 887923e..0000000
--- a/sound/soc/codecs/sn95031.c
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * sn95031.c - TI sn95031 Codec driver
- *
- * Copyright (C) 2010 Intel Corp
- * Author: Vinod Koul <vinod.koul@intel.com>
- * Author: Harsha Priya <priya.harsha@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include <asm/intel_scu_ipc.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <sound/jack.h>
-#include "sn95031.h"
-
-#define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100)
-#define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-
-/* adc helper functions */
-
-/* enables mic bias voltage */
-static void sn95031_enable_mic_bias(struct snd_soc_codec *codec)
-{
- snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0));
- snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2));
-}
-
-/* Enable/Disable the ADC depending on the argument */
-static void configure_adc(struct snd_soc_codec *sn95031_codec, int val)
-{
- int value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
-
- if (val) {
- /* Enable and start the ADC */
- value |= (SN95031_ADC_ENBL | SN95031_ADC_START);
- value &= (~SN95031_ADC_NO_LOOP);
- } else {
- /* Just stop the ADC */
- value &= (~SN95031_ADC_START);
- }
- snd_soc_write(sn95031_codec, SN95031_ADC1CNTL1, value);
-}
-
-/*
- * finds an empty channel for conversion
- * If the ADC is not enabled then start using 0th channel
- * itself. Otherwise find an empty channel by looking for a
- * channel in which the stopbit is set to 1. returns the index
- * of the first free channel if succeeds or an error code.
- *
- * Context: can sleep
- *
- */
-static int find_free_channel(struct snd_soc_codec *sn95031_codec)
-{
- int i, value;
-
- /* check whether ADC is enabled */
- value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
-
- if ((value & SN95031_ADC_ENBL) == 0)
- return 0;
-
- /* ADC is already enabled; Looking for an empty channel */
- for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) {
- value = snd_soc_read(sn95031_codec,
- SN95031_ADC_CHNL_START_ADDR + i);
- if (value & SN95031_STOPBIT_MASK)
- break;
- }
- return (i == SN95031_ADC_CHANLS_MAX) ? (-EINVAL) : i;
-}
-
-/* Initialize the ADC for reading micbias values. Can sleep. */
-static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec)
-{
- int base_addr, chnl_addr;
- int value;
- int channel_index;
-
- /* Index of the first channel in which the stop bit is set */
- channel_index = find_free_channel(sn95031_codec);
- if (channel_index < 0) {
- pr_err("No free ADC channels");
- return channel_index;
- }
-
- base_addr = SN95031_ADC_CHNL_START_ADDR + channel_index;
-
- if (!(channel_index == 0 || channel_index == SN95031_ADC_LOOP_MAX)) {
- /* Reset stop bit for channels other than 0 and 12 */
- value = snd_soc_read(sn95031_codec, base_addr);
- /* Set the stop bit to zero */
- snd_soc_write(sn95031_codec, base_addr, value & 0xEF);
- /* Index of the first free channel */
- base_addr++;
- channel_index++;
- }
-
- /* Since this is the last channel, set the stop bit
- to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
- snd_soc_write(sn95031_codec, base_addr,
- SN95031_AUDIO_DETECT_CODE | 0x10);
-
- chnl_addr = SN95031_ADC_DATA_START_ADDR + 2 * channel_index;
- pr_debug("mid_initialize : %x", chnl_addr);
- configure_adc(sn95031_codec, 1);
- return chnl_addr;
-}
-
-
-/* reads the ADC registers and gets the mic bias value in mV. */
-static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
-{
- u16 adc_adr = sn95031_initialize_adc(codec);
- u16 adc_val1, adc_val2;
- unsigned int mic_bias;
-
- sn95031_enable_mic_bias(codec);
-
- /* Enable the sound card for conversion before reading */
- snd_soc_write(codec, SN95031_ADC1CNTL3, 0x05);
- /* Re-toggle the RRDATARD bit */
- snd_soc_write(codec, SN95031_ADC1CNTL3, 0x04);
-
- /* Read the higher bits of data */
- msleep(1000);
- adc_val1 = snd_soc_read(codec, adc_adr);
- adc_adr++;
- adc_val2 = snd_soc_read(codec, adc_adr);
-
- /* Adding lower two bits to the higher bits */
- mic_bias = (adc_val1 << 2) + (adc_val2 & 3);
- mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000;
- pr_debug("mic bias = %dmV\n", mic_bias);
- return mic_bias;
-}
-/*end - adc helper functions */
-
-static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val)
-{
- u8 value = 0;
- int ret;
-
- ret = intel_scu_ipc_ioread8(reg, &value);
- if (ret == 0)
- *val = value;
-
- return ret;
-}
-
-static int sn95031_write(void *ctx, unsigned int reg, unsigned int value)
-{
- return intel_scu_ipc_iowrite8(reg, value);
-}
-
-static const struct regmap_config sn95031_regmap = {
- .reg_read = sn95031_read,
- .reg_write = sn95031_write,
-};
-
-static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
- enum snd_soc_bias_level level)
-{
- switch (level) {
- case SND_SOC_BIAS_ON:
- break;
-
- case SND_SOC_BIAS_PREPARE:
- if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
- pr_debug("vaud_bias powering up pll\n");
- /* power up the pll */
- snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
- /* enable pcm 2 */
- snd_soc_update_bits(codec, SN95031_PCM2C2,
- BIT(0), BIT(0));
- }
- break;
-
- case SND_SOC_BIAS_STANDBY:
- switch (snd_soc_codec_get_bias_level(codec)) {
- case SND_SOC_BIAS_OFF:
- pr_debug("vaud_bias power up rail\n");
- /* power up the rail */
- snd_soc_write(codec, SN95031_VAUD,
- BIT(2)|BIT(1)|BIT(0));
- msleep(1);
- break;
- case SND_SOC_BIAS_PREPARE:
- /* turn off pcm */
- pr_debug("vaud_bias power dn pcm\n");
- snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
- snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
- break;
- default:
- break;
- }
- break;
-
-
- case SND_SOC_BIAS_OFF:
- pr_debug("vaud_bias _OFF doing rail shutdown\n");
- snd_soc_write(codec, SN95031_VAUD, BIT(3));
- break;
- }
-
- return 0;
-}
-
-static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
- /* power up the rail */
- snd_soc_write(codec, SN95031_VHSP, 0x3D);
- snd_soc_write(codec, SN95031_VHSN, 0x3F);
- msleep(1);
- } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
- pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
- snd_soc_write(codec, SN95031_VHSP, 0xC4);
- snd_soc_write(codec, SN95031_VHSN, 0x04);
- }
- return 0;
-}
-
-static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
- /* power up the rail */
- snd_soc_write(codec, SN95031_VIHF, 0x27);
- msleep(1);
- } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
- pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
- snd_soc_write(codec, SN95031_VIHF, 0x24);
- }
- return 0;
-}
-
-static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
-
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- ldo = BIT(5)|BIT(4);
- clk_dir = BIT(0);
- data_dir = BIT(7);
- }
- /* program DMIC LDO, clock and set clock */
- snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
- snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
- snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir);
- return 0;
-}
-
-static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
-
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- ldo = BIT(5)|BIT(4);
- clk_dir = BIT(2);
- data_dir = BIT(1);
- }
- /* program DMIC LDO, clock and set clock */
- snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
- snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
- snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir);
- return 0;
-}
-
-static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- unsigned int ldo = 0;
-
- if (SND_SOC_DAPM_EVENT_ON(event))
- ldo = BIT(7)|BIT(6);
-
- /* program DMIC LDO */
- snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
- return 0;
-}
-
-/* mux controls */
-static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
-
-static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum,
- SN95031_ADCCONFIG, 1, sn95031_mic_texts);
-
-static const struct snd_kcontrol_new sn95031_micl_mux_control =
- SOC_DAPM_ENUM("Route", sn95031_micl_enum);
-
-static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum,
- SN95031_ADCCONFIG, 3, sn95031_mic_texts);
-
-static const struct snd_kcontrol_new sn95031_micr_mux_control =
- SOC_DAPM_ENUM("Route", sn95031_micr_enum);
-
-static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3",
- "DMIC4", "DMIC5", "DMIC6",
- "ADC Left", "ADC Right" };
-
-static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum,
- SN95031_AUDIOMUX12, 0, sn95031_input_texts);
-
-static const struct snd_kcontrol_new sn95031_input1_mux_control =
- SOC_DAPM_ENUM("Route", sn95031_input1_enum);
-
-static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum,
- SN95031_AUDIOMUX12, 4, sn95031_input_texts);
-
-static const struct snd_kcontrol_new sn95031_input2_mux_control =
- SOC_DAPM_ENUM("Route", sn95031_input2_enum);
-
-static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum,
- SN95031_AUDIOMUX34, 0, sn95031_input_texts);
-
-static const struct snd_kcontrol_new sn95031_input3_mux_control =
- SOC_DAPM_ENUM("Route", sn95031_input3_enum);
-
-static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum,
- SN95031_AUDIOMUX34, 4, sn95031_input_texts);
-
-static const struct snd_kcontrol_new sn95031_input4_mux_control =
- SOC_DAPM_ENUM("Route", sn95031_input4_enum);
-
-/* capture path controls */
-
-static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"};
-
-/* 0dB to 30dB in 10dB steps */
-static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0);
-
-static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum,
- SN95031_MICAMP1, 1, sn95031_micmode_text);
-static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum,
- SN95031_MICAMP2, 1, sn95031_micmode_text);
-
-static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"};
-
-static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum,
- SN95031_DMICMUX, 0, sn95031_dmic_cfg_text);
-static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum,
- SN95031_DMICMUX, 1, sn95031_dmic_cfg_text);
-static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum,
- SN95031_DMICMUX, 2, sn95031_dmic_cfg_text);
-
-static const struct snd_kcontrol_new sn95031_snd_controls[] = {
- SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum),
- SOC_ENUM("Mic2Mode Capture Route", sn95031_micmode2_enum),
- SOC_ENUM("DMIC12 Capture Route", sn95031_dmic12_cfg_enum),
- SOC_ENUM("DMIC34 Capture Route", sn95031_dmic34_cfg_enum),
- SOC_ENUM("DMIC56 Capture Route", sn95031_dmic56_cfg_enum),
- SOC_SINGLE_TLV("Mic1 Capture Volume", SN95031_MICAMP1,
- 2, 4, 0, mic_tlv),
- SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2,
- 2, 4, 0, mic_tlv),
-};
-
-/* DAPM widgets */
-static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
-
- /* all end points mic, hs etc */
- SND_SOC_DAPM_OUTPUT("HPOUTL"),
- SND_SOC_DAPM_OUTPUT("HPOUTR"),
- SND_SOC_DAPM_OUTPUT("EPOUT"),
- SND_SOC_DAPM_OUTPUT("IHFOUTL"),
- SND_SOC_DAPM_OUTPUT("IHFOUTR"),
- SND_SOC_DAPM_OUTPUT("LINEOUTL"),
- SND_SOC_DAPM_OUTPUT("LINEOUTR"),
- SND_SOC_DAPM_OUTPUT("VIB1OUT"),
- SND_SOC_DAPM_OUTPUT("VIB2OUT"),
-
- SND_SOC_DAPM_INPUT("AMIC1"), /* headset mic */
- SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_INPUT("DMIC1"),
- SND_SOC_DAPM_INPUT("DMIC2"),
- SND_SOC_DAPM_INPUT("DMIC3"),
- SND_SOC_DAPM_INPUT("DMIC4"),
- SND_SOC_DAPM_INPUT("DMIC5"),
- SND_SOC_DAPM_INPUT("DMIC6"),
- SND_SOC_DAPM_INPUT("LINEINL"),
- SND_SOC_DAPM_INPUT("LINEINR"),
-
- SND_SOC_DAPM_MICBIAS("AMIC1Bias", SN95031_MICBIAS, 2, 0),
- SND_SOC_DAPM_MICBIAS("AMIC2Bias", SN95031_MICBIAS, 3, 0),
- SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0),
- SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0),
- SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0),
-
- SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0,
- sn95031_dmic12_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("DMIC34supply", SN95031_DMICLK, 1, 0,
- sn95031_dmic34_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("DMIC56supply", SN95031_DMICLK, 2, 0,
- sn95031_dmic56_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT("PCM_Out", "Capture", 0,
- SND_SOC_NOPM, 0, 0),
-
- SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0,
- sn95031_vhs_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0,
- sn95031_vihf_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- /* playback path driver enables */
- SND_SOC_DAPM_PGA("Headset Left Playback",
- SN95031_DRIVEREN, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Headset Right Playback",
- SN95031_DRIVEREN, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Speaker Left Playback",
- SN95031_DRIVEREN, 2, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Speaker Right Playback",
- SN95031_DRIVEREN, 3, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Vibra1 Playback",
- SN95031_DRIVEREN, 4, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Vibra2 Playback",
- SN95031_DRIVEREN, 5, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Earpiece Playback",
- SN95031_DRIVEREN, 6, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Lineout Left Playback",
- SN95031_LOCTL, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Lineout Right Playback",
- SN95031_LOCTL, 4, 0, NULL, 0),
-
- /* playback path filter enable */
- SND_SOC_DAPM_PGA("Headset Left Filter",
- SN95031_HSEPRXCTRL, 4, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Headset Right Filter",
- SN95031_HSEPRXCTRL, 5, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Speaker Left Filter",
- SN95031_IHFRXCTRL, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Speaker Right Filter",
- SN95031_IHFRXCTRL, 1, 0, NULL, 0),
-
- /* DACs */
- SND_SOC_DAPM_DAC("HSDAC Left", "Headset",
- SN95031_DACCONFIG, 0, 0),
- SND_SOC_DAPM_DAC("HSDAC Right", "Headset",
- SN95031_DACCONFIG, 1, 0),
- SND_SOC_DAPM_DAC("IHFDAC Left", "Speaker",
- SN95031_DACCONFIG, 2, 0),
- SND_SOC_DAPM_DAC("IHFDAC Right", "Speaker",
- SN95031_DACCONFIG, 3, 0),
- SND_SOC_DAPM_DAC("Vibra1 DAC", "Vibra1",
- SN95031_VIB1C5, 1, 0),
- SND_SOC_DAPM_DAC("Vibra2 DAC", "Vibra2",
- SN95031_VIB2C5, 1, 0),
-
- /* capture widgets */
- SND_SOC_DAPM_PGA("LineIn Enable Left", SN95031_MICAMP1,
- 7, 0, NULL, 0),
- SND_SOC_DAPM_PGA("LineIn Enable Right", SN95031_MICAMP2,
- 7, 0, NULL, 0),
-
- SND_SOC_DAPM_PGA("MIC1 Enable", SN95031_MICAMP1, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("MIC2 Enable", SN95031_MICAMP2, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("TX1 Enable", SN95031_AUDIOTXEN, 2, 0, NULL, 0),
- SND_SOC_DAPM_PGA("TX2 Enable", SN95031_AUDIOTXEN, 3, 0, NULL, 0),
- SND_SOC_DAPM_PGA("TX3 Enable", SN95031_AUDIOTXEN, 4, 0, NULL, 0),
- SND_SOC_DAPM_PGA("TX4 Enable", SN95031_AUDIOTXEN, 5, 0, NULL, 0),
-
- /* ADC have null stream as they will be turned ON by TX path */
- SND_SOC_DAPM_ADC("ADC Left", NULL,
- SN95031_ADCCONFIG, 0, 0),
- SND_SOC_DAPM_ADC("ADC Right", NULL,
- SN95031_ADCCONFIG, 2, 0),
-
- SND_SOC_DAPM_MUX("Mic_InputL Capture Route",
- SND_SOC_NOPM, 0, 0, &sn95031_micl_mux_control),
- SND_SOC_DAPM_MUX("Mic_InputR Capture Route",
- SND_SOC_NOPM, 0, 0, &sn95031_micr_mux_control),
-
- SND_SOC_DAPM_MUX("Txpath1 Capture Route",
- SND_SOC_NOPM, 0, 0, &sn95031_input1_mux_control),
- SND_SOC_DAPM_MUX("Txpath2 Capture Route",
- SND_SOC_NOPM, 0, 0, &sn95031_input2_mux_control),
- SND_SOC_DAPM_MUX("Txpath3 Capture Route",
- SND_SOC_NOPM, 0, 0, &sn95031_input3_mux_control),
- SND_SOC_DAPM_MUX("Txpath4 Capture Route",
- SND_SOC_NOPM, 0, 0, &sn95031_input4_mux_control),
-
-};
-
-static const struct snd_soc_dapm_route sn95031_audio_map[] = {
- /* headset and earpiece map */
- { "HPOUTL", NULL, "Headset Rail"},
- { "HPOUTR", NULL, "Headset Rail"},
- { "HPOUTL", NULL, "Headset Left Playback" },
- { "HPOUTR", NULL, "Headset Right Playback" },
- { "EPOUT", NULL, "Earpiece Playback" },
- { "Headset Left Playback", NULL, "Headset Left Filter"},
- { "Headset Right Playback", NULL, "Headset Right Filter"},
- { "Earpiece Playback", NULL, "Headset Left Filter"},
- { "Headset Left Filter", NULL, "HSDAC Left"},
- { "Headset Right Filter", NULL, "HSDAC Right"},
-
- /* speaker map */
- { "IHFOUTL", NULL, "Speaker Rail"},
- { "IHFOUTR", NULL, "Speaker Rail"},
- { "IHFOUTL", NULL, "Speaker Left Playback"},
- { "IHFOUTR", NULL, "Speaker Right Playback"},
- { "Speaker Left Playback", NULL, "Speaker Left Filter"},
- { "Speaker Right Playback", NULL, "Speaker Right Filter"},
- { "Speaker Left Filter", NULL, "IHFDAC Left"},
- { "Speaker Right Filter", NULL, "IHFDAC Right"},
-
- /* vibra map */
- { "VIB1OUT", NULL, "Vibra1 Playback"},
- { "Vibra1 Playback", NULL, "Vibra1 DAC"},
-
- { "VIB2OUT", NULL, "Vibra2 Playback"},
- { "Vibra2 Playback", NULL, "Vibra2 DAC"},
-
- /* lineout */
- { "LINEOUTL", NULL, "Lineout Left Playback"},
- { "LINEOUTR", NULL, "Lineout Right Playback"},
- { "Lineout Left Playback", NULL, "Headset Left Filter"},
- { "Lineout Left Playback", NULL, "Speaker Left Filter"},
- { "Lineout Left Playback", NULL, "Vibra1 DAC"},
- { "Lineout Right Playback", NULL, "Headset Right Filter"},
- { "Lineout Right Playback", NULL, "Speaker Right Filter"},
- { "Lineout Right Playback", NULL, "Vibra2 DAC"},
-
- /* Headset (AMIC1) mic */
- { "AMIC1Bias", NULL, "AMIC1"},
- { "MIC1 Enable", NULL, "AMIC1Bias"},
- { "Mic_InputL Capture Route", "AMIC", "MIC1 Enable"},
-
- /* AMIC2 */
- { "AMIC2Bias", NULL, "AMIC2"},
- { "MIC2 Enable", NULL, "AMIC2Bias"},
- { "Mic_InputR Capture Route", "AMIC", "MIC2 Enable"},
-
-
- /* Linein */
- { "LineIn Enable Left", NULL, "LINEINL"},
- { "LineIn Enable Right", NULL, "LINEINR"},
- { "Mic_InputL Capture Route", "LineIn", "LineIn Enable Left"},
- { "Mic_InputR Capture Route", "LineIn", "LineIn Enable Right"},
-
- /* ADC connection */
- { "ADC Left", NULL, "Mic_InputL Capture Route"},
- { "ADC Right", NULL, "Mic_InputR Capture Route"},
-
- /*DMIC connections */
- { "DMIC1", NULL, "DMIC12supply"},
- { "DMIC2", NULL, "DMIC12supply"},
- { "DMIC3", NULL, "DMIC34supply"},
- { "DMIC4", NULL, "DMIC34supply"},
- { "DMIC5", NULL, "DMIC56supply"},
- { "DMIC6", NULL, "DMIC56supply"},
-
- { "DMIC12Bias", NULL, "DMIC1"},
- { "DMIC12Bias", NULL, "DMIC2"},
- { "DMIC34Bias", NULL, "DMIC3"},
- { "DMIC34Bias", NULL, "DMIC4"},
- { "DMIC56Bias", NULL, "DMIC5"},
- { "DMIC56Bias", NULL, "DMIC6"},
-
- /*TX path inputs*/
- { "Txpath1 Capture Route", "ADC Left", "ADC Left"},
- { "Txpath2 Capture Route", "ADC Left", "ADC Left"},
- { "Txpath3 Capture Route", "ADC Left", "ADC Left"},
- { "Txpath4 Capture Route", "ADC Left", "ADC Left"},
- { "Txpath1 Capture Route", "ADC Right", "ADC Right"},
- { "Txpath2 Capture Route", "ADC Right", "ADC Right"},
- { "Txpath3 Capture Route", "ADC Right", "ADC Right"},
- { "Txpath4 Capture Route", "ADC Right", "ADC Right"},
- { "Txpath1 Capture Route", "DMIC1", "DMIC1"},
- { "Txpath2 Capture Route", "DMIC1", "DMIC1"},
- { "Txpath3 Capture Route", "DMIC1", "DMIC1"},
- { "Txpath4 Capture Route", "DMIC1", "DMIC1"},
- { "Txpath1 Capture Route", "DMIC2", "DMIC2"},
- { "Txpath2 Capture Route", "DMIC2", "DMIC2"},
- { "Txpath3 Capture Route", "DMIC2", "DMIC2"},
- { "Txpath4 Capture Route", "DMIC2", "DMIC2"},
- { "Txpath1 Capture Route", "DMIC3", "DMIC3"},
- { "Txpath2 Capture Route", "DMIC3", "DMIC3"},
- { "Txpath3 Capture Route", "DMIC3", "DMIC3"},
- { "Txpath4 Capture Route", "DMIC3", "DMIC3"},
- { "Txpath1 Capture Route", "DMIC4", "DMIC4"},
- { "Txpath2 Capture Route", "DMIC4", "DMIC4"},
- { "Txpath3 Capture Route", "DMIC4", "DMIC4"},
- { "Txpath4 Capture Route", "DMIC4", "DMIC4"},
- { "Txpath1 Capture Route", "DMIC5", "DMIC5"},
- { "Txpath2 Capture Route", "DMIC5", "DMIC5"},
- { "Txpath3 Capture Route", "DMIC5", "DMIC5"},
- { "Txpath4 Capture Route", "DMIC5", "DMIC5"},
- { "Txpath1 Capture Route", "DMIC6", "DMIC6"},
- { "Txpath2 Capture Route", "DMIC6", "DMIC6"},
- { "Txpath3 Capture Route", "DMIC6", "DMIC6"},
- { "Txpath4 Capture Route", "DMIC6", "DMIC6"},
-
- /* tx path */
- { "TX1 Enable", NULL, "Txpath1 Capture Route"},
- { "TX2 Enable", NULL, "Txpath2 Capture Route"},
- { "TX3 Enable", NULL, "Txpath3 Capture Route"},
- { "TX4 Enable", NULL, "Txpath4 Capture Route"},
- { "PCM_Out", NULL, "TX1 Enable"},
- { "PCM_Out", NULL, "TX2 Enable"},
- { "PCM_Out", NULL, "TX3 Enable"},
- { "PCM_Out", NULL, "TX4 Enable"},
-
-};
-
-/* speaker and headset mutes, for audio pops and clicks */
-static int sn95031_pcm_hs_mute(struct snd_soc_dai *dai, int mute)
-{
- snd_soc_update_bits(dai->codec,
- SN95031_HSLVOLCTRL, BIT(7), (!mute << 7));
- snd_soc_update_bits(dai->codec,
- SN95031_HSRVOLCTRL, BIT(7), (!mute << 7));
- return 0;
-}
-
-static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
-{
- snd_soc_update_bits(dai->codec,
- SN95031_IHFLVOLCTRL, BIT(7), (!mute << 7));
- snd_soc_update_bits(dai->codec,
- SN95031_IHFRVOLCTRL, BIT(7), (!mute << 7));
- return 0;
-}
-
-static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
- unsigned int format, rate;
-
- switch (params_width(params)) {
- case 16:
- format = BIT(4)|BIT(5);
- break;
-
- case 24:
- format = 0;
- break;
- default:
- return -EINVAL;
- }
- snd_soc_update_bits(dai->codec, SN95031_PCM2C2,
- BIT(4)|BIT(5), format);
-
- switch (params_rate(params)) {
- case 48000:
- pr_debug("RATE_48000\n");
- rate = 0;
- break;
-
- case 44100:
- pr_debug("RATE_44100\n");
- rate = BIT(7);
- break;
-
- default:
- pr_err("ERR rate %d\n", params_rate(params));
- return -EINVAL;
- }
- snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate);
-
- return 0;
-}
-
-/* Codec DAI section */
-static const struct snd_soc_dai_ops sn95031_headset_dai_ops = {
- .digital_mute = sn95031_pcm_hs_mute,
- .hw_params = sn95031_pcm_hw_params,
-};
-
-static const struct snd_soc_dai_ops sn95031_speaker_dai_ops = {
- .digital_mute = sn95031_pcm_spkr_mute,
- .hw_params = sn95031_pcm_hw_params,
-};
-
-static const struct snd_soc_dai_ops sn95031_vib1_dai_ops = {
- .hw_params = sn95031_pcm_hw_params,
-};
-
-static const struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
- .hw_params = sn95031_pcm_hw_params,
-};
-
-static struct snd_soc_dai_driver sn95031_dais[] = {
-{
- .name = "SN95031 Headset",
- .playback = {
- .stream_name = "Headset",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SN95031_RATES,
- .formats = SN95031_FORMATS,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 5,
- .rates = SN95031_RATES,
- .formats = SN95031_FORMATS,
- },
- .ops = &sn95031_headset_dai_ops,
-},
-{ .name = "SN95031 Speaker",
- .playback = {
- .stream_name = "Speaker",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SN95031_RATES,
- .formats = SN95031_FORMATS,
- },
- .ops = &sn95031_speaker_dai_ops,
-},
-{ .name = "SN95031 Vibra1",
- .playback = {
- .stream_name = "Vibra1",
- .channels_min = 1,
- .channels_max = 1,
- .rates = SN95031_RATES,
- .formats = SN95031_FORMATS,
- },
- .ops = &sn95031_vib1_dai_ops,
-},
-{ .name = "SN95031 Vibra2",
- .playback = {
- .stream_name = "Vibra2",
- .channels_min = 1,
- .channels_max = 1,
- .rates = SN95031_RATES,
- .formats = SN95031_FORMATS,
- },
- .ops = &sn95031_vib2_dai_ops,
-},
-};
-
-static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec)
-{
- snd_soc_write(codec, SN95031_BTNCTRL2, 0x00);
-}
-
-static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
-{
- snd_soc_write(codec, SN95031_BTNCTRL1, 0x77);
- snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
-}
-
-static int sn95031_get_headset_state(struct snd_soc_codec *codec,
- struct snd_soc_jack *mfld_jack)
-{
- int micbias = sn95031_get_mic_bias(codec);
-
- int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
-
- pr_debug("jack type detected = %d\n", jack_type);
- if (jack_type == SND_JACK_HEADSET)
- sn95031_enable_jack_btn(codec);
- return jack_type;
-}
-
-void sn95031_jack_detection(struct snd_soc_codec *codec,
- struct mfld_jack_data *jack_data)
-{
- unsigned int status;
- unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
-
- pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id);
- if (jack_data->intr_id & 0x1) {
- pr_debug("short_push detected\n");
- status = SND_JACK_HEADSET | SND_JACK_BTN_0;
- } else if (jack_data->intr_id & 0x2) {
- pr_debug("long_push detected\n");
- status = SND_JACK_HEADSET | SND_JACK_BTN_1;
- } else if (jack_data->intr_id & 0x4) {
- pr_debug("headset or headphones inserted\n");
- status = sn95031_get_headset_state(codec, jack_data->mfld_jack);
- } else if (jack_data->intr_id & 0x8) {
- pr_debug("headset or headphones removed\n");
- status = 0;
- sn95031_disable_jack_btn(codec);
- } else {
- pr_err("unidentified interrupt\n");
- return;
- }
-
- snd_soc_jack_report(jack_data->mfld_jack, status, mask);
- /*button pressed and released so we send explicit button release */
- if ((status & SND_JACK_BTN_0) | (status & SND_JACK_BTN_1))
- snd_soc_jack_report(jack_data->mfld_jack,
- SND_JACK_HEADSET, mask);
-}
-EXPORT_SYMBOL_GPL(sn95031_jack_detection);
-
-/* codec registration */
-static int sn95031_codec_probe(struct snd_soc_codec *codec)
-{
- pr_debug("codec_probe called\n");
-
- /* PCM interface config
- * This sets the pcm rx slot conguration to max 6 slots
- * for max 4 dais (2 stereo and 2 mono)
- */
- snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10);
- snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32);
- snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54);
- snd_soc_write(codec, SN95031_PCM2TXSLOT01, 0x10);
- snd_soc_write(codec, SN95031_PCM2TXSLOT23, 0x32);
- /* pcm port setting
- * This sets the pcm port to slave and clock at 19.2Mhz which
- * can support 6slots, sampling rate set per stream in hw-params
- */
- snd_soc_write(codec, SN95031_PCM1C1, 0x00);
- snd_soc_write(codec, SN95031_PCM2C1, 0x01);
- snd_soc_write(codec, SN95031_PCM2C2, 0x0A);
- snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4));
- /* vendor vibra workround, the vibras are muted by
- * custom register so unmute them
- */
- snd_soc_write(codec, SN95031_SSR5, 0x80);
- snd_soc_write(codec, SN95031_SSR6, 0x80);
- snd_soc_write(codec, SN95031_VIB1C5, 0x00);
- snd_soc_write(codec, SN95031_VIB2C5, 0x00);
- /* configure vibras for pcm port */
- snd_soc_write(codec, SN95031_VIB1C3, 0x00);
- snd_soc_write(codec, SN95031_VIB2C3, 0x00);
-
- /* soft mute ramp time */
- snd_soc_write(codec, SN95031_SOFTMUTE, 0x3);
- /* fix the initial volume at 1dB,
- * default in +9dB,
- * 1dB give optimal swing on DAC, amps
- */
- snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08);
- snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08);
- snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08);
- snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08);
- /* dac mode and lineout workaround */
- snd_soc_write(codec, SN95031_SSR2, 0x10);
- snd_soc_write(codec, SN95031_SSR3, 0x40);
-
- return 0;
-}
-
-static const struct snd_soc_codec_driver sn95031_codec = {
- .probe = sn95031_codec_probe,
- .set_bias_level = sn95031_set_vaud_bias,
- .idle_bias_off = true,
-
- .component_driver = {
- .controls = sn95031_snd_controls,
- .num_controls = ARRAY_SIZE(sn95031_snd_controls),
- .dapm_widgets = sn95031_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets),
- .dapm_routes = sn95031_audio_map,
- .num_dapm_routes = ARRAY_SIZE(sn95031_audio_map),
- },
-};
-
-static int sn95031_device_probe(struct platform_device *pdev)
-{
- struct regmap *regmap;
-
- pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev));
-
- regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- return snd_soc_register_codec(&pdev->dev, &sn95031_codec,
- sn95031_dais, ARRAY_SIZE(sn95031_dais));
-}
-
-static int sn95031_device_remove(struct platform_device *pdev)
-{
- pr_debug("codec device remove called\n");
- snd_soc_unregister_codec(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver sn95031_codec_driver = {
- .driver = {
- .name = "sn95031",
- },
- .probe = sn95031_device_probe,
- .remove = sn95031_device_remove,
-};
-
-module_platform_driver(sn95031_codec_driver);
-
-MODULE_DESCRIPTION("ASoC TI SN95031 codec driver");
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sn95031");
diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h
deleted file mode 100644
index 7651fe4..0000000
--- a/sound/soc/codecs/sn95031.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * sn95031.h - TI sn95031 Codec driver
- *
- * Copyright (C) 2010 Intel Corp
- * Author: Vinod Koul <vinod.koul@intel.com>
- * Author: Harsha Priya <priya.harsha@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
- */
-#ifndef _SN95031_H
-#define _SN95031_H
-
-/*register map*/
-#define SN95031_VAUD 0xDB
-#define SN95031_VHSP 0xDC
-#define SN95031_VHSN 0xDD
-#define SN95031_VIHF 0xC9
-
-#define SN95031_AUDPLLCTRL 0x240
-#define SN95031_DMICBUF0123 0x241
-#define SN95031_DMICBUF45 0x242
-#define SN95031_DMICGPO 0x244
-#define SN95031_DMICMUX 0x245
-#define SN95031_DMICLK 0x246
-#define SN95031_MICBIAS 0x247
-#define SN95031_ADCCONFIG 0x248
-#define SN95031_MICAMP1 0x249
-#define SN95031_MICAMP2 0x24A
-#define SN95031_NOISEMUX 0x24B
-#define SN95031_AUDIOMUX12 0x24C
-#define SN95031_AUDIOMUX34 0x24D
-#define SN95031_AUDIOSINC 0x24E
-#define SN95031_AUDIOTXEN 0x24F
-#define SN95031_HSEPRXCTRL 0x250
-#define SN95031_IHFRXCTRL 0x251
-#define SN95031_HSMIXER 0x256
-#define SN95031_DACCONFIG 0x257
-#define SN95031_SOFTMUTE 0x258
-#define SN95031_HSLVOLCTRL 0x259
-#define SN95031_HSRVOLCTRL 0x25A
-#define SN95031_IHFLVOLCTRL 0x25B
-#define SN95031_IHFRVOLCTRL 0x25C
-#define SN95031_DRIVEREN 0x25D
-#define SN95031_LOCTL 0x25E
-#define SN95031_VIB1C1 0x25F
-#define SN95031_VIB1C2 0x260
-#define SN95031_VIB1C3 0x261
-#define SN95031_VIB1SPIPCM1 0x262
-#define SN95031_VIB1SPIPCM2 0x263
-#define SN95031_VIB1C5 0x264
-#define SN95031_VIB2C1 0x265
-#define SN95031_VIB2C2 0x266
-#define SN95031_VIB2C3 0x267
-#define SN95031_VIB2SPIPCM1 0x268
-#define SN95031_VIB2SPIPCM2 0x269
-#define SN95031_VIB2C5 0x26A
-#define SN95031_BTNCTRL1 0x26B
-#define SN95031_BTNCTRL2 0x26C
-#define SN95031_PCM1TXSLOT01 0x26D
-#define SN95031_PCM1TXSLOT23 0x26E
-#define SN95031_PCM1TXSLOT45 0x26F
-#define SN95031_PCM1RXSLOT0_3 0x270
-#define SN95031_PCM1RXSLOT45 0x271
-#define SN95031_PCM2TXSLOT01 0x272
-#define SN95031_PCM2TXSLOT23 0x273
-#define SN95031_PCM2TXSLOT45 0x274
-#define SN95031_PCM2RXSLOT01 0x275
-#define SN95031_PCM2RXSLOT23 0x276
-#define SN95031_PCM2RXSLOT45 0x277
-#define SN95031_PCM1C1 0x278
-#define SN95031_PCM1C2 0x279
-#define SN95031_PCM1C3 0x27A
-#define SN95031_PCM2C1 0x27B
-#define SN95031_PCM2C2 0x27C
-/*end codec register defn*/
-
-/*vendor defn these are not part of avp*/
-#define SN95031_SSR2 0x381
-#define SN95031_SSR3 0x382
-#define SN95031_SSR5 0x384
-#define SN95031_SSR6 0x385
-
-/* ADC registers */
-
-#define SN95031_ADC1CNTL1 0x1C0
-#define SN95031_ADC_ENBL 0x10
-#define SN95031_ADC_START 0x08
-#define SN95031_ADC1CNTL3 0x1C2
-#define SN95031_ADCTHERM_ENBL 0x04
-#define SN95031_ADCRRDATA_ENBL 0x05
-#define SN95031_STOPBIT_MASK 16
-#define SN95031_ADCTHERM_MASK 4
-#define SN95031_ADC_CHANLS_MAX 15 /* Number of ADC channels */
-#define SN95031_ADC_LOOP_MAX (SN95031_ADC_CHANLS_MAX - 1)
-#define SN95031_ADC_NO_LOOP 0x07
-#define SN95031_AUDIO_GPIO_CTRL 0x070
-
-/* ADC channel code values */
-#define SN95031_AUDIO_DETECT_CODE 0x06
-
-/* ADC base addresses */
-#define SN95031_ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
-#define SN95031_ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
-/* multipier to convert to mV */
-#define SN95031_ADC_ONE_LSB_MULTIPLIER 2346
-
-
-struct mfld_jack_data {
- int intr_id;
- int micbias_vol;
- struct snd_soc_jack *mfld_jack;
-};
-
-extern void sn95031_jack_detection(struct snd_soc_codec *codec,
- struct mfld_jack_data *jack_data);
-
-#endif
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index 7acd051..c8fd636 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -34,10 +34,11 @@ static const struct snd_soc_dapm_route dir_routes[] = {
#define STUB_RATES SNDRV_PCM_RATE_8000_192000
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
-static const struct snd_soc_codec_driver soc_codec_spdif_dir = {
+static struct snd_soc_codec_driver soc_codec_spdif_dir = {
.component_driver = {
.dapm_widgets = dir_widgets,
.num_dapm_widgets = ARRAY_SIZE(dir_widgets),
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index 063a64f..037aa1d 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -27,7 +27,8 @@
#define STUB_RATES SNDRV_PCM_RATE_8000_192000
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dapm_widget dit_widgets[] = {
SND_SOC_DAPM_OUTPUT("spdif-out"),
@@ -37,7 +38,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
{ "spdif-out", NULL, "Playback" },
};
-static const struct snd_soc_codec_driver soc_codec_spdif_dit = {
+static struct snd_soc_codec_driver soc_codec_spdif_dit = {
.component_driver = {
.dapm_widgets = dit_widgets,
.num_dapm_widgets = ARRAY_SIZE(dit_widgets),
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 730fb20..1ff3edb 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -116,7 +116,7 @@ struct aic31xx_pdata {
/* INT2 interrupt control */
#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49)
/* GPIO1 control */
-#define AIC31XX_GPIO1 AIC31XX_REG(0, 50)
+#define AIC31XX_GPIO1 AIC31XX_REG(0, 51)
#define AIC31XX_DACPRB AIC31XX_REG(0, 60)
/* ADC Instruction Set Register */
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index c482b2e..cfe72b9 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -232,7 +232,7 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
struct device_node *twl4030_codec_node = NULL;
- twl4030_codec_node = of_find_node_by_name(codec->dev->parent->of_node,
+ twl4030_codec_node = of_get_child_by_name(codec->dev->parent->of_node,
"codec");
if (!pdata && twl4030_codec_node) {
@@ -241,9 +241,11 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
GFP_KERNEL);
if (!pdata) {
dev_err(codec->dev, "Can not allocate memory\n");
+ of_node_put(twl4030_codec_node);
return NULL;
}
twl4030_setup_pdata_of(pdata, twl4030_codec_node);
+ of_node_put(twl4030_codec_node);
}
return pdata;
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index d83dab5..5c2f572 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -98,6 +98,8 @@ struct wm2200_priv {
int rev;
int sysclk;
+
+ unsigned int symmetric_rates:1;
};
#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1)
@@ -1550,7 +1552,7 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
static int wm2200_probe(struct snd_soc_codec *codec)
{
- struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev);
+ struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
int ret;
wm2200->codec = codec;
@@ -1758,7 +1760,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
lrclk = bclk_rates[bclk] / params_rate(params);
dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- dai->symmetric_rates)
+ wm2200->symmetric_rates)
snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
WM2200_AIF1RX_BCPF_MASK, lrclk);
else
@@ -2059,13 +2061,14 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
static int wm2200_dai_probe(struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
+ struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
unsigned int val = 0;
int ret;
ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
if (ret >= 0) {
if ((ret & WM2200_GP1_FN_MASK) != 0) {
- dai->symmetric_rates = true;
+ wm2200->symmetric_rates = true;
val = WM2200_AIF1TX_LRCLK_SRC;
}
} else {
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 65c059b5..66e32f5 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1733,7 +1733,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
le64_to_cpu(footer->timestamp));
while (pos < firmware->size &&
- pos - firmware->size > sizeof(*region)) {
+ sizeof(*region) < firmware->size - pos) {
region = (void *)&(firmware->data[pos]);
region_name = "Unknown";
reg = 0;
@@ -1782,8 +1782,8 @@ static int wm_adsp_load(struct wm_adsp *dsp)
regions, le32_to_cpu(region->len), offset,
region_name);
- if ((pos + le32_to_cpu(region->len) + sizeof(*region)) >
- firmware->size) {
+ if (le32_to_cpu(region->len) >
+ firmware->size - pos - sizeof(*region)) {
adsp_err(dsp,
"%s.%d: %s region len %d bytes exceeds file length %zu\n",
file, regions, region_name,
@@ -2253,7 +2253,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
blocks = 0;
while (pos < firmware->size &&
- pos - firmware->size > sizeof(*blk)) {
+ sizeof(*blk) < firmware->size - pos) {
blk = (void *)(&firmware->data[pos]);
type = le16_to_cpu(blk->type);
@@ -2327,8 +2327,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
}
if (reg) {
- if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) >
- firmware->size) {
+ if (le32_to_cpu(blk->len) >
+ firmware->size - pos - sizeof(*blk)) {
adsp_err(dsp,
"%s.%d: %s region len %d bytes exceeds file length %zu\n",
file, blocks, region_name,
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 804c6f2..03ba218 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1242,6 +1242,20 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
return snd_mask_refine(fmt, &nfmt);
}
+static int davinci_mcasp_hw_rule_min_periodsize(
+ struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *period_size = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ struct snd_interval frames;
+
+ snd_interval_any(&frames);
+ frames.min = 64;
+ frames.integer = 1;
+
+ return snd_interval_refine(period_size, &frames);
+}
+
static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
@@ -1333,6 +1347,11 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
return ret;
}
+ snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ davinci_mcasp_hw_rule_min_periodsize, NULL,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+
return 0;
}
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 84ef638..191426a 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -29,7 +29,6 @@
#include "../codecs/tlv320aic23.h"
#include "imx-ssi.h"
-#include "fsl_ssi.h"
#include "imx-audmux.h"
#define CODEC_CLOCK 12000000
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 1225e03..989be51 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -442,8 +442,8 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
if (fsl_asoc_card_is_ac97(priv)) {
#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
/*
* Use slots 3/4 for S/PDIF so SSI won't try to enable
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 0f163ab..2c5856a 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -57,7 +57,7 @@
#define REG_ASRDOC 0x74
#define REG_ASRDI(i) (REG_ASRDIA + (i << 3))
#define REG_ASRDO(i) (REG_ASRDOA + (i << 3))
-#define REG_ASRDx(x, i) (x == IN ? REG_ASRDI(i) : REG_ASRDO(i))
+#define REG_ASRDx(x, i) ((x) == IN ? REG_ASRDI(i) : REG_ASRDO(i))
#define REG_ASRIDRHA 0x80
#define REG_ASRIDRLA 0x84
@@ -260,8 +260,8 @@
#define ASRFSTi_OUTPUT_FIFO_SHIFT 12
#define ASRFSTi_OUTPUT_FIFO_MASK (((1 << ASRFSTi_OUTPUT_FIFO_WIDTH) - 1) << ASRFSTi_OUTPUT_FIFO_SHIFT)
#define ASRFSTi_IAEi_SHIFT 11
-#define ASRFSTi_IAEi_MASK (1 << ASRFSTi_OAFi_SHIFT)
-#define ASRFSTi_IAEi (1 << ASRFSTi_OAFi_SHIFT)
+#define ASRFSTi_IAEi_MASK (1 << ASRFSTi_IAEi_SHIFT)
+#define ASRFSTi_IAEi (1 << ASRFSTi_IAEi_SHIFT)
#define ASRFSTi_INPUT_FIFO_WIDTH 7
#define ASRFSTi_INPUT_FIFO_SHIFT 0
#define ASRFSTi_INPUT_FIFO_MASK ((1 << ASRFSTi_INPUT_FIFO_WIDTH) - 1)
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 0c11f43..8c2981b 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -913,8 +913,8 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
dma->dai.pcm_free = fsl_dma_free_dma_buffers;
/* Store the SSI-specific information that we need */
- dma->ssi_stx_phys = res.start + CCSR_SSI_STX0;
- dma->ssi_srx_phys = res.start + CCSR_SSI_SRX0;
+ dma->ssi_stx_phys = res.start + REG_SSI_STX0;
+ dma->ssi_srx_phys = res.start + REG_SSI_SRX0;
iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
if (iprop)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index f2f51e06..aecd00f 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -38,6 +38,7 @@
#include <linux/ctype.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/of.h>
@@ -68,21 +69,35 @@
* samples will be written to STX properly.
*/
#ifdef __BIG_ENDIAN
-#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
- SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
- SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
+#define FSLSSI_I2S_FORMATS \
+ (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S18_3BE | \
+ SNDRV_PCM_FMTBIT_S20_3BE | \
+ SNDRV_PCM_FMTBIT_S24_3BE | \
+ SNDRV_PCM_FMTBIT_S24_BE)
#else
-#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+#define FSLSSI_I2S_FORMATS \
+ (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
#endif
-#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \
- CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \
- CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN)
-#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
- CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
- CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
+#define FSLSSI_SIER_DBG_RX_FLAGS \
+ (SSI_SIER_RFF0_EN | \
+ SSI_SIER_RLS_EN | \
+ SSI_SIER_RFS_EN | \
+ SSI_SIER_ROE0_EN | \
+ SSI_SIER_RFRC_EN)
+#define FSLSSI_SIER_DBG_TX_FLAGS \
+ (SSI_SIER_TFE0_EN | \
+ SSI_SIER_TLS_EN | \
+ SSI_SIER_TFS_EN | \
+ SSI_SIER_TUE0_EN | \
+ SSI_SIER_TFRC_EN)
enum fsl_ssi_type {
FSL_SSI_MCP8610,
@@ -91,23 +106,18 @@ enum fsl_ssi_type {
FSL_SSI_MX51,
};
-struct fsl_ssi_reg_val {
+struct fsl_ssi_regvals {
u32 sier;
u32 srcr;
u32 stcr;
u32 scr;
};
-struct fsl_ssi_rxtx_reg_val {
- struct fsl_ssi_reg_val rx;
- struct fsl_ssi_reg_val tx;
-};
-
static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CCSR_SSI_SACCEN:
- case CCSR_SSI_SACCDIS:
+ case REG_SSI_SACCEN:
+ case REG_SSI_SACCDIS:
return false;
default:
return true;
@@ -117,18 +127,18 @@ static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CCSR_SSI_STX0:
- case CCSR_SSI_STX1:
- case CCSR_SSI_SRX0:
- case CCSR_SSI_SRX1:
- case CCSR_SSI_SISR:
- case CCSR_SSI_SFCSR:
- case CCSR_SSI_SACNT:
- case CCSR_SSI_SACADD:
- case CCSR_SSI_SACDAT:
- case CCSR_SSI_SATAG:
- case CCSR_SSI_SACCST:
- case CCSR_SSI_SOR:
+ case REG_SSI_STX0:
+ case REG_SSI_STX1:
+ case REG_SSI_SRX0:
+ case REG_SSI_SRX1:
+ case REG_SSI_SISR:
+ case REG_SSI_SFCSR:
+ case REG_SSI_SACNT:
+ case REG_SSI_SACADD:
+ case REG_SSI_SACDAT:
+ case REG_SSI_SATAG:
+ case REG_SSI_SACCST:
+ case REG_SSI_SOR:
return true;
default:
return false;
@@ -138,12 +148,12 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CCSR_SSI_SRX0:
- case CCSR_SSI_SRX1:
- case CCSR_SSI_SISR:
- case CCSR_SSI_SACADD:
- case CCSR_SSI_SACDAT:
- case CCSR_SSI_SATAG:
+ case REG_SSI_SRX0:
+ case REG_SSI_SRX1:
+ case REG_SSI_SISR:
+ case REG_SSI_SACADD:
+ case REG_SSI_SACDAT:
+ case REG_SSI_SATAG:
return true;
default:
return false;
@@ -153,9 +163,9 @@ static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg)
static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CCSR_SSI_SRX0:
- case CCSR_SSI_SRX1:
- case CCSR_SSI_SACCST:
+ case REG_SSI_SRX0:
+ case REG_SSI_SRX1:
+ case REG_SSI_SACCST:
return false;
default:
return true;
@@ -163,12 +173,12 @@ static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
}
static const struct regmap_config fsl_ssi_regconfig = {
- .max_register = CCSR_SSI_SACCDIS,
+ .max_register = REG_SSI_SACCDIS,
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
- .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1,
+ .num_reg_defaults_raw = REG_SSI_SACCDIS / sizeof(uint32_t) + 1,
.readable_reg = fsl_ssi_readable_reg,
.volatile_reg = fsl_ssi_volatile_reg,
.precious_reg = fsl_ssi_precious_reg,
@@ -184,78 +194,79 @@ struct fsl_ssi_soc_data {
};
/**
- * fsl_ssi_private: per-SSI private data
+ * fsl_ssi: per-SSI private data
*
- * @reg: Pointer to the regmap registers
+ * @regs: Pointer to the regmap registers
* @irq: IRQ of this SSI
* @cpu_dai_drv: CPU DAI driver for this device
*
* @dai_fmt: DAI configuration this device is currently used with
- * @i2s_mode: i2s and network mode configuration of the device. Is used to
- * switch between normal and i2s/network mode
- * mode depending on the number of channels
+ * @i2s_net: I2S and Network mode configurations of SCR register
* @use_dma: DMA is used or FIQ with stream filter
- * @use_dual_fifo: DMA with support for both FIFOs used
- * @fifo_deph: Depth of the SSI FIFOs
- * @slot_width: width of each DAI slot
- * @slots: number of slots
- * @rxtx_reg_val: Specific register settings for receive/transmit configuration
+ * @use_dual_fifo: DMA with support for dual FIFO mode
+ * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree
+ * @fifo_depth: Depth of the SSI FIFOs
+ * @slot_width: Width of each DAI slot
+ * @slots: Number of slots
+ * @regvals: Specific RX/TX register settings
*
- * @clk: SSI clock
- * @baudclk: SSI baud clock for master mode
+ * @clk: Clock source to access register
+ * @baudclk: Clock source to generate bit and frame-sync clocks
* @baudclk_streams: Active streams that are using baudclk
*
+ * @regcache_sfcsr: Cache sfcsr register value during suspend and resume
+ * @regcache_sacnt: Cache sacnt register value during suspend and resume
+ *
* @dma_params_tx: DMA transmit parameters
* @dma_params_rx: DMA receive parameters
* @ssi_phys: physical address of the SSI registers
*
* @fiq_params: FIQ stream filtering parameters
*
- * @pdev: Pointer to pdev used for deprecated fsl-ssi sound card
+ * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only)
+ * TODO: Should be replaced with simple-sound-card
*
* @dbg_stats: Debugging statistics
*
* @soc: SoC specific data
+ * @dev: Pointer to &pdev->dev
+ *
+ * @fifo_watermark: The FIFO watermark setting. Notifies DMA when there are
+ * @fifo_watermark or fewer words in TX fifo or
+ * @fifo_watermark or more empty words in RX fifo.
+ * @dma_maxburst: Max number of words to transfer in one go. So far,
+ * this is always the same as fifo_watermark.
*
- * @fifo_watermark: the FIFO watermark setting. Notifies DMA when
- * there are @fifo_watermark or fewer words in TX fifo or
- * @fifo_watermark or more empty words in RX fifo.
- * @dma_maxburst: max number of words to transfer in one go. So far,
- * this is always the same as fifo_watermark.
+ * @ac97_reg_lock: Mutex lock to serialize AC97 register access operations
*/
-struct fsl_ssi_private {
+struct fsl_ssi {
struct regmap *regs;
int irq;
struct snd_soc_dai_driver cpu_dai_drv;
unsigned int dai_fmt;
- u8 i2s_mode;
+ u8 i2s_net;
bool use_dma;
bool use_dual_fifo;
bool has_ipg_clk_name;
unsigned int fifo_depth;
unsigned int slot_width;
unsigned int slots;
- struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
+ struct fsl_ssi_regvals regvals[2];
struct clk *clk;
struct clk *baudclk;
unsigned int baudclk_streams;
- /* regcache for volatile regs */
u32 regcache_sfcsr;
u32 regcache_sacnt;
- /* DMA params */
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
dma_addr_t ssi_phys;
- /* params for non-dma FIQ stream filtered mode */
struct imx_pcm_fiq_params fiq_params;
- /* Used when using fsl-ssi as sound-card. This is only used by ppc and
- * should be replaced with simple-sound-card. */
struct platform_device *pdev;
struct fsl_ssi_dbg dbg_stats;
@@ -265,30 +276,32 @@ struct fsl_ssi_private {
u32 fifo_watermark;
u32 dma_maxburst;
+
+ struct mutex ac97_reg_lock;
};
/*
- * imx51 and later SoCs have a slightly different IP that allows the
- * SSI configuration while the SSI unit is running.
- *
- * More important, it is necessary on those SoCs to configure the
- * sperate TX/RX DMA bits just before starting the stream
- * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi
- * sends any DMA requests to the SDMA unit, otherwise it is not defined
- * how the SDMA unit handles the DMA request.
+ * SoC specific data
*
- * SDMA units are present on devices starting at imx35 but the imx35
- * reference manual states that the DMA bits should not be changed
- * while the SSI unit is running (SSIEN). So we support the necessary
- * online configuration of fsl-ssi starting at imx51.
+ * Notes:
+ * 1) SSI in earlier SoCS has critical bits in control registers that
+ * cannot be changed after SSI starts running -- a software reset
+ * (set SSIEN to 0) is required to change their values. So adding
+ * an offline_config flag for these SoCs.
+ * 2) SDMA is available since imx35. However, imx35 does not support
+ * DMA bits changing when SSI is running, so set offline_config.
+ * 3) imx51 and later versions support register configurations when
+ * SSI is running (SSIEN); For these versions, DMA needs to be
+ * configured before SSI sends DMA request to avoid an undefined
+ * DMA request on the SDMA side.
*/
static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = {
.imx = false,
.offline_config = true,
- .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC |
- CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
- CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1,
+ .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC |
+ SSI_SISR_ROE0 | SSI_SISR_ROE1 |
+ SSI_SISR_TUE0 | SSI_SISR_TUE1,
};
static struct fsl_ssi_soc_data fsl_ssi_imx21 = {
@@ -301,16 +314,16 @@ static struct fsl_ssi_soc_data fsl_ssi_imx21 = {
static struct fsl_ssi_soc_data fsl_ssi_imx35 = {
.imx = true,
.offline_config = true,
- .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC |
- CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
- CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1,
+ .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC |
+ SSI_SISR_ROE0 | SSI_SISR_ROE1 |
+ SSI_SISR_TUE0 | SSI_SISR_TUE1,
};
static struct fsl_ssi_soc_data fsl_ssi_imx51 = {
.imx = true,
.offline_config = false,
- .sisr_write_mask = CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
- CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1,
+ .sisr_write_mask = SSI_SISR_ROE0 | SSI_SISR_ROE1 |
+ SSI_SISR_TUE0 | SSI_SISR_TUE1,
};
static const struct of_device_id fsl_ssi_ids[] = {
@@ -322,108 +335,86 @@ static const struct of_device_id fsl_ssi_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
-static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private)
+static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi)
{
- return (ssi_private->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
+ return (ssi->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
SND_SOC_DAIFMT_AC97;
}
-static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
+static bool fsl_ssi_is_i2s_master(struct fsl_ssi *ssi)
{
- return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+ return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
SND_SOC_DAIFMT_CBS_CFS;
}
-static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
+static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi)
{
- return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+ return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
SND_SOC_DAIFMT_CBM_CFS;
}
+
/**
- * fsl_ssi_isr: SSI interrupt handler
- *
- * Although it's possible to use the interrupt handler to send and receive
- * data to/from the SSI, we use the DMA instead. Programming is more
- * complicated, but the performance is much better.
- *
- * This interrupt handler is used only to gather statistics.
- *
- * @irq: IRQ of the SSI device
- * @dev_id: pointer to the ssi_private structure for this SSI device
+ * Interrupt handler to gather states
*/
static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
{
- struct fsl_ssi_private *ssi_private = dev_id;
- struct regmap *regs = ssi_private->regs;
+ struct fsl_ssi *ssi = dev_id;
+ struct regmap *regs = ssi->regs;
__be32 sisr;
__be32 sisr2;
- /* We got an interrupt, so read the status register to see what we
- were interrupted for. We mask it with the Interrupt Enable register
- so that we only check for events that we're interested in.
- */
- regmap_read(regs, CCSR_SSI_SISR, &sisr);
+ regmap_read(regs, REG_SSI_SISR, &sisr);
- sisr2 = sisr & ssi_private->soc->sisr_write_mask;
+ sisr2 = sisr & ssi->soc->sisr_write_mask;
/* Clear the bits that we set */
if (sisr2)
- regmap_write(regs, CCSR_SSI_SISR, sisr2);
+ regmap_write(regs, REG_SSI_SISR, sisr2);
- fsl_ssi_dbg_isr(&ssi_private->dbg_stats, sisr);
+ fsl_ssi_dbg_isr(&ssi->dbg_stats, sisr);
return IRQ_HANDLED;
}
-/*
- * Enable/Disable all rx/tx config flags at once.
+/**
+ * Enable or disable all rx/tx config flags at once
*/
-static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
- bool enable)
+static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable)
{
- struct regmap *regs = ssi_private->regs;
- struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
+ struct regmap *regs = ssi->regs;
+ struct fsl_ssi_regvals *vals = ssi->regvals;
if (enable) {
- regmap_update_bits(regs, CCSR_SSI_SIER,
- vals->rx.sier | vals->tx.sier,
- vals->rx.sier | vals->tx.sier);
- regmap_update_bits(regs, CCSR_SSI_SRCR,
- vals->rx.srcr | vals->tx.srcr,
- vals->rx.srcr | vals->tx.srcr);
- regmap_update_bits(regs, CCSR_SSI_STCR,
- vals->rx.stcr | vals->tx.stcr,
- vals->rx.stcr | vals->tx.stcr);
+ regmap_update_bits(regs, REG_SSI_SIER,
+ vals[RX].sier | vals[TX].sier,
+ vals[RX].sier | vals[TX].sier);
+ regmap_update_bits(regs, REG_SSI_SRCR,
+ vals[RX].srcr | vals[TX].srcr,
+ vals[RX].srcr | vals[TX].srcr);
+ regmap_update_bits(regs, REG_SSI_STCR,
+ vals[RX].stcr | vals[TX].stcr,
+ vals[RX].stcr | vals[TX].stcr);
} else {
- regmap_update_bits(regs, CCSR_SSI_SRCR,
- vals->rx.srcr | vals->tx.srcr, 0);
- regmap_update_bits(regs, CCSR_SSI_STCR,
- vals->rx.stcr | vals->tx.stcr, 0);
- regmap_update_bits(regs, CCSR_SSI_SIER,
- vals->rx.sier | vals->tx.sier, 0);
+ regmap_update_bits(regs, REG_SSI_SRCR,
+ vals[RX].srcr | vals[TX].srcr, 0);
+ regmap_update_bits(regs, REG_SSI_STCR,
+ vals[RX].stcr | vals[TX].stcr, 0);
+ regmap_update_bits(regs, REG_SSI_SIER,
+ vals[RX].sier | vals[TX].sier, 0);
}
}
-/*
- * Clear RX or TX FIFO to remove samples from the previous
- * stream session which may be still present in the FIFO and
- * may introduce bad samples and/or channel slipping.
- *
- * Note: The SOR is not documented in recent IMX datasheet, but
- * is described in IMX51 reference manual at section 56.3.3.15.
+/**
+ * Clear remaining data in the FIFO to avoid dirty data or channel slipping
*/
-static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private,
- bool is_rx)
+static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx)
{
- if (is_rx) {
- regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR,
- CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR);
- } else {
- regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR,
- CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR);
- }
+ bool tx = !is_rx;
+
+ regmap_update_bits(ssi->regs, REG_SSI_SOR,
+ SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx));
}
-/*
+/**
* Calculate the bits that have to be disabled for the current stream that is
* getting disabled. This keeps the bits enabled that are necessary for the
* second stream to work if 'stream_active' is true.
@@ -443,261 +434,239 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private,
((vals_disable) & \
((vals_disable) ^ ((vals_stream) * (u32)!!(stream_active))))
-/*
- * Enable/Disable a ssi configuration. You have to pass either
- * ssi_private->rxtx_reg_val.rx or tx as vals parameter.
+/**
+ * Enable or disable SSI configuration.
*/
-static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
- struct fsl_ssi_reg_val *vals)
+static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,
+ struct fsl_ssi_regvals *vals)
{
- struct regmap *regs = ssi_private->regs;
- struct fsl_ssi_reg_val *avals;
+ struct regmap *regs = ssi->regs;
+ struct fsl_ssi_regvals *avals;
int nr_active_streams;
- u32 scr_val;
+ u32 scr;
int keep_active;
- regmap_read(regs, CCSR_SSI_SCR, &scr_val);
+ regmap_read(regs, REG_SSI_SCR, &scr);
- nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
- !!(scr_val & CCSR_SSI_SCR_RE);
+ nr_active_streams = !!(scr & SSI_SCR_TE) + !!(scr & SSI_SCR_RE);
if (nr_active_streams - 1 > 0)
keep_active = 1;
else
keep_active = 0;
- /* Find the other direction values rx or tx which we do not want to
- * modify */
- if (&ssi_private->rxtx_reg_val.rx == vals)
- avals = &ssi_private->rxtx_reg_val.tx;
+ /* Get the opposite direction to keep its values untouched */
+ if (&ssi->regvals[RX] == vals)
+ avals = &ssi->regvals[TX];
else
- avals = &ssi_private->rxtx_reg_val.rx;
+ avals = &ssi->regvals[RX];
- /* If vals should be disabled, start with disabling the unit */
if (!enable) {
+ /*
+ * To keep the other stream safe, exclude shared bits between
+ * both streams, and get safe bits to disable current stream
+ */
u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr,
- keep_active);
- regmap_update_bits(regs, CCSR_SSI_SCR, scr, 0);
+ keep_active);
+ /* Safely disable SCR register for the stream */
+ regmap_update_bits(regs, REG_SSI_SCR, scr, 0);
}
/*
- * We are running on a SoC which does not support online SSI
- * reconfiguration, so we have to enable all necessary flags at once
- * even if we do not use them later (capture and playback configuration)
+ * For cases where online configuration is not supported,
+ * 1) Enable all necessary bits of both streams when 1st stream starts
+ * even if the opposite stream will not start
+ * 2) Disable all remaining bits of both streams when last stream ends
*/
- if (ssi_private->soc->offline_config) {
- if ((enable && !nr_active_streams) ||
- (!enable && !keep_active))
- fsl_ssi_rxtx_config(ssi_private, enable);
+ if (ssi->soc->offline_config) {
+ if ((enable && !nr_active_streams) || (!enable && !keep_active))
+ fsl_ssi_rxtx_config(ssi, enable);
goto config_done;
}
- /*
- * Configure single direction units while the SSI unit is running
- * (online configuration)
- */
+ /* Online configure single direction while SSI is running */
if (enable) {
- fsl_ssi_fifo_clear(ssi_private, vals->scr & CCSR_SSI_SCR_RE);
+ fsl_ssi_fifo_clear(ssi, vals->scr & SSI_SCR_RE);
- regmap_update_bits(regs, CCSR_SSI_SRCR, vals->srcr, vals->srcr);
- regmap_update_bits(regs, CCSR_SSI_STCR, vals->stcr, vals->stcr);
- regmap_update_bits(regs, CCSR_SSI_SIER, vals->sier, vals->sier);
+ regmap_update_bits(regs, REG_SSI_SRCR, vals->srcr, vals->srcr);
+ regmap_update_bits(regs, REG_SSI_STCR, vals->stcr, vals->stcr);
+ regmap_update_bits(regs, REG_SSI_SIER, vals->sier, vals->sier);
} else {
u32 sier;
u32 srcr;
u32 stcr;
/*
- * Disabling the necessary flags for one of rx/tx while the
- * other stream is active is a little bit more difficult. We
- * have to disable only those flags that differ between both
- * streams (rx XOR tx) and that are set in the stream that is
- * disabled now. Otherwise we could alter flags of the other
- * stream
+ * To keep the other stream safe, exclude shared bits between
+ * both streams, and get safe bits to disable current stream
*/
-
- /* These assignments are simply vals without bits set in avals*/
sier = fsl_ssi_disable_val(vals->sier, avals->sier,
- keep_active);
+ keep_active);
srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr,
- keep_active);
+ keep_active);
stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr,
- keep_active);
+ keep_active);
- regmap_update_bits(regs, CCSR_SSI_SRCR, srcr, 0);
- regmap_update_bits(regs, CCSR_SSI_STCR, stcr, 0);
- regmap_update_bits(regs, CCSR_SSI_SIER, sier, 0);
+ /* Safely disable other control registers for the stream */
+ regmap_update_bits(regs, REG_SSI_SRCR, srcr, 0);
+ regmap_update_bits(regs, REG_SSI_STCR, stcr, 0);
+ regmap_update_bits(regs, REG_SSI_SIER, sier, 0);
}
config_done:
/* Enabling of subunits is done after configuration */
if (enable) {
- if (ssi_private->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) {
- /*
- * Be sure the Tx FIFO is filled when TE is set.
- * Otherwise, there are some chances to start the
- * playback with some void samples inserted first,
- * generating a channel slip.
- *
- * First, SSIEN must be set, to let the FIFO be filled.
- *
- * Notes:
- * - Limit this fix to the DMA case until FIQ cases can
- * be tested.
- * - Limit the length of the busy loop to not lock the
- * system too long, even if 1-2 loops are sufficient
- * in general.
- */
+ /*
+ * Start DMA before setting TE to avoid FIFO underrun
+ * which may cause a channel slip or a channel swap
+ *
+ * TODO: FIQ cases might also need this upon testing
+ */
+ if (ssi->use_dma && (vals->scr & SSI_SCR_TE)) {
int i;
int max_loop = 100;
- regmap_update_bits(regs, CCSR_SSI_SCR,
- CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN);
+
+ /* Enable SSI first to send TX DMA request */
+ regmap_update_bits(regs, REG_SSI_SCR,
+ SSI_SCR_SSIEN, SSI_SCR_SSIEN);
+
+ /* Busy wait until TX FIFO not empty -- DMA working */
for (i = 0; i < max_loop; i++) {
u32 sfcsr;
- regmap_read(regs, CCSR_SSI_SFCSR, &sfcsr);
- if (CCSR_SSI_SFCSR_TFCNT0(sfcsr))
+ regmap_read(regs, REG_SSI_SFCSR, &sfcsr);
+ if (SSI_SFCSR_TFCNT0(sfcsr))
break;
}
if (i == max_loop) {
- dev_err(ssi_private->dev,
+ dev_err(ssi->dev,
"Timeout waiting TX FIFO filling\n");
}
}
- regmap_update_bits(regs, CCSR_SSI_SCR, vals->scr, vals->scr);
+ /* Enable all remaining bits */
+ regmap_update_bits(regs, REG_SSI_SCR, vals->scr, vals->scr);
}
}
+static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable)
+{
+ fsl_ssi_config(ssi, enable, &ssi->regvals[RX]);
+}
-static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
+static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi)
{
- fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
+ struct regmap *regs = ssi->regs;
+
+ /* no SACC{ST,EN,DIS} regs on imx21-class SSI */
+ if (!ssi->soc->imx21regs) {
+ /* Disable all channel slots */
+ regmap_write(regs, REG_SSI_SACCDIS, 0xff);
+ /* Enable slots 3 & 4 -- PCM Playback Left & Right channels */
+ regmap_write(regs, REG_SSI_SACCEN, 0x300);
+ }
}
-static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
+static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable)
{
- fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
+ /*
+ * SACCST might be modified via AC Link by a CODEC if it sends
+ * extra bits in their SLOTREQ requests, which'll accidentally
+ * send valid data to slots other than normal playback slots.
+ *
+ * To be safe, configure SACCST right before TX starts.
+ */
+ if (enable && fsl_ssi_is_ac97(ssi))
+ fsl_ssi_tx_ac97_saccst_setup(ssi);
+
+ fsl_ssi_config(ssi, enable, &ssi->regvals[TX]);
}
-/*
- * Setup rx/tx register values used to enable/disable the streams. These will
- * be used later in fsl_ssi_config to setup the streams without the need to
- * check for all different SSI modes.
+/**
+ * Cache critical bits of SIER, SRCR, STCR and SCR to later set them safely
*/
-static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private)
+static void fsl_ssi_setup_regvals(struct fsl_ssi *ssi)
{
- struct fsl_ssi_rxtx_reg_val *reg = &ssi_private->rxtx_reg_val;
-
- reg->rx.sier = CCSR_SSI_SIER_RFF0_EN;
- reg->rx.srcr = CCSR_SSI_SRCR_RFEN0;
- reg->rx.scr = 0;
- reg->tx.sier = CCSR_SSI_SIER_TFE0_EN;
- reg->tx.stcr = CCSR_SSI_STCR_TFEN0;
- reg->tx.scr = 0;
-
- if (!fsl_ssi_is_ac97(ssi_private)) {
- reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE;
- reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN;
- reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE;
- reg->tx.sier |= CCSR_SSI_SIER_TFE0_EN;
+ struct fsl_ssi_regvals *vals = ssi->regvals;
+
+ vals[RX].sier = SSI_SIER_RFF0_EN;
+ vals[RX].srcr = SSI_SRCR_RFEN0;
+ vals[RX].scr = 0;
+ vals[TX].sier = SSI_SIER_TFE0_EN;
+ vals[TX].stcr = SSI_STCR_TFEN0;
+ vals[TX].scr = 0;
+
+ /* AC97 has already enabled SSIEN, RE and TE, so ignore them */
+ if (!fsl_ssi_is_ac97(ssi)) {
+ vals[RX].scr = SSI_SCR_SSIEN | SSI_SCR_RE;
+ vals[TX].scr = SSI_SCR_SSIEN | SSI_SCR_TE;
}
- if (ssi_private->use_dma) {
- reg->rx.sier |= CCSR_SSI_SIER_RDMAE;
- reg->tx.sier |= CCSR_SSI_SIER_TDMAE;
+ if (ssi->use_dma) {
+ vals[RX].sier |= SSI_SIER_RDMAE;
+ vals[TX].sier |= SSI_SIER_TDMAE;
} else {
- reg->rx.sier |= CCSR_SSI_SIER_RIE;
- reg->tx.sier |= CCSR_SSI_SIER_TIE;
+ vals[RX].sier |= SSI_SIER_RIE;
+ vals[TX].sier |= SSI_SIER_TIE;
}
- reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS;
- reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS;
+ vals[RX].sier |= FSLSSI_SIER_DBG_RX_FLAGS;
+ vals[TX].sier |= FSLSSI_SIER_DBG_TX_FLAGS;
}
-static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
+static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi)
{
- struct regmap *regs = ssi_private->regs;
+ struct regmap *regs = ssi->regs;
- /*
- * Setup the clock control register
- */
- regmap_write(regs, CCSR_SSI_STCCR,
- CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13));
- regmap_write(regs, CCSR_SSI_SRCCR,
- CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13));
+ /* Setup the clock control register */
+ regmap_write(regs, REG_SSI_STCCR, SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13));
+ regmap_write(regs, REG_SSI_SRCCR, SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13));
- /*
- * Enable AC97 mode and startup the SSI
- */
- regmap_write(regs, CCSR_SSI_SACNT,
- CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV);
-
- /* no SACC{ST,EN,DIS} regs on imx21-class SSI */
- if (!ssi_private->soc->imx21regs) {
- regmap_write(regs, CCSR_SSI_SACCDIS, 0xff);
- regmap_write(regs, CCSR_SSI_SACCEN, 0x300);
- }
+ /* Enable AC97 mode and startup the SSI */
+ regmap_write(regs, REG_SSI_SACNT, SSI_SACNT_AC97EN | SSI_SACNT_FV);
- /*
- * Enable SSI, Transmit and Receive. AC97 has to communicate with the
- * codec before a stream is started.
- */
- regmap_update_bits(regs, CCSR_SSI_SCR,
- CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE,
- CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
+ /* AC97 has to communicate with codec before starting a stream */
+ regmap_update_bits(regs, REG_SSI_SCR,
+ SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE,
+ SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE);
- regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_WAIT(3));
+ regmap_write(regs, REG_SSI_SOR, SSI_SOR_WAIT(3));
}
-/**
- * fsl_ssi_startup: create a new substream
- *
- * This is the first function called when a stream is opened.
- *
- * If this is the first stream open, then grab the IRQ and program most of
- * the SSI registers.
- */
static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private =
- snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai);
int ret;
- ret = clk_prepare_enable(ssi_private->clk);
+ ret = clk_prepare_enable(ssi->clk);
if (ret)
return ret;
- /* When using dual fifo mode, it is safer to ensure an even period
+ /*
+ * When using dual fifo mode, it is safer to ensure an even period
* size. If appearing to an odd number while DMA always starts its
* task from fifo0, fifo1 would be neglected at the end of each
* period. But SSI would still access fifo1 with an invalid data.
*/
- if (ssi_private->use_dual_fifo)
+ if (ssi->use_dual_fifo)
snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
return 0;
}
-/**
- * fsl_ssi_shutdown: shutdown the SSI
- *
- */
static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private =
- snd_soc_dai_get_drvdata(rtd->cpu_dai);
-
- clk_disable_unprepare(ssi_private->clk);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ clk_disable_unprepare(ssi->clk);
}
/**
- * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
+ * Configure Digital Audio Interface bit clock
*
* Note: This function can be only called when using SSI as DAI master
*
@@ -706,12 +675,13 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
* (In 2-channel I2S Master mode, slot_width is fixed 32)
*/
static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
- struct snd_soc_dai *cpu_dai,
- struct snd_pcm_hw_params *hw_params)
+ struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *hw_params)
{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
- struct regmap *regs = ssi_private->regs;
- int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
+ bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
+ struct regmap *regs = ssi->regs;
+ int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret;
u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
unsigned long clkrate, baudrate, tmprate;
unsigned int slots = params_channels(hw_params);
@@ -721,29 +691,29 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
bool baudclk_is_used;
/* Override slots and slot_width if being specifically set... */
- if (ssi_private->slots)
- slots = ssi_private->slots;
+ if (ssi->slots)
+ slots = ssi->slots;
/* ...but keep 32 bits if slots is 2 -- I2S Master mode */
- if (ssi_private->slot_width && slots != 2)
- slot_width = ssi_private->slot_width;
+ if (ssi->slot_width && slots != 2)
+ slot_width = ssi->slot_width;
/* Generate bit clock based on the slot number and slot width */
freq = slots * slot_width * params_rate(hw_params);
/* Don't apply it to any non-baudclk circumstance */
- if (IS_ERR(ssi_private->baudclk))
+ if (IS_ERR(ssi->baudclk))
return -EINVAL;
/*
* Hardware limitation: The bclk rate must be
* never greater than 1/5 IPG clock rate
*/
- if (freq * 5 > clk_get_rate(ssi_private->clk)) {
- dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n");
+ if (freq * 5 > clk_get_rate(ssi->clk)) {
+ dev_err(dai->dev, "bitclk > ipgclk / 5\n");
return -EINVAL;
}
- baudclk_is_used = ssi_private->baudclk_streams & ~(BIT(substream->stream));
+ baudclk_is_used = ssi->baudclk_streams & ~(BIT(substream->stream));
/* It should be already enough to divide clock by setting pm alone */
psr = 0;
@@ -755,9 +725,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
tmprate = freq * factor * (i + 1);
if (baudclk_is_used)
- clkrate = clk_get_rate(ssi_private->baudclk);
+ clkrate = clk_get_rate(ssi->baudclk);
else
- clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
+ clkrate = clk_round_rate(ssi->baudclk, tmprate);
clkrate /= factor;
afreq = clkrate / (i + 1);
@@ -788,24 +758,22 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
/* No proper pm found if it is still remaining the initial value */
if (pm == 999) {
- dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
+ dev_err(dai->dev, "failed to handle the required sysclk\n");
return -EINVAL;
}
- stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
- (psr ? CCSR_SSI_SxCCR_PSR : 0);
- mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 |
- CCSR_SSI_SxCCR_PSR;
+ stccr = SSI_SxCCR_PM(pm + 1) | (div2 ? SSI_SxCCR_DIV2 : 0) |
+ (psr ? SSI_SxCCR_PSR : 0);
+ mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous)
- regmap_update_bits(regs, CCSR_SSI_STCCR, mask, stccr);
- else
- regmap_update_bits(regs, CCSR_SSI_SRCCR, mask, stccr);
+ /* STCCR is used for RX in synchronous mode */
+ tx2 = tx || synchronous;
+ regmap_update_bits(regs, REG_SSI_SxCCR(tx2), mask, stccr);
if (!baudclk_is_used) {
- ret = clk_set_rate(ssi_private->baudclk, baudrate);
+ ret = clk_set_rate(ssi->baudclk, baudrate);
if (ret) {
- dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
+ dev_err(dai->dev, "failed to set baudclk rate\n");
return -EINVAL;
}
}
@@ -814,185 +782,165 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
}
/**
- * fsl_ssi_hw_params - program the sample size
- *
- * Most of the SSI registers have been programmed in the startup function,
- * but the word length must be programmed here. Unfortunately, programming
- * the SxCCR.WL bits requires the SSI to be temporarily disabled. This can
- * cause a problem with supporting simultaneous playback and capture. If
- * the SSI is already playing a stream, then that stream may be temporarily
- * stopped when you start capture.
+ * Configure SSI based on PCM hardware parameters
*
- * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
- * clock master.
+ * Notes:
+ * 1) SxCCR.WL bits are critical bits that require SSI to be temporarily
+ * disabled on offline_config SoCs. Even for online configurable SoCs
+ * running in synchronous mode (both TX and RX use STCCR), it is not
+ * safe to re-configure them when both two streams start running.
+ * 2) SxCCR.PM, SxCCR.DIV2 and SxCCR.PSR bits will be configured in the
+ * fsl_ssi_set_bclk() if SSI is the DAI clock master.
*/
static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai)
{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
- struct regmap *regs = ssi_private->regs;
+ bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
+ struct regmap *regs = ssi->regs;
unsigned int channels = params_channels(hw_params);
unsigned int sample_size = params_width(hw_params);
- u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
+ u32 wl = SSI_SxCCR_WL(sample_size);
int ret;
- u32 scr_val;
+ u32 scr;
int enabled;
- regmap_read(regs, CCSR_SSI_SCR, &scr_val);
- enabled = scr_val & CCSR_SSI_SCR_SSIEN;
+ regmap_read(regs, REG_SSI_SCR, &scr);
+ enabled = scr & SSI_SCR_SSIEN;
/*
- * If we're in synchronous mode, and the SSI is already enabled,
- * then STCCR is already set properly.
+ * SSI is properly configured if it is enabled and running in
+ * the synchronous mode; Note that AC97 mode is an exception
+ * that should set separate configurations for STCCR and SRCCR
+ * despite running in the synchronous mode.
*/
- if (enabled && ssi_private->cpu_dai_drv.symmetric_rates)
+ if (enabled && ssi->cpu_dai_drv.symmetric_rates)
return 0;
- if (fsl_ssi_is_i2s_master(ssi_private)) {
- ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params);
+ if (fsl_ssi_is_i2s_master(ssi)) {
+ ret = fsl_ssi_set_bclk(substream, dai, hw_params);
if (ret)
return ret;
/* Do not enable the clock if it is already enabled */
- if (!(ssi_private->baudclk_streams & BIT(substream->stream))) {
- ret = clk_prepare_enable(ssi_private->baudclk);
+ if (!(ssi->baudclk_streams & BIT(substream->stream))) {
+ ret = clk_prepare_enable(ssi->baudclk);
if (ret)
return ret;
- ssi_private->baudclk_streams |= BIT(substream->stream);
+ ssi->baudclk_streams |= BIT(substream->stream);
}
}
- if (!fsl_ssi_is_ac97(ssi_private)) {
- u8 i2smode;
- /*
- * Switch to normal net mode in order to have a frame sync
- * signal every 32 bits instead of 16 bits
- */
- if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16)
- i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL |
- CCSR_SSI_SCR_NET;
+ if (!fsl_ssi_is_ac97(ssi)) {
+ u8 i2s_net;
+ /* Normal + Network mode to send 16-bit data in 32-bit frames */
+ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16)
+ i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET;
else
- i2smode = ssi_private->i2s_mode;
+ i2s_net = ssi->i2s_net;
- regmap_update_bits(regs, CCSR_SSI_SCR,
- CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
- channels == 1 ? 0 : i2smode);
+ regmap_update_bits(regs, REG_SSI_SCR,
+ SSI_SCR_I2S_NET_MASK,
+ channels == 1 ? 0 : i2s_net);
}
- /*
- * FIXME: The documentation says that SxCCR[WL] should not be
- * modified while the SSI is enabled. The only time this can
- * happen is if we're trying to do simultaneous playback and
- * capture in asynchronous mode. Unfortunately, I have been enable
- * to get that to work at all on the P1022DS. Therefore, we don't
- * bother to disable/enable the SSI when setting SxCCR[WL], because
- * the SSI will stop anyway. Maybe one day, this will get fixed.
- */
-
/* In synchronous mode, the SSI uses STCCR for capture */
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
- ssi_private->cpu_dai_drv.symmetric_rates)
- regmap_update_bits(regs, CCSR_SSI_STCCR, CCSR_SSI_SxCCR_WL_MASK,
- wl);
- else
- regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK,
- wl);
+ tx2 = tx || ssi->cpu_dai_drv.symmetric_rates;
+ regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl);
return 0;
}
static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *cpu_dai)
+ struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private =
- snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- if (fsl_ssi_is_i2s_master(ssi_private) &&
- ssi_private->baudclk_streams & BIT(substream->stream)) {
- clk_disable_unprepare(ssi_private->baudclk);
- ssi_private->baudclk_streams &= ~BIT(substream->stream);
+ if (fsl_ssi_is_i2s_master(ssi) &&
+ ssi->baudclk_streams & BIT(substream->stream)) {
+ clk_disable_unprepare(ssi->baudclk);
+ ssi->baudclk_streams &= ~BIT(substream->stream);
}
return 0;
}
static int _fsl_ssi_set_dai_fmt(struct device *dev,
- struct fsl_ssi_private *ssi_private,
- unsigned int fmt)
+ struct fsl_ssi *ssi, unsigned int fmt)
{
- struct regmap *regs = ssi_private->regs;
+ struct regmap *regs = ssi->regs;
u32 strcr = 0, stcr, srcr, scr, mask;
u8 wm;
- ssi_private->dai_fmt = fmt;
+ ssi->dai_fmt = fmt;
- if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) {
- dev_err(dev, "baudclk is missing which is necessary for master mode\n");
+ if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) {
+ dev_err(dev, "missing baudclk for master mode\n");
return -EINVAL;
}
- fsl_ssi_setup_reg_vals(ssi_private);
+ fsl_ssi_setup_regvals(ssi);
- regmap_read(regs, CCSR_SSI_SCR, &scr);
- scr &= ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
- scr |= CCSR_SSI_SCR_SYNC_TX_FS;
+ regmap_read(regs, REG_SSI_SCR, &scr);
+ scr &= ~(SSI_SCR_SYN | SSI_SCR_I2S_MODE_MASK);
+ /* Synchronize frame sync clock for TE to avoid data slipping */
+ scr |= SSI_SCR_SYNC_TX_FS;
- mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
- CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
- CCSR_SSI_STCR_TEFS;
- regmap_read(regs, CCSR_SSI_STCR, &stcr);
- regmap_read(regs, CCSR_SSI_SRCR, &srcr);
+ mask = SSI_STCR_TXBIT0 | SSI_STCR_TFDIR | SSI_STCR_TXDIR |
+ SSI_STCR_TSCKP | SSI_STCR_TFSI | SSI_STCR_TFSL | SSI_STCR_TEFS;
+ regmap_read(regs, REG_SSI_STCR, &stcr);
+ regmap_read(regs, REG_SSI_SRCR, &srcr);
stcr &= ~mask;
srcr &= ~mask;
- ssi_private->i2s_mode = CCSR_SSI_SCR_NET;
+ /* Use Network mode as default */
+ ssi->i2s_net = SSI_SCR_NET;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- regmap_update_bits(regs, CCSR_SSI_STCCR,
- CCSR_SSI_SxCCR_DC_MASK,
- CCSR_SSI_SxCCR_DC(2));
- regmap_update_bits(regs, CCSR_SSI_SRCCR,
- CCSR_SSI_SxCCR_DC_MASK,
- CCSR_SSI_SxCCR_DC(2));
+ regmap_update_bits(regs, REG_SSI_STCCR,
+ SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2));
+ regmap_update_bits(regs, REG_SSI_SRCCR,
+ SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2));
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFS:
- ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
+ ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE;
+ ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE;
break;
default:
return -EINVAL;
}
/* Data on rising edge of bclk, frame low, 1clk before data */
- strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
- CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
+ strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP |
+ SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
break;
case SND_SOC_DAIFMT_LEFT_J:
/* Data on rising edge of bclk, frame high */
- strcr |= CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TSCKP;
+ strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP;
break;
case SND_SOC_DAIFMT_DSP_A:
/* Data on rising edge of bclk, frame high, 1clk before data */
- strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
- CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
+ strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |
+ SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
break;
case SND_SOC_DAIFMT_DSP_B:
/* Data on rising edge of bclk, frame high */
- strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
- CCSR_SSI_STCR_TXBIT0;
+ strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | SSI_STCR_TXBIT0;
break;
case SND_SOC_DAIFMT_AC97:
- ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL;
+ /* Data on falling edge of bclk, frame high, 1clk before data */
+ ssi->i2s_net |= SSI_SCR_I2S_MODE_NORMAL;
break;
default:
return -EINVAL;
}
- scr |= ssi_private->i2s_mode;
+ scr |= ssi->i2s_net;
/* DAI clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -1001,16 +949,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
break;
case SND_SOC_DAIFMT_IB_NF:
/* Invert bit clock */
- strcr ^= CCSR_SSI_STCR_TSCKP;
+ strcr ^= SSI_STCR_TSCKP;
break;
case SND_SOC_DAIFMT_NB_IF:
/* Invert frame clock */
- strcr ^= CCSR_SSI_STCR_TFSI;
+ strcr ^= SSI_STCR_TFSI;
break;
case SND_SOC_DAIFMT_IB_IF:
/* Invert both clocks */
- strcr ^= CCSR_SSI_STCR_TSCKP;
- strcr ^= CCSR_SSI_STCR_TFSI;
+ strcr ^= SSI_STCR_TSCKP;
+ strcr ^= SSI_STCR_TFSI;
break;
default:
return -EINVAL;
@@ -1019,123 +967,122 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
/* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR;
- scr |= CCSR_SSI_SCR_SYS_CLK_EN;
+ /* Output bit and frame sync clocks */
+ strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
+ scr |= SSI_SCR_SYS_CLK_EN;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+ /* Input bit or frame sync clocks */
+ scr &= ~SSI_SCR_SYS_CLK_EN;
break;
case SND_SOC_DAIFMT_CBM_CFS:
- strcr &= ~CCSR_SSI_STCR_TXDIR;
- strcr |= CCSR_SSI_STCR_TFDIR;
- scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+ /* Input bit clock but output frame sync clock */
+ strcr &= ~SSI_STCR_TXDIR;
+ strcr |= SSI_STCR_TFDIR;
+ scr &= ~SSI_SCR_SYS_CLK_EN;
break;
default:
- if (!fsl_ssi_is_ac97(ssi_private))
+ if (!fsl_ssi_is_ac97(ssi))
return -EINVAL;
}
stcr |= strcr;
srcr |= strcr;
- if (ssi_private->cpu_dai_drv.symmetric_rates
- || fsl_ssi_is_ac97(ssi_private)) {
- /* Need to clear RXDIR when using SYNC or AC97 mode */
- srcr &= ~CCSR_SSI_SRCR_RXDIR;
- scr |= CCSR_SSI_SCR_SYN;
+ /* Set SYN mode and clear RXDIR bit when using SYN or AC97 mode */
+ if (ssi->cpu_dai_drv.symmetric_rates || fsl_ssi_is_ac97(ssi)) {
+ srcr &= ~SSI_SRCR_RXDIR;
+ scr |= SSI_SCR_SYN;
}
- regmap_write(regs, CCSR_SSI_STCR, stcr);
- regmap_write(regs, CCSR_SSI_SRCR, srcr);
- regmap_write(regs, CCSR_SSI_SCR, scr);
+ regmap_write(regs, REG_SSI_STCR, stcr);
+ regmap_write(regs, REG_SSI_SRCR, srcr);
+ regmap_write(regs, REG_SSI_SCR, scr);
- wm = ssi_private->fifo_watermark;
+ wm = ssi->fifo_watermark;
- regmap_write(regs, CCSR_SSI_SFCSR,
- CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
- CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm));
+ regmap_write(regs, REG_SSI_SFCSR,
+ SSI_SFCSR_TFWM0(wm) | SSI_SFCSR_RFWM0(wm) |
+ SSI_SFCSR_TFWM1(wm) | SSI_SFCSR_RFWM1(wm));
- if (ssi_private->use_dual_fifo) {
- regmap_update_bits(regs, CCSR_SSI_SRCR, CCSR_SSI_SRCR_RFEN1,
- CCSR_SSI_SRCR_RFEN1);
- regmap_update_bits(regs, CCSR_SSI_STCR, CCSR_SSI_STCR_TFEN1,
- CCSR_SSI_STCR_TFEN1);
- regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_TCH_EN,
- CCSR_SSI_SCR_TCH_EN);
+ if (ssi->use_dual_fifo) {
+ regmap_update_bits(regs, REG_SSI_SRCR,
+ SSI_SRCR_RFEN1, SSI_SRCR_RFEN1);
+ regmap_update_bits(regs, REG_SSI_STCR,
+ SSI_STCR_TFEN1, SSI_STCR_TFEN1);
+ regmap_update_bits(regs, REG_SSI_SCR,
+ SSI_SCR_TCH_EN, SSI_SCR_TCH_EN);
}
if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97)
- fsl_ssi_setup_ac97(ssi_private);
+ fsl_ssi_setup_ac97(ssi);
return 0;
-
}
/**
- * fsl_ssi_set_dai_fmt - configure Digital Audio Interface Format.
+ * Configure Digital Audio Interface (DAI) Format
*/
-static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
+
+ /* AC97 configured DAIFMT earlier in the probe() */
+ if (fsl_ssi_is_ac97(ssi))
+ return 0;
- return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt);
+ return _fsl_ssi_set_dai_fmt(dai->dev, ssi, fmt);
}
/**
- * fsl_ssi_set_dai_tdm_slot - set TDM slot number
- *
- * Note: This function can be only called when using SSI as DAI master
+ * Set TDM slot number and slot width
*/
-static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
- u32 rx_mask, int slots, int slot_width)
+static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
- struct regmap *regs = ssi_private->regs;
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
+ struct regmap *regs = ssi->regs;
u32 val;
/* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */
if (slot_width & 1 || slot_width < 8 || slot_width > 24) {
- dev_err(cpu_dai->dev, "invalid slot width: %d\n", slot_width);
+ dev_err(dai->dev, "invalid slot width: %d\n", slot_width);
return -EINVAL;
}
/* The slot number should be >= 2 if using Network mode or I2S mode */
- regmap_read(regs, CCSR_SSI_SCR, &val);
- val &= CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET;
+ regmap_read(regs, REG_SSI_SCR, &val);
+ val &= SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET;
if (val && slots < 2) {
- dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n");
+ dev_err(dai->dev, "slot number should be >= 2 in I2S or NET\n");
return -EINVAL;
}
- regmap_update_bits(regs, CCSR_SSI_STCCR, CCSR_SSI_SxCCR_DC_MASK,
- CCSR_SSI_SxCCR_DC(slots));
- regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_DC_MASK,
- CCSR_SSI_SxCCR_DC(slots));
+ regmap_update_bits(regs, REG_SSI_STCCR,
+ SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots));
+ regmap_update_bits(regs, REG_SSI_SRCCR,
+ SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots));
- /* The register SxMSKs needs SSI to provide essential clock due to
- * hardware design. So we here temporarily enable SSI to set them.
- */
- regmap_read(regs, CCSR_SSI_SCR, &val);
- val &= CCSR_SSI_SCR_SSIEN;
- regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN,
- CCSR_SSI_SCR_SSIEN);
+ /* Save SSIEN bit of the SCR register */
+ regmap_read(regs, REG_SSI_SCR, &val);
+ val &= SSI_SCR_SSIEN;
+ /* Temporarily enable SSI to allow SxMSKs to be configurable */
+ regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, SSI_SCR_SSIEN);
- regmap_write(regs, CCSR_SSI_STMSK, ~tx_mask);
- regmap_write(regs, CCSR_SSI_SRMSK, ~rx_mask);
+ regmap_write(regs, REG_SSI_STMSK, ~tx_mask);
+ regmap_write(regs, REG_SSI_SRMSK, ~rx_mask);
- regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val);
+ /* Restore the value of SSIEN bit */
+ regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, val);
- ssi_private->slot_width = slot_width;
- ssi_private->slots = slots;
+ ssi->slot_width = slot_width;
+ ssi->slots = slots;
return 0;
}
/**
- * fsl_ssi_trigger: start and stop the DMA transfer.
- *
- * This function is called by ALSA to start, stop, pause, and resume the DMA
- * transfer of data.
+ * Start or stop SSI and corresponding DMA transaction.
*
* The DMA channel is in external master start and pause mode, which
* means the SSI completely controls the flow of data.
@@ -1144,37 +1091,38 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- struct regmap *regs = ssi_private->regs;
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct regmap *regs = ssi->regs;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fsl_ssi_tx_config(ssi_private, true);
+ fsl_ssi_tx_config(ssi, true);
else
- fsl_ssi_rx_config(ssi_private, true);
+ fsl_ssi_rx_config(ssi, true);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fsl_ssi_tx_config(ssi_private, false);
+ fsl_ssi_tx_config(ssi, false);
else
- fsl_ssi_rx_config(ssi_private, false);
+ fsl_ssi_rx_config(ssi, false);
break;
default:
return -EINVAL;
}
- if (fsl_ssi_is_ac97(ssi_private)) {
+ /* Clear corresponding FIFO */
+ if (fsl_ssi_is_ac97(ssi)) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR);
+ regmap_write(regs, REG_SSI_SOR, SSI_SOR_TX_CLR);
else
- regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_RX_CLR);
+ regmap_write(regs, REG_SSI_SOR, SSI_SOR_RX_CLR);
}
return 0;
@@ -1182,27 +1130,26 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
- if (ssi_private->soc->imx && ssi_private->use_dma) {
- dai->playback_dma_data = &ssi_private->dma_params_tx;
- dai->capture_dma_data = &ssi_private->dma_params_rx;
+ if (ssi->soc->imx && ssi->use_dma) {
+ dai->playback_dma_data = &ssi->dma_params_tx;
+ dai->capture_dma_data = &ssi->dma_params_rx;
}
return 0;
}
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
- .startup = fsl_ssi_startup,
- .shutdown = fsl_ssi_shutdown,
- .hw_params = fsl_ssi_hw_params,
- .hw_free = fsl_ssi_hw_free,
- .set_fmt = fsl_ssi_set_dai_fmt,
- .set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
- .trigger = fsl_ssi_trigger,
+ .startup = fsl_ssi_startup,
+ .shutdown = fsl_ssi_shutdown,
+ .hw_params = fsl_ssi_hw_params,
+ .hw_free = fsl_ssi_hw_free,
+ .set_fmt = fsl_ssi_set_dai_fmt,
+ .set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
+ .trigger = fsl_ssi_trigger,
};
-/* Template for the CPU dai driver structure */
static struct snd_soc_dai_driver fsl_ssi_dai_template = {
.probe = fsl_ssi_dai_probe,
.playback = {
@@ -1223,7 +1170,7 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
};
static const struct snd_soc_component_driver fsl_ssi_component = {
- .name = "fsl-ssi",
+ .name = "fsl-ssi",
};
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
@@ -1234,23 +1181,23 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20,
},
.capture = {
.stream_name = "AC97 Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ /* 16-bit capture is broken (errata ERR003778) */
+ .formats = SNDRV_PCM_FMTBIT_S20,
},
.ops = &fsl_ssi_dai_ops,
};
-
-static struct fsl_ssi_private *fsl_ac97_data;
+static struct fsl_ssi *fsl_ac97_data;
static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
- unsigned short val)
+ unsigned short val)
{
struct regmap *regs = fsl_ac97_data->regs;
unsigned int lreg;
@@ -1260,61 +1207,68 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
if (reg > 0x7f)
return;
+ mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 write clk_prepare_enable failed: %d\n",
ret);
- return;
+ goto ret_unlock;
}
lreg = reg << 12;
- regmap_write(regs, CCSR_SSI_SACADD, lreg);
+ regmap_write(regs, REG_SSI_SACADD, lreg);
lval = val << 4;
- regmap_write(regs, CCSR_SSI_SACDAT, lval);
+ regmap_write(regs, REG_SSI_SACDAT, lval);
- regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK,
- CCSR_SSI_SACNT_WR);
+ regmap_update_bits(regs, REG_SSI_SACNT,
+ SSI_SACNT_RDWR_MASK, SSI_SACNT_WR);
udelay(100);
clk_disable_unprepare(fsl_ac97_data->clk);
+
+ret_unlock:
+ mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
- unsigned short reg)
+ unsigned short reg)
{
struct regmap *regs = fsl_ac97_data->regs;
-
- unsigned short val = -1;
+ unsigned short val = 0;
u32 reg_val;
unsigned int lreg;
int ret;
+ mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
- pr_err("ac97 read clk_prepare_enable failed: %d\n",
- ret);
- return -1;
+ pr_err("ac97 read clk_prepare_enable failed: %d\n", ret);
+ goto ret_unlock;
}
lreg = (reg & 0x7f) << 12;
- regmap_write(regs, CCSR_SSI_SACADD, lreg);
- regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK,
- CCSR_SSI_SACNT_RD);
+ regmap_write(regs, REG_SSI_SACADD, lreg);
+ regmap_update_bits(regs, REG_SSI_SACNT,
+ SSI_SACNT_RDWR_MASK, SSI_SACNT_RD);
udelay(100);
- regmap_read(regs, CCSR_SSI_SACDAT, &reg_val);
+ regmap_read(regs, REG_SSI_SACDAT, &reg_val);
val = (reg_val >> 4) & 0xffff;
clk_disable_unprepare(fsl_ac97_data->clk);
+ret_unlock:
+ mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
return val;
}
static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
- .read = fsl_ssi_ac97_read,
- .write = fsl_ssi_ac97_write,
+ .read = fsl_ssi_ac97_read,
+ .write = fsl_ssi_ac97_write,
};
/**
@@ -1329,70 +1283,67 @@ static void make_lowercase(char *s)
}
static int fsl_ssi_imx_probe(struct platform_device *pdev,
- struct fsl_ssi_private *ssi_private, void __iomem *iomem)
+ struct fsl_ssi *ssi, void __iomem *iomem)
{
struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
u32 dmas[4];
int ret;
- if (ssi_private->has_ipg_clk_name)
- ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
+ /* Backward compatible for a DT without ipg clock name assigned */
+ if (ssi->has_ipg_clk_name)
+ ssi->clk = devm_clk_get(dev, "ipg");
else
- ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(ssi_private->clk)) {
- ret = PTR_ERR(ssi_private->clk);
- dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+ ssi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ssi->clk)) {
+ ret = PTR_ERR(ssi->clk);
+ dev_err(dev, "failed to get clock: %d\n", ret);
return ret;
}
- if (!ssi_private->has_ipg_clk_name) {
- ret = clk_prepare_enable(ssi_private->clk);
+ /* Enable the clock since regmap will not handle it in this case */
+ if (!ssi->has_ipg_clk_name) {
+ ret = clk_prepare_enable(ssi->clk);
if (ret) {
- dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+ dev_err(dev, "clk_prepare_enable failed: %d\n", ret);
return ret;
}
}
- /* For those SLAVE implementations, we ignore non-baudclk cases
- * and, instead, abandon MASTER mode that needs baud clock.
- */
- ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
- if (IS_ERR(ssi_private->baudclk))
- dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
- PTR_ERR(ssi_private->baudclk));
+ /* Do not error out for slave cases that live without a baud clock */
+ ssi->baudclk = devm_clk_get(dev, "baud");
+ if (IS_ERR(ssi->baudclk))
+ dev_dbg(dev, "failed to get baud clock: %ld\n",
+ PTR_ERR(ssi->baudclk));
- ssi_private->dma_params_tx.maxburst = ssi_private->dma_maxburst;
- ssi_private->dma_params_rx.maxburst = ssi_private->dma_maxburst;
- ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
- ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
+ ssi->dma_params_tx.maxburst = ssi->dma_maxburst;
+ ssi->dma_params_rx.maxburst = ssi->dma_maxburst;
+ ssi->dma_params_tx.addr = ssi->ssi_phys + REG_SSI_STX0;
+ ssi->dma_params_rx.addr = ssi->ssi_phys + REG_SSI_SRX0;
+ /* Set to dual FIFO mode according to the SDMA sciprt */
ret = of_property_read_u32_array(np, "dmas", dmas, 4);
- if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
- ssi_private->use_dual_fifo = true;
- /* When using dual fifo mode, we need to keep watermark
- * as even numbers due to dma script limitation.
+ if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
+ ssi->use_dual_fifo = true;
+ /*
+ * Use even numbers to avoid channel swap due to SDMA
+ * script design
*/
- ssi_private->dma_params_tx.maxburst &= ~0x1;
- ssi_private->dma_params_rx.maxburst &= ~0x1;
+ ssi->dma_params_tx.maxburst &= ~0x1;
+ ssi->dma_params_rx.maxburst &= ~0x1;
}
- if (!ssi_private->use_dma) {
-
+ if (!ssi->use_dma) {
/*
- * Some boards use an incompatible codec. To get it
- * working, we are using imx-fiq-pcm-audio, that
- * can handle those codecs. DMA is not possible in this
- * situation.
+ * Some boards use an incompatible codec. Use imx-fiq-pcm-audio
+ * to get it working, as DMA is not possible in this situation.
*/
+ ssi->fiq_params.irq = ssi->irq;
+ ssi->fiq_params.base = iomem;
+ ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
+ ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
- ssi_private->fiq_params.irq = ssi_private->irq;
- ssi_private->fiq_params.base = iomem;
- ssi_private->fiq_params.dma_params_rx =
- &ssi_private->dma_params_rx;
- ssi_private->fiq_params.dma_params_tx =
- &ssi_private->dma_params_tx;
-
- ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
+ ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
if (ret)
goto error_pcm;
} else {
@@ -1404,26 +1355,26 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
return 0;
error_pcm:
+ if (!ssi->has_ipg_clk_name)
+ clk_disable_unprepare(ssi->clk);
- if (!ssi_private->has_ipg_clk_name)
- clk_disable_unprepare(ssi_private->clk);
return ret;
}
-static void fsl_ssi_imx_clean(struct platform_device *pdev,
- struct fsl_ssi_private *ssi_private)
+static void fsl_ssi_imx_clean(struct platform_device *pdev, struct fsl_ssi *ssi)
{
- if (!ssi_private->use_dma)
+ if (!ssi->use_dma)
imx_pcm_fiq_exit(pdev);
- if (!ssi_private->has_ipg_clk_name)
- clk_disable_unprepare(ssi_private->clk);
+ if (!ssi->has_ipg_clk_name)
+ clk_disable_unprepare(ssi->clk);
}
static int fsl_ssi_probe(struct platform_device *pdev)
{
- struct fsl_ssi_private *ssi_private;
+ struct fsl_ssi *ssi;
int ret = 0;
struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
const char *p, *sprop;
const uint32_t *iprop;
@@ -1432,182 +1383,159 @@ static int fsl_ssi_probe(struct platform_device *pdev)
char name[64];
struct regmap_config regconfig = fsl_ssi_regconfig;
- of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
+ of_id = of_match_device(fsl_ssi_ids, dev);
if (!of_id || !of_id->data)
return -EINVAL;
- ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private),
- GFP_KERNEL);
- if (!ssi_private)
+ ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL);
+ if (!ssi)
return -ENOMEM;
- ssi_private->soc = of_id->data;
- ssi_private->dev = &pdev->dev;
+ ssi->soc = of_id->data;
+ ssi->dev = dev;
+ /* Check if being used in AC97 mode */
sprop = of_get_property(np, "fsl,mode", NULL);
if (sprop) {
if (!strcmp(sprop, "ac97-slave"))
- ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97;
+ ssi->dai_fmt = SND_SOC_DAIFMT_AC97;
}
- ssi_private->use_dma = !of_property_read_bool(np,
- "fsl,fiq-stream-filter");
-
- if (fsl_ssi_is_ac97(ssi_private)) {
- memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai,
- sizeof(fsl_ssi_ac97_dai));
-
- fsl_ac97_data = ssi_private;
+ /* Select DMA or FIQ */
+ ssi->use_dma = !of_property_read_bool(np, "fsl,fiq-stream-filter");
- ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
- if (ret) {
- dev_err(&pdev->dev, "could not set AC'97 ops\n");
- return ret;
- }
+ if (fsl_ssi_is_ac97(ssi)) {
+ memcpy(&ssi->cpu_dai_drv, &fsl_ssi_ac97_dai,
+ sizeof(fsl_ssi_ac97_dai));
+ fsl_ac97_data = ssi;
} else {
- /* Initialize this copy of the CPU DAI driver structure */
- memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+ memcpy(&ssi->cpu_dai_drv, &fsl_ssi_dai_template,
sizeof(fsl_ssi_dai_template));
}
- ssi_private->cpu_dai_drv.name = dev_name(&pdev->dev);
+ ssi->cpu_dai_drv.name = dev_name(dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- iomem = devm_ioremap_resource(&pdev->dev, res);
+ iomem = devm_ioremap_resource(dev, res);
if (IS_ERR(iomem))
return PTR_ERR(iomem);
- ssi_private->ssi_phys = res->start;
+ ssi->ssi_phys = res->start;
- if (ssi_private->soc->imx21regs) {
- /*
- * According to datasheet imx21-class SSI
- * don't have SACC{ST,EN,DIS} regs.
- */
- regconfig.max_register = CCSR_SSI_SRMSK;
+ if (ssi->soc->imx21regs) {
+ /* No SACC{ST,EN,DIS} regs in imx21-class SSI */
+ regconfig.max_register = REG_SSI_SRMSK;
regconfig.num_reg_defaults_raw =
- CCSR_SSI_SRMSK / sizeof(uint32_t) + 1;
+ REG_SSI_SRMSK / sizeof(uint32_t) + 1;
}
ret = of_property_match_string(np, "clock-names", "ipg");
if (ret < 0) {
- ssi_private->has_ipg_clk_name = false;
- ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
- &regconfig);
+ ssi->has_ipg_clk_name = false;
+ ssi->regs = devm_regmap_init_mmio(dev, iomem, &regconfig);
} else {
- ssi_private->has_ipg_clk_name = true;
- ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
- "ipg", iomem, &regconfig);
+ ssi->has_ipg_clk_name = true;
+ ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem,
+ &regconfig);
}
- if (IS_ERR(ssi_private->regs)) {
- dev_err(&pdev->dev, "Failed to init register map\n");
- return PTR_ERR(ssi_private->regs);
+ if (IS_ERR(ssi->regs)) {
+ dev_err(dev, "failed to init register map\n");
+ return PTR_ERR(ssi->regs);
}
- ssi_private->irq = platform_get_irq(pdev, 0);
- if (ssi_private->irq < 0) {
- dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
- return ssi_private->irq;
+ ssi->irq = platform_get_irq(pdev, 0);
+ if (ssi->irq < 0) {
+ dev_err(dev, "no irq for node %s\n", pdev->name);
+ return ssi->irq;
}
- /* Are the RX and the TX clocks locked? */
+ /* Set software limitations for synchronous mode */
if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
- if (!fsl_ssi_is_ac97(ssi_private))
- ssi_private->cpu_dai_drv.symmetric_rates = 1;
+ if (!fsl_ssi_is_ac97(ssi)) {
+ ssi->cpu_dai_drv.symmetric_rates = 1;
+ ssi->cpu_dai_drv.symmetric_samplebits = 1;
+ }
- ssi_private->cpu_dai_drv.symmetric_channels = 1;
- ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
+ ssi->cpu_dai_drv.symmetric_channels = 1;
}
- /* Determine the FIFO depth. */
+ /* Fetch FIFO depth; Set to 8 for older DT without this property */
iprop = of_get_property(np, "fsl,fifo-depth", NULL);
if (iprop)
- ssi_private->fifo_depth = be32_to_cpup(iprop);
+ ssi->fifo_depth = be32_to_cpup(iprop);
else
- /* Older 8610 DTs didn't have the fifo-depth property */
- ssi_private->fifo_depth = 8;
+ ssi->fifo_depth = 8;
/*
- * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't
- * use FIFO 1 but set the watermark appropriately nontheless.
- * We program the transmit water to signal a DMA transfer
- * if there are N elements left in the FIFO. For chips with 15-deep
- * FIFOs, set watermark to 8. This allows the SSI to operate at a
- * high data rate without channel slipping. Behavior is unchanged
- * for the older chips with a fifo depth of only 8. A value of 4
- * might be appropriate for the older chips, but is left at
- * fifo_depth-2 until sombody has a chance to test.
+ * Configure TX and RX DMA watermarks -- when to send a DMA request
*
- * We set the watermark on the same level as the DMA burstsize. For
- * fiq it is probably better to use the biggest possible watermark
- * size.
+ * Values should be tested to avoid FIFO under/over run. Set maxburst
+ * to fifo_watermark to maxiumize DMA transaction to reduce overhead.
*/
- switch (ssi_private->fifo_depth) {
+ switch (ssi->fifo_depth) {
case 15:
/*
- * 2 samples is not enough when running at high data
- * rates (like 48kHz @ 16 bits/channel, 16 channels)
- * 8 seems to split things evenly and leave enough time
- * for the DMA to fill the FIFO before it's over/under
- * run.
+ * Set to 8 as a balanced configuration -- When TX FIFO has 8
+ * empty slots, send a DMA request to fill these 8 slots. The
+ * remaining 7 slots should be able to allow DMA to finish the
+ * transaction before TX FIFO underruns; Same applies to RX.
+ *
+ * Tested with cases running at 48kHz @ 16 bits x 16 channels
*/
- ssi_private->fifo_watermark = 8;
- ssi_private->dma_maxburst = 8;
+ ssi->fifo_watermark = 8;
+ ssi->dma_maxburst = 8;
break;
case 8:
default:
- /*
- * maintain old behavior for older chips.
- * Keeping it the same because I don't have an older
- * board to test with.
- * I suspect this could be changed to be something to
- * leave some more space in the fifo.
- */
- ssi_private->fifo_watermark = ssi_private->fifo_depth - 2;
- ssi_private->dma_maxburst = ssi_private->fifo_depth - 2;
+ /* Safely use old watermark configurations for older chips */
+ ssi->fifo_watermark = ssi->fifo_depth - 2;
+ ssi->dma_maxburst = ssi->fifo_depth - 2;
break;
}
- dev_set_drvdata(&pdev->dev, ssi_private);
+ dev_set_drvdata(dev, ssi);
- if (ssi_private->soc->imx) {
- ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem);
+ if (ssi->soc->imx) {
+ ret = fsl_ssi_imx_probe(pdev, ssi, iomem);
if (ret)
return ret;
}
- ret = devm_snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
- &ssi_private->cpu_dai_drv, 1);
+ if (fsl_ssi_is_ac97(ssi)) {
+ mutex_init(&ssi->ac97_reg_lock);
+ ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+ if (ret) {
+ dev_err(dev, "failed to set AC'97 ops\n");
+ goto error_ac97_ops;
+ }
+ }
+
+ ret = devm_snd_soc_register_component(dev, &fsl_ssi_component,
+ &ssi->cpu_dai_drv, 1);
if (ret) {
- dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+ dev_err(dev, "failed to register DAI: %d\n", ret);
goto error_asoc_register;
}
- if (ssi_private->use_dma) {
- ret = devm_request_irq(&pdev->dev, ssi_private->irq,
- fsl_ssi_isr, 0, dev_name(&pdev->dev),
- ssi_private);
+ if (ssi->use_dma) {
+ ret = devm_request_irq(dev, ssi->irq, fsl_ssi_isr, 0,
+ dev_name(dev), ssi);
if (ret < 0) {
- dev_err(&pdev->dev, "could not claim irq %u\n",
- ssi_private->irq);
+ dev_err(dev, "failed to claim irq %u\n", ssi->irq);
goto error_asoc_register;
}
}
- ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev);
+ ret = fsl_ssi_debugfs_create(&ssi->dbg_stats, dev);
if (ret)
goto error_asoc_register;
- /*
- * If codec-handle property is missing from SSI node, we assume
- * that the machine driver uses new binding which does not require
- * SSI driver to trigger machine driver's probe.
- */
+ /* Bypass it if using newer DT bindings of ASoC machine drivers */
if (!of_get_property(np, "codec-handle", NULL))
goto done;
- /* Trigger the machine driver's probe function. The platform driver
- * name of the machine driver is taken from /compatible property of the
- * device tree. We also pass the address of the CPU DAI driver
- * structure.
+ /*
+ * Backward compatible for older bindings by manually triggering the
+ * machine driver's probe(). Use /compatible property, including the
+ * address of CPU DAI driver structure, as the name of machine driver.
*/
sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL);
/* Sometimes the compatible name has a "fsl," prefix, so we strip it. */
@@ -1617,34 +1545,31 @@ static int fsl_ssi_probe(struct platform_device *pdev)
snprintf(name, sizeof(name), "snd-soc-%s", sprop);
make_lowercase(name);
- ssi_private->pdev =
- platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
- if (IS_ERR(ssi_private->pdev)) {
- ret = PTR_ERR(ssi_private->pdev);
- dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
+ ssi->pdev = platform_device_register_data(dev, name, 0, NULL, 0);
+ if (IS_ERR(ssi->pdev)) {
+ ret = PTR_ERR(ssi->pdev);
+ dev_err(dev, "failed to register platform: %d\n", ret);
goto error_sound_card;
}
done:
- if (ssi_private->dai_fmt)
- _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private,
- ssi_private->dai_fmt);
+ if (ssi->dai_fmt)
+ _fsl_ssi_set_dai_fmt(dev, ssi, ssi->dai_fmt);
- if (fsl_ssi_is_ac97(ssi_private)) {
+ if (fsl_ssi_is_ac97(ssi)) {
u32 ssi_idx;
ret = of_property_read_u32(np, "cell-index", &ssi_idx);
if (ret) {
- dev_err(&pdev->dev, "cannot get SSI index property\n");
+ dev_err(dev, "failed to get SSI index property\n");
goto error_sound_card;
}
- ssi_private->pdev =
- platform_device_register_data(NULL,
- "ac97-codec", ssi_idx, NULL, 0);
- if (IS_ERR(ssi_private->pdev)) {
- ret = PTR_ERR(ssi_private->pdev);
- dev_err(&pdev->dev,
+ ssi->pdev = platform_device_register_data(NULL, "ac97-codec",
+ ssi_idx, NULL, 0);
+ if (IS_ERR(ssi->pdev)) {
+ ret = PTR_ERR(ssi->pdev);
+ dev_err(dev,
"failed to register AC97 codec platform: %d\n",
ret);
goto error_sound_card;
@@ -1654,29 +1579,36 @@ done:
return 0;
error_sound_card:
- fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
-
+ fsl_ssi_debugfs_remove(&ssi->dbg_stats);
error_asoc_register:
- if (ssi_private->soc->imx)
- fsl_ssi_imx_clean(pdev, ssi_private);
+ if (fsl_ssi_is_ac97(ssi))
+ snd_soc_set_ac97_ops(NULL);
+error_ac97_ops:
+ if (fsl_ssi_is_ac97(ssi))
+ mutex_destroy(&ssi->ac97_reg_lock);
+
+ if (ssi->soc->imx)
+ fsl_ssi_imx_clean(pdev, ssi);
return ret;
}
static int fsl_ssi_remove(struct platform_device *pdev)
{
- struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
+ struct fsl_ssi *ssi = dev_get_drvdata(&pdev->dev);
- fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
+ fsl_ssi_debugfs_remove(&ssi->dbg_stats);
- if (ssi_private->pdev)
- platform_device_unregister(ssi_private->pdev);
+ if (ssi->pdev)
+ platform_device_unregister(ssi->pdev);
- if (ssi_private->soc->imx)
- fsl_ssi_imx_clean(pdev, ssi_private);
+ if (ssi->soc->imx)
+ fsl_ssi_imx_clean(pdev, ssi);
- if (fsl_ssi_is_ac97(ssi_private))
+ if (fsl_ssi_is_ac97(ssi)) {
snd_soc_set_ac97_ops(NULL);
+ mutex_destroy(&ssi->ac97_reg_lock);
+ }
return 0;
}
@@ -1684,13 +1616,11 @@ static int fsl_ssi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int fsl_ssi_suspend(struct device *dev)
{
- struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
- struct regmap *regs = ssi_private->regs;
+ struct fsl_ssi *ssi = dev_get_drvdata(dev);
+ struct regmap *regs = ssi->regs;
- regmap_read(regs, CCSR_SSI_SFCSR,
- &ssi_private->regcache_sfcsr);
- regmap_read(regs, CCSR_SSI_SACNT,
- &ssi_private->regcache_sacnt);
+ regmap_read(regs, REG_SSI_SFCSR, &ssi->regcache_sfcsr);
+ regmap_read(regs, REG_SSI_SACNT, &ssi->regcache_sacnt);
regcache_cache_only(regs, true);
regcache_mark_dirty(regs);
@@ -1700,17 +1630,16 @@ static int fsl_ssi_suspend(struct device *dev)
static int fsl_ssi_resume(struct device *dev)
{
- struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
- struct regmap *regs = ssi_private->regs;
+ struct fsl_ssi *ssi = dev_get_drvdata(dev);
+ struct regmap *regs = ssi->regs;
regcache_cache_only(regs, false);
- regmap_update_bits(regs, CCSR_SSI_SFCSR,
- CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
- CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
- ssi_private->regcache_sfcsr);
- regmap_write(regs, CCSR_SSI_SACNT,
- ssi_private->regcache_sacnt);
+ regmap_update_bits(regs, REG_SSI_SFCSR,
+ SSI_SFCSR_RFWM1_MASK | SSI_SFCSR_TFWM1_MASK |
+ SSI_SFCSR_RFWM0_MASK | SSI_SFCSR_TFWM0_MASK,
+ ssi->regcache_sfcsr);
+ regmap_write(regs, REG_SSI_SACNT, ssi->regcache_sacnt);
return regcache_sync(regs);
}
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 5065105..de2fdc5 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -1,5 +1,5 @@
/*
- * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 SoC
+ * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 and i.MX SoC
*
* Author: Timur Tabi <timur@freescale.com>
*
@@ -12,198 +12,261 @@
#ifndef _MPC8610_I2S_H
#define _MPC8610_I2S_H
-/* SSI registers */
-#define CCSR_SSI_STX0 0x00
-#define CCSR_SSI_STX1 0x04
-#define CCSR_SSI_SRX0 0x08
-#define CCSR_SSI_SRX1 0x0c
-#define CCSR_SSI_SCR 0x10
-#define CCSR_SSI_SISR 0x14
-#define CCSR_SSI_SIER 0x18
-#define CCSR_SSI_STCR 0x1c
-#define CCSR_SSI_SRCR 0x20
-#define CCSR_SSI_STCCR 0x24
-#define CCSR_SSI_SRCCR 0x28
-#define CCSR_SSI_SFCSR 0x2c
-#define CCSR_SSI_STR 0x30
-#define CCSR_SSI_SOR 0x34
-#define CCSR_SSI_SACNT 0x38
-#define CCSR_SSI_SACADD 0x3c
-#define CCSR_SSI_SACDAT 0x40
-#define CCSR_SSI_SATAG 0x44
-#define CCSR_SSI_STMSK 0x48
-#define CCSR_SSI_SRMSK 0x4c
-#define CCSR_SSI_SACCST 0x50
-#define CCSR_SSI_SACCEN 0x54
-#define CCSR_SSI_SACCDIS 0x58
+#define RX 0
+#define TX 1
-#define CCSR_SSI_SCR_SYNC_TX_FS 0x00001000
-#define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800
-#define CCSR_SSI_SCR_TFR_CLK_DIS 0x00000400
-#define CCSR_SSI_SCR_TCH_EN 0x00000100
-#define CCSR_SSI_SCR_SYS_CLK_EN 0x00000080
-#define CCSR_SSI_SCR_I2S_MODE_MASK 0x00000060
-#define CCSR_SSI_SCR_I2S_MODE_NORMAL 0x00000000
-#define CCSR_SSI_SCR_I2S_MODE_MASTER 0x00000020
-#define CCSR_SSI_SCR_I2S_MODE_SLAVE 0x00000040
-#define CCSR_SSI_SCR_SYN 0x00000010
-#define CCSR_SSI_SCR_NET 0x00000008
-#define CCSR_SSI_SCR_RE 0x00000004
-#define CCSR_SSI_SCR_TE 0x00000002
-#define CCSR_SSI_SCR_SSIEN 0x00000001
+/* -- SSI Register Map -- */
-#define CCSR_SSI_SISR_RFRC 0x01000000
-#define CCSR_SSI_SISR_TFRC 0x00800000
-#define CCSR_SSI_SISR_CMDAU 0x00040000
-#define CCSR_SSI_SISR_CMDDU 0x00020000
-#define CCSR_SSI_SISR_RXT 0x00010000
-#define CCSR_SSI_SISR_RDR1 0x00008000
-#define CCSR_SSI_SISR_RDR0 0x00004000
-#define CCSR_SSI_SISR_TDE1 0x00002000
-#define CCSR_SSI_SISR_TDE0 0x00001000
-#define CCSR_SSI_SISR_ROE1 0x00000800
-#define CCSR_SSI_SISR_ROE0 0x00000400
-#define CCSR_SSI_SISR_TUE1 0x00000200
-#define CCSR_SSI_SISR_TUE0 0x00000100
-#define CCSR_SSI_SISR_TFS 0x00000080
-#define CCSR_SSI_SISR_RFS 0x00000040
-#define CCSR_SSI_SISR_TLS 0x00000020
-#define CCSR_SSI_SISR_RLS 0x00000010
-#define CCSR_SSI_SISR_RFF1 0x00000008
-#define CCSR_SSI_SISR_RFF0 0x00000004
-#define CCSR_SSI_SISR_TFE1 0x00000002
-#define CCSR_SSI_SISR_TFE0 0x00000001
+/* SSI Transmit Data Register 0 */
+#define REG_SSI_STX0 0x00
+/* SSI Transmit Data Register 1 */
+#define REG_SSI_STX1 0x04
+/* SSI Receive Data Register 0 */
+#define REG_SSI_SRX0 0x08
+/* SSI Receive Data Register 1 */
+#define REG_SSI_SRX1 0x0c
+/* SSI Control Register */
+#define REG_SSI_SCR 0x10
+/* SSI Interrupt Status Register */
+#define REG_SSI_SISR 0x14
+/* SSI Interrupt Enable Register */
+#define REG_SSI_SIER 0x18
+/* SSI Transmit Configuration Register */
+#define REG_SSI_STCR 0x1c
+/* SSI Receive Configuration Register */
+#define REG_SSI_SRCR 0x20
+#define REG_SSI_SxCR(tx) ((tx) ? REG_SSI_STCR : REG_SSI_SRCR)
+/* SSI Transmit Clock Control Register */
+#define REG_SSI_STCCR 0x24
+/* SSI Receive Clock Control Register */
+#define REG_SSI_SRCCR 0x28
+#define REG_SSI_SxCCR(tx) ((tx) ? REG_SSI_STCCR : REG_SSI_SRCCR)
+/* SSI FIFO Control/Status Register */
+#define REG_SSI_SFCSR 0x2c
+/*
+ * SSI Test Register (Intended for debugging purposes only)
+ *
+ * Note: STR is not documented in recent IMX datasheet, but
+ * is described in IMX51 reference manual at section 56.3.3.14
+ */
+#define REG_SSI_STR 0x30
+/*
+ * SSI Option Register (Intended for internal use only)
+ *
+ * Note: SOR is not documented in recent IMX datasheet, but
+ * is described in IMX51 reference manual at section 56.3.3.15
+ */
+#define REG_SSI_SOR 0x34
+/* SSI AC97 Control Register */
+#define REG_SSI_SACNT 0x38
+/* SSI AC97 Command Address Register */
+#define REG_SSI_SACADD 0x3c
+/* SSI AC97 Command Data Register */
+#define REG_SSI_SACDAT 0x40
+/* SSI AC97 Tag Register */
+#define REG_SSI_SATAG 0x44
+/* SSI Transmit Time Slot Mask Register */
+#define REG_SSI_STMSK 0x48
+/* SSI Receive Time Slot Mask Register */
+#define REG_SSI_SRMSK 0x4c
+#define REG_SSI_SxMSK(tx) ((tx) ? REG_SSI_STMSK : REG_SSI_SRMSK)
+/*
+ * SSI AC97 Channel Status Register
+ *
+ * The status could be changed by:
+ * 1) Writing a '1' bit at some position in SACCEN sets relevant bit in SACCST
+ * 2) Writing a '1' bit at some position in SACCDIS unsets the relevant bit
+ * 3) Receivng a '1' in SLOTREQ bit from external CODEC via AC Link
+ */
+#define REG_SSI_SACCST 0x50
+/* SSI AC97 Channel Enable Register -- Set bits in SACCST */
+#define REG_SSI_SACCEN 0x54
+/* SSI AC97 Channel Disable Register -- Clear bits in SACCST */
+#define REG_SSI_SACCDIS 0x58
+
+/* -- SSI Register Field Maps -- */
-#define CCSR_SSI_SIER_RFRC_EN 0x01000000
-#define CCSR_SSI_SIER_TFRC_EN 0x00800000
-#define CCSR_SSI_SIER_RDMAE 0x00400000
-#define CCSR_SSI_SIER_RIE 0x00200000
-#define CCSR_SSI_SIER_TDMAE 0x00100000
-#define CCSR_SSI_SIER_TIE 0x00080000
-#define CCSR_SSI_SIER_CMDAU_EN 0x00040000
-#define CCSR_SSI_SIER_CMDDU_EN 0x00020000
-#define CCSR_SSI_SIER_RXT_EN 0x00010000
-#define CCSR_SSI_SIER_RDR1_EN 0x00008000
-#define CCSR_SSI_SIER_RDR0_EN 0x00004000
-#define CCSR_SSI_SIER_TDE1_EN 0x00002000
-#define CCSR_SSI_SIER_TDE0_EN 0x00001000
-#define CCSR_SSI_SIER_ROE1_EN 0x00000800
-#define CCSR_SSI_SIER_ROE0_EN 0x00000400
-#define CCSR_SSI_SIER_TUE1_EN 0x00000200
-#define CCSR_SSI_SIER_TUE0_EN 0x00000100
-#define CCSR_SSI_SIER_TFS_EN 0x00000080
-#define CCSR_SSI_SIER_RFS_EN 0x00000040
-#define CCSR_SSI_SIER_TLS_EN 0x00000020
-#define CCSR_SSI_SIER_RLS_EN 0x00000010
-#define CCSR_SSI_SIER_RFF1_EN 0x00000008
-#define CCSR_SSI_SIER_RFF0_EN 0x00000004
-#define CCSR_SSI_SIER_TFE1_EN 0x00000002
-#define CCSR_SSI_SIER_TFE0_EN 0x00000001
+/* SSI Control Register -- REG_SSI_SCR 0x10 */
+#define SSI_SCR_SYNC_TX_FS 0x00001000
+#define SSI_SCR_RFR_CLK_DIS 0x00000800
+#define SSI_SCR_TFR_CLK_DIS 0x00000400
+#define SSI_SCR_TCH_EN 0x00000100
+#define SSI_SCR_SYS_CLK_EN 0x00000080
+#define SSI_SCR_I2S_MODE_MASK 0x00000060
+#define SSI_SCR_I2S_MODE_NORMAL 0x00000000
+#define SSI_SCR_I2S_MODE_MASTER 0x00000020
+#define SSI_SCR_I2S_MODE_SLAVE 0x00000040
+#define SSI_SCR_SYN 0x00000010
+#define SSI_SCR_NET 0x00000008
+#define SSI_SCR_I2S_NET_MASK (SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK)
+#define SSI_SCR_RE 0x00000004
+#define SSI_SCR_TE 0x00000002
+#define SSI_SCR_SSIEN 0x00000001
-#define CCSR_SSI_STCR_TXBIT0 0x00000200
-#define CCSR_SSI_STCR_TFEN1 0x00000100
-#define CCSR_SSI_STCR_TFEN0 0x00000080
-#define CCSR_SSI_STCR_TFDIR 0x00000040
-#define CCSR_SSI_STCR_TXDIR 0x00000020
-#define CCSR_SSI_STCR_TSHFD 0x00000010
-#define CCSR_SSI_STCR_TSCKP 0x00000008
-#define CCSR_SSI_STCR_TFSI 0x00000004
-#define CCSR_SSI_STCR_TFSL 0x00000002
-#define CCSR_SSI_STCR_TEFS 0x00000001
+/* SSI Interrupt Status Register -- REG_SSI_SISR 0x14 */
+#define SSI_SISR_RFRC 0x01000000
+#define SSI_SISR_TFRC 0x00800000
+#define SSI_SISR_CMDAU 0x00040000
+#define SSI_SISR_CMDDU 0x00020000
+#define SSI_SISR_RXT 0x00010000
+#define SSI_SISR_RDR1 0x00008000
+#define SSI_SISR_RDR0 0x00004000
+#define SSI_SISR_TDE1 0x00002000
+#define SSI_SISR_TDE0 0x00001000
+#define SSI_SISR_ROE1 0x00000800
+#define SSI_SISR_ROE0 0x00000400
+#define SSI_SISR_TUE1 0x00000200
+#define SSI_SISR_TUE0 0x00000100
+#define SSI_SISR_TFS 0x00000080
+#define SSI_SISR_RFS 0x00000040
+#define SSI_SISR_TLS 0x00000020
+#define SSI_SISR_RLS 0x00000010
+#define SSI_SISR_RFF1 0x00000008
+#define SSI_SISR_RFF0 0x00000004
+#define SSI_SISR_TFE1 0x00000002
+#define SSI_SISR_TFE0 0x00000001
-#define CCSR_SSI_SRCR_RXEXT 0x00000400
-#define CCSR_SSI_SRCR_RXBIT0 0x00000200
-#define CCSR_SSI_SRCR_RFEN1 0x00000100
-#define CCSR_SSI_SRCR_RFEN0 0x00000080
-#define CCSR_SSI_SRCR_RFDIR 0x00000040
-#define CCSR_SSI_SRCR_RXDIR 0x00000020
-#define CCSR_SSI_SRCR_RSHFD 0x00000010
-#define CCSR_SSI_SRCR_RSCKP 0x00000008
-#define CCSR_SSI_SRCR_RFSI 0x00000004
-#define CCSR_SSI_SRCR_RFSL 0x00000002
-#define CCSR_SSI_SRCR_REFS 0x00000001
+/* SSI Interrupt Enable Register -- REG_SSI_SIER 0x18 */
+#define SSI_SIER_RFRC_EN 0x01000000
+#define SSI_SIER_TFRC_EN 0x00800000
+#define SSI_SIER_RDMAE 0x00400000
+#define SSI_SIER_RIE 0x00200000
+#define SSI_SIER_TDMAE 0x00100000
+#define SSI_SIER_TIE 0x00080000
+#define SSI_SIER_CMDAU_EN 0x00040000
+#define SSI_SIER_CMDDU_EN 0x00020000
+#define SSI_SIER_RXT_EN 0x00010000
+#define SSI_SIER_RDR1_EN 0x00008000
+#define SSI_SIER_RDR0_EN 0x00004000
+#define SSI_SIER_TDE1_EN 0x00002000
+#define SSI_SIER_TDE0_EN 0x00001000
+#define SSI_SIER_ROE1_EN 0x00000800
+#define SSI_SIER_ROE0_EN 0x00000400
+#define SSI_SIER_TUE1_EN 0x00000200
+#define SSI_SIER_TUE0_EN 0x00000100
+#define SSI_SIER_TFS_EN 0x00000080
+#define SSI_SIER_RFS_EN 0x00000040
+#define SSI_SIER_TLS_EN 0x00000020
+#define SSI_SIER_RLS_EN 0x00000010
+#define SSI_SIER_RFF1_EN 0x00000008
+#define SSI_SIER_RFF0_EN 0x00000004
+#define SSI_SIER_TFE1_EN 0x00000002
+#define SSI_SIER_TFE0_EN 0x00000001
-/* STCCR and SRCCR */
-#define CCSR_SSI_SxCCR_DIV2_SHIFT 18
-#define CCSR_SSI_SxCCR_DIV2 0x00040000
-#define CCSR_SSI_SxCCR_PSR_SHIFT 17
-#define CCSR_SSI_SxCCR_PSR 0x00020000
-#define CCSR_SSI_SxCCR_WL_SHIFT 13
-#define CCSR_SSI_SxCCR_WL_MASK 0x0001E000
-#define CCSR_SSI_SxCCR_WL(x) \
- (((((x) / 2) - 1) << CCSR_SSI_SxCCR_WL_SHIFT) & CCSR_SSI_SxCCR_WL_MASK)
-#define CCSR_SSI_SxCCR_DC_SHIFT 8
-#define CCSR_SSI_SxCCR_DC_MASK 0x00001F00
-#define CCSR_SSI_SxCCR_DC(x) \
- ((((x) - 1) << CCSR_SSI_SxCCR_DC_SHIFT) & CCSR_SSI_SxCCR_DC_MASK)
-#define CCSR_SSI_SxCCR_PM_SHIFT 0
-#define CCSR_SSI_SxCCR_PM_MASK 0x000000FF
-#define CCSR_SSI_SxCCR_PM(x) \
- ((((x) - 1) << CCSR_SSI_SxCCR_PM_SHIFT) & CCSR_SSI_SxCCR_PM_MASK)
+/* SSI Transmit Configuration Register -- REG_SSI_STCR 0x1C */
+#define SSI_STCR_TXBIT0 0x00000200
+#define SSI_STCR_TFEN1 0x00000100
+#define SSI_STCR_TFEN0 0x00000080
+#define SSI_STCR_TFDIR 0x00000040
+#define SSI_STCR_TXDIR 0x00000020
+#define SSI_STCR_TSHFD 0x00000010
+#define SSI_STCR_TSCKP 0x00000008
+#define SSI_STCR_TFSI 0x00000004
+#define SSI_STCR_TFSL 0x00000002
+#define SSI_STCR_TEFS 0x00000001
+
+/* SSI Receive Configuration Register -- REG_SSI_SRCR 0x20 */
+#define SSI_SRCR_RXEXT 0x00000400
+#define SSI_SRCR_RXBIT0 0x00000200
+#define SSI_SRCR_RFEN1 0x00000100
+#define SSI_SRCR_RFEN0 0x00000080
+#define SSI_SRCR_RFDIR 0x00000040
+#define SSI_SRCR_RXDIR 0x00000020
+#define SSI_SRCR_RSHFD 0x00000010
+#define SSI_SRCR_RSCKP 0x00000008
+#define SSI_SRCR_RFSI 0x00000004
+#define SSI_SRCR_RFSL 0x00000002
+#define SSI_SRCR_REFS 0x00000001
/*
- * The xFCNT bits are read-only, and the xFWM bits are read/write. Use the
- * CCSR_SSI_SFCSR_xFCNTy() macros to read the FIFO counters, and use the
- * CCSR_SSI_SFCSR_xFWMy() macros to set the watermarks.
+ * SSI Transmit Clock Control Register -- REG_SSI_STCCR 0x24
+ * SSI Receive Clock Control Register -- REG_SSI_SRCCR 0x28
+ */
+#define SSI_SxCCR_DIV2_SHIFT 18
+#define SSI_SxCCR_DIV2 0x00040000
+#define SSI_SxCCR_PSR_SHIFT 17
+#define SSI_SxCCR_PSR 0x00020000
+#define SSI_SxCCR_WL_SHIFT 13
+#define SSI_SxCCR_WL_MASK 0x0001E000
+#define SSI_SxCCR_WL(x) \
+ (((((x) / 2) - 1) << SSI_SxCCR_WL_SHIFT) & SSI_SxCCR_WL_MASK)
+#define SSI_SxCCR_DC_SHIFT 8
+#define SSI_SxCCR_DC_MASK 0x00001F00
+#define SSI_SxCCR_DC(x) \
+ ((((x) - 1) << SSI_SxCCR_DC_SHIFT) & SSI_SxCCR_DC_MASK)
+#define SSI_SxCCR_PM_SHIFT 0
+#define SSI_SxCCR_PM_MASK 0x000000FF
+#define SSI_SxCCR_PM(x) \
+ ((((x) - 1) << SSI_SxCCR_PM_SHIFT) & SSI_SxCCR_PM_MASK)
+
+/*
+ * SSI FIFO Control/Status Register -- REG_SSI_SFCSR 0x2c
+ *
+ * Tx or Rx FIFO Counter -- SSI_SFCSR_xFCNTy Read-Only
+ * Tx or Rx FIFO Watermarks -- SSI_SFCSR_xFWMy Read/Write
*/
-#define CCSR_SSI_SFCSR_RFCNT1_SHIFT 28
-#define CCSR_SSI_SFCSR_RFCNT1_MASK 0xF0000000
-#define CCSR_SSI_SFCSR_RFCNT1(x) \
- (((x) & CCSR_SSI_SFCSR_RFCNT1_MASK) >> CCSR_SSI_SFCSR_RFCNT1_SHIFT)
-#define CCSR_SSI_SFCSR_TFCNT1_SHIFT 24
-#define CCSR_SSI_SFCSR_TFCNT1_MASK 0x0F000000
-#define CCSR_SSI_SFCSR_TFCNT1(x) \
- (((x) & CCSR_SSI_SFCSR_TFCNT1_MASK) >> CCSR_SSI_SFCSR_TFCNT1_SHIFT)
-#define CCSR_SSI_SFCSR_RFWM1_SHIFT 20
-#define CCSR_SSI_SFCSR_RFWM1_MASK 0x00F00000
-#define CCSR_SSI_SFCSR_RFWM1(x) \
- (((x) << CCSR_SSI_SFCSR_RFWM1_SHIFT) & CCSR_SSI_SFCSR_RFWM1_MASK)
-#define CCSR_SSI_SFCSR_TFWM1_SHIFT 16
-#define CCSR_SSI_SFCSR_TFWM1_MASK 0x000F0000
-#define CCSR_SSI_SFCSR_TFWM1(x) \
- (((x) << CCSR_SSI_SFCSR_TFWM1_SHIFT) & CCSR_SSI_SFCSR_TFWM1_MASK)
-#define CCSR_SSI_SFCSR_RFCNT0_SHIFT 12
-#define CCSR_SSI_SFCSR_RFCNT0_MASK 0x0000F000
-#define CCSR_SSI_SFCSR_RFCNT0(x) \
- (((x) & CCSR_SSI_SFCSR_RFCNT0_MASK) >> CCSR_SSI_SFCSR_RFCNT0_SHIFT)
-#define CCSR_SSI_SFCSR_TFCNT0_SHIFT 8
-#define CCSR_SSI_SFCSR_TFCNT0_MASK 0x00000F00
-#define CCSR_SSI_SFCSR_TFCNT0(x) \
- (((x) & CCSR_SSI_SFCSR_TFCNT0_MASK) >> CCSR_SSI_SFCSR_TFCNT0_SHIFT)
-#define CCSR_SSI_SFCSR_RFWM0_SHIFT 4
-#define CCSR_SSI_SFCSR_RFWM0_MASK 0x000000F0
-#define CCSR_SSI_SFCSR_RFWM0(x) \
- (((x) << CCSR_SSI_SFCSR_RFWM0_SHIFT) & CCSR_SSI_SFCSR_RFWM0_MASK)
-#define CCSR_SSI_SFCSR_TFWM0_SHIFT 0
-#define CCSR_SSI_SFCSR_TFWM0_MASK 0x0000000F
-#define CCSR_SSI_SFCSR_TFWM0(x) \
- (((x) << CCSR_SSI_SFCSR_TFWM0_SHIFT) & CCSR_SSI_SFCSR_TFWM0_MASK)
+#define SSI_SFCSR_RFCNT1_SHIFT 28
+#define SSI_SFCSR_RFCNT1_MASK 0xF0000000
+#define SSI_SFCSR_RFCNT1(x) \
+ (((x) & SSI_SFCSR_RFCNT1_MASK) >> SSI_SFCSR_RFCNT1_SHIFT)
+#define SSI_SFCSR_TFCNT1_SHIFT 24
+#define SSI_SFCSR_TFCNT1_MASK 0x0F000000
+#define SSI_SFCSR_TFCNT1(x) \
+ (((x) & SSI_SFCSR_TFCNT1_MASK) >> SSI_SFCSR_TFCNT1_SHIFT)
+#define SSI_SFCSR_RFWM1_SHIFT 20
+#define SSI_SFCSR_RFWM1_MASK 0x00F00000
+#define SSI_SFCSR_RFWM1(x) \
+ (((x) << SSI_SFCSR_RFWM1_SHIFT) & SSI_SFCSR_RFWM1_MASK)
+#define SSI_SFCSR_TFWM1_SHIFT 16
+#define SSI_SFCSR_TFWM1_MASK 0x000F0000
+#define SSI_SFCSR_TFWM1(x) \
+ (((x) << SSI_SFCSR_TFWM1_SHIFT) & SSI_SFCSR_TFWM1_MASK)
+#define SSI_SFCSR_RFCNT0_SHIFT 12
+#define SSI_SFCSR_RFCNT0_MASK 0x0000F000
+#define SSI_SFCSR_RFCNT0(x) \
+ (((x) & SSI_SFCSR_RFCNT0_MASK) >> SSI_SFCSR_RFCNT0_SHIFT)
+#define SSI_SFCSR_TFCNT0_SHIFT 8
+#define SSI_SFCSR_TFCNT0_MASK 0x00000F00
+#define SSI_SFCSR_TFCNT0(x) \
+ (((x) & SSI_SFCSR_TFCNT0_MASK) >> SSI_SFCSR_TFCNT0_SHIFT)
+#define SSI_SFCSR_RFWM0_SHIFT 4
+#define SSI_SFCSR_RFWM0_MASK 0x000000F0
+#define SSI_SFCSR_RFWM0(x) \
+ (((x) << SSI_SFCSR_RFWM0_SHIFT) & SSI_SFCSR_RFWM0_MASK)
+#define SSI_SFCSR_TFWM0_SHIFT 0
+#define SSI_SFCSR_TFWM0_MASK 0x0000000F
+#define SSI_SFCSR_TFWM0(x) \
+ (((x) << SSI_SFCSR_TFWM0_SHIFT) & SSI_SFCSR_TFWM0_MASK)
-#define CCSR_SSI_STR_TEST 0x00008000
-#define CCSR_SSI_STR_RCK2TCK 0x00004000
-#define CCSR_SSI_STR_RFS2TFS 0x00002000
-#define CCSR_SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F)
-#define CCSR_SSI_STR_TXD2RXD 0x00000080
-#define CCSR_SSI_STR_TCK2RCK 0x00000040
-#define CCSR_SSI_STR_TFS2RFS 0x00000020
-#define CCSR_SSI_STR_TXSTATE(x) ((x) & 0x1F)
+/* SSI Test Register -- REG_SSI_STR 0x30 */
+#define SSI_STR_TEST 0x00008000
+#define SSI_STR_RCK2TCK 0x00004000
+#define SSI_STR_RFS2TFS 0x00002000
+#define SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F)
+#define SSI_STR_TXD2RXD 0x00000080
+#define SSI_STR_TCK2RCK 0x00000040
+#define SSI_STR_TFS2RFS 0x00000020
+#define SSI_STR_TXSTATE(x) ((x) & 0x1F)
-#define CCSR_SSI_SOR_CLKOFF 0x00000040
-#define CCSR_SSI_SOR_RX_CLR 0x00000020
-#define CCSR_SSI_SOR_TX_CLR 0x00000010
-#define CCSR_SSI_SOR_INIT 0x00000008
-#define CCSR_SSI_SOR_WAIT_SHIFT 1
-#define CCSR_SSI_SOR_WAIT_MASK 0x00000006
-#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
-#define CCSR_SSI_SOR_SYNRST 0x00000001
+/* SSI Option Register -- REG_SSI_SOR 0x34 */
+#define SSI_SOR_CLKOFF 0x00000040
+#define SSI_SOR_RX_CLR 0x00000020
+#define SSI_SOR_TX_CLR 0x00000010
+#define SSI_SOR_xX_CLR(tx) ((tx) ? SSI_SOR_TX_CLR : SSI_SOR_RX_CLR)
+#define SSI_SOR_INIT 0x00000008
+#define SSI_SOR_WAIT_SHIFT 1
+#define SSI_SOR_WAIT_MASK 0x00000006
+#define SSI_SOR_WAIT(x) (((x) & 3) << SSI_SOR_WAIT_SHIFT)
+#define SSI_SOR_SYNRST 0x00000001
-#define CCSR_SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5)
-#define CCSR_SSI_SACNT_WR 0x00000010
-#define CCSR_SSI_SACNT_RD 0x00000008
-#define CCSR_SSI_SACNT_RDWR_MASK 0x00000018
-#define CCSR_SSI_SACNT_TIF 0x00000004
-#define CCSR_SSI_SACNT_FV 0x00000002
-#define CCSR_SSI_SACNT_AC97EN 0x00000001
+/* SSI AC97 Control Register -- REG_SSI_SACNT 0x38 */
+#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5)
+#define SSI_SACNT_WR 0x00000010
+#define SSI_SACNT_RD 0x00000008
+#define SSI_SACNT_RDWR_MASK 0x00000018
+#define SSI_SACNT_TIF 0x00000004
+#define SSI_SACNT_FV 0x00000002
+#define SSI_SACNT_AC97EN 0x00000001
struct device;
@@ -255,7 +318,7 @@ static inline void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *stats, u32 sisr)
}
static inline int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg,
- struct device *dev)
+ struct device *dev)
{
return 0;
}
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c
index 5469ffb..7aac63e 100644
--- a/sound/soc/fsl/fsl_ssi_dbg.c
+++ b/sound/soc/fsl/fsl_ssi_dbg.c
@@ -18,86 +18,86 @@
void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *dbg, u32 sisr)
{
- if (sisr & CCSR_SSI_SISR_RFRC)
+ if (sisr & SSI_SISR_RFRC)
dbg->stats.rfrc++;
- if (sisr & CCSR_SSI_SISR_TFRC)
+ if (sisr & SSI_SISR_TFRC)
dbg->stats.tfrc++;
- if (sisr & CCSR_SSI_SISR_CMDAU)
+ if (sisr & SSI_SISR_CMDAU)
dbg->stats.cmdau++;
- if (sisr & CCSR_SSI_SISR_CMDDU)
+ if (sisr & SSI_SISR_CMDDU)
dbg->stats.cmddu++;
- if (sisr & CCSR_SSI_SISR_RXT)
+ if (sisr & SSI_SISR_RXT)
dbg->stats.rxt++;
- if (sisr & CCSR_SSI_SISR_RDR1)
+ if (sisr & SSI_SISR_RDR1)
dbg->stats.rdr1++;
- if (sisr & CCSR_SSI_SISR_RDR0)
+ if (sisr & SSI_SISR_RDR0)
dbg->stats.rdr0++;
- if (sisr & CCSR_SSI_SISR_TDE1)
+ if (sisr & SSI_SISR_TDE1)
dbg->stats.tde1++;
- if (sisr & CCSR_SSI_SISR_TDE0)
+ if (sisr & SSI_SISR_TDE0)
dbg->stats.tde0++;
- if (sisr & CCSR_SSI_SISR_ROE1)
+ if (sisr & SSI_SISR_ROE1)
dbg->stats.roe1++;
- if (sisr & CCSR_SSI_SISR_ROE0)
+ if (sisr & SSI_SISR_ROE0)
dbg->stats.roe0++;
- if (sisr & CCSR_SSI_SISR_TUE1)
+ if (sisr & SSI_SISR_TUE1)
dbg->stats.tue1++;
- if (sisr & CCSR_SSI_SISR_TUE0)
+ if (sisr & SSI_SISR_TUE0)
dbg->stats.tue0++;
- if (sisr & CCSR_SSI_SISR_TFS)
+ if (sisr & SSI_SISR_TFS)
dbg->stats.tfs++;
- if (sisr & CCSR_SSI_SISR_RFS)
+ if (sisr & SSI_SISR_RFS)
dbg->stats.rfs++;
- if (sisr & CCSR_SSI_SISR_TLS)
+ if (sisr & SSI_SISR_TLS)
dbg->stats.tls++;
- if (sisr & CCSR_SSI_SISR_RLS)
+ if (sisr & SSI_SISR_RLS)
dbg->stats.rls++;
- if (sisr & CCSR_SSI_SISR_RFF1)
+ if (sisr & SSI_SISR_RFF1)
dbg->stats.rff1++;
- if (sisr & CCSR_SSI_SISR_RFF0)
+ if (sisr & SSI_SISR_RFF0)
dbg->stats.rff0++;
- if (sisr & CCSR_SSI_SISR_TFE1)
+ if (sisr & SSI_SISR_TFE1)
dbg->stats.tfe1++;
- if (sisr & CCSR_SSI_SISR_TFE0)
+ if (sisr & SSI_SISR_TFE0)
dbg->stats.tfe0++;
}
-/* Show the statistics of a flag only if its interrupt is enabled. The
- * compiler will optimze this code to a no-op if the interrupt is not
- * enabled.
+/**
+ * Show the statistics of a flag only if its interrupt is enabled
+ *
+ * Compilers will optimize it to a no-op if the interrupt is disabled
*/
#define SIER_SHOW(flag, name) \
do { \
- if (CCSR_SSI_SIER_##flag) \
+ if (SSI_SIER_##flag) \
seq_printf(s, #name "=%u\n", ssi_dbg->stats.name); \
} while (0)
/**
- * fsl_sysfs_ssi_show: display SSI statistics
+ * Display the statistics for the current SSI device
*
- * Display the statistics for the current SSI device. To avoid confusion,
- * we only show those counts that are enabled.
+ * To avoid confusion, only show those counts that are enabled
*/
static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
{
@@ -147,7 +147,8 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
return -ENOMEM;
ssi_dbg->dbg_stats = debugfs_create_file("stats", S_IRUGO,
- ssi_dbg->dbg_dir, ssi_dbg, &fsl_ssi_stats_ops);
+ ssi_dbg->dbg_dir, ssi_dbg,
+ &fsl_ssi_stats_ops);
if (!ssi_dbg->dbg_stats) {
debugfs_remove(ssi_dbg->dbg_dir);
return -ENOMEM;
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index 0c8f86d..07a5720 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -36,7 +36,6 @@
#include <linux/of_irq.h>
#include <linux/mfd/syscon.h>
#include <linux/reset-controller.h>
-#include <linux/clk.h>
#include "hi6210-i2s.h"
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 7b49d04..f2c9e8c 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -1,71 +1,122 @@
+config SND_SOC_INTEL_SST_TOPLEVEL
+ bool "Intel ASoC SST drivers"
+ default y
+ depends on X86 || COMPILE_TEST
+ select SND_SOC_INTEL_MACH
+ help
+ Intel ASoC SST Platform Drivers. If you have a Intel machine that
+ has an audio controller with a DSP and I2S or DMIC port, then
+ enable this option by saying Y
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Intel SST drivers.
+
+if SND_SOC_INTEL_SST_TOPLEVEL
+
config SND_SST_IPC
tristate
+ # This option controls the IPC core for HiFi2 platforms
config SND_SST_IPC_PCI
tristate
select SND_SST_IPC
+ # This option controls the PCI-based IPC for HiFi2 platforms
+ # (Medfield, Merrifield).
config SND_SST_IPC_ACPI
tristate
select SND_SST_IPC
- select SND_SOC_INTEL_SST
- select IOSF_MBI
+ # This option controls the ACPI-based IPC for HiFi2 platforms
+ # (Baytrail, Cherrytrail)
-config SND_SOC_INTEL_COMMON
+config SND_SOC_INTEL_SST_ACPI
tristate
+ # This option controls ACPI-based probing on
+ # Haswell/Broadwell/Baytrail legacy and will be set
+ # when these platforms are enabled
config SND_SOC_INTEL_SST
tristate
- select SND_SOC_INTEL_SST_ACPI if ACPI
config SND_SOC_INTEL_SST_FIRMWARE
tristate
select DW_DMAC_CORE
-
-config SND_SOC_INTEL_SST_ACPI
- tristate
-
-config SND_SOC_ACPI_INTEL_MATCH
- tristate
- select SND_SOC_ACPI if ACPI
-
-config SND_SOC_INTEL_SST_TOPLEVEL
- tristate "Intel ASoC SST drivers"
- depends on X86 || COMPILE_TEST
- select SND_SOC_INTEL_MACH
- select SND_SOC_INTEL_COMMON
- help
- Intel ASoC Audio Drivers. If you have a Intel machine that
- has audio controller with a DSP and I2S or DMIC port, then
- enable this option by saying Y or M
- If unsure select "N".
+ # This option controls firmware download on
+ # Haswell/Broadwell/Baytrail legacy and will be set
+ # when these platforms are enabled
config SND_SOC_INTEL_HASWELL
- tristate "Intel ASoC SST driver for Haswell/Broadwell"
- depends on SND_SOC_INTEL_SST_TOPLEVEL && SND_DMA_SGBUF
- depends on DMADEVICES
+ tristate "Haswell/Broadwell Platforms"
+ depends on SND_DMA_SGBUF
+ depends on DMADEVICES && ACPI
select SND_SOC_INTEL_SST
+ select SND_SOC_INTEL_SST_ACPI
select SND_SOC_INTEL_SST_FIRMWARE
+ select SND_SOC_ACPI_INTEL_MATCH
+ help
+ If you have a Intel Haswell or Broadwell platform connected to
+ an I2S codec, then enable this option by saying Y or m. This is
+ typically used for Chromebooks. This is a recommended option.
config SND_SOC_INTEL_BAYTRAIL
- tristate "Intel ASoC SST driver for Baytrail (legacy)"
- depends on SND_SOC_INTEL_SST_TOPLEVEL
- depends on DMADEVICES
+ tristate "Baytrail (legacy) Platforms"
+ depends on DMADEVICES && ACPI
select SND_SOC_INTEL_SST
+ select SND_SOC_INTEL_SST_ACPI
select SND_SOC_INTEL_SST_FIRMWARE
+ select SND_SOC_ACPI_INTEL_MATCH
+ help
+ If you have a Intel Baytrail platform connected to an I2S codec,
+ then enable this option by saying Y or m. This was typically used
+ for Baytrail Chromebooks but this option is now deprecated and is
+ not recommended, use SND_SST_ATOM_HIFI2_PLATFORM instead.
+
+config SND_SST_ATOM_HIFI2_PLATFORM_PCI
+ tristate "PCI HiFi2 (Medfield, Merrifield) Platforms"
+ depends on X86 && PCI
+ select SND_SST_IPC_PCI
+ select SND_SOC_COMPRESS
+ help
+ If you have a Intel Medfield or Merrifield/Edison platform, then
+ enable this option by saying Y or m. Distros will typically not
+ enable this option: Medfield devices are not available to
+ developers and while Merrifield/Edison can run a mainline kernel with
+ limited functionality it will require a firmware file which
+ is not in the standard firmware tree
config SND_SST_ATOM_HIFI2_PLATFORM
- tristate "Intel ASoC SST driver for HiFi2 platforms (*field, *trail)"
- depends on SND_SOC_INTEL_SST_TOPLEVEL && X86
+ tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms"
+ depends on X86 && ACPI
+ select SND_SST_IPC_ACPI
select SND_SOC_COMPRESS
+ select SND_SOC_ACPI_INTEL_MATCH
+ select IOSF_MBI
+ help
+ If you have a Intel Baytrail or Cherrytrail platform with an I2S
+ codec, then enable this option by saying Y or m. This is a
+ recommended option
config SND_SOC_INTEL_SKYLAKE
- tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL"
- depends on SND_SOC_INTEL_SST_TOPLEVEL && PCI && ACPI
+ tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
+ depends on PCI && ACPI
select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER
select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST
+ select SND_SOC_ACPI_INTEL_MATCH
+ help
+ If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
+ GeminiLake or CannonLake platform with the DSP enabled in the BIOS
+ then enable this option by saying Y or m.
+
+config SND_SOC_ACPI_INTEL_MATCH
+ tristate
+ select SND_SOC_ACPI if ACPI
+ # this option controls the compilation of ACPI matching tables and
+ # helpers and is not meant to be selected by the user.
+
+endif ## SND_SOC_INTEL_SST_TOPLEVEL
# ASoC codec drivers
source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index b973d45..8160520 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# Core support
-obj-$(CONFIG_SND_SOC_INTEL_COMMON) += common/
+obj-$(CONFIG_SND_SOC) += common/
# Platform Support
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 32d6e02..6cd481b 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
/* Find the IRQ */
ctx->irq_num = platform_get_irq(pdev,
ctx->pdata->res_info->acpi_ipc_irq_index);
+ if (ctx->irq_num <= 0)
+ return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
+
return 0;
}
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index 65e257b..7ee6aeb 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -220,10 +220,10 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
sst_free_block(sst_drv_ctx, block);
out:
test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
- return 0;
+ return ret;
}
-/*
+/**
* sst_pause_stream - Send msg for a pausing stream
* @str_id: stream ID
*
@@ -261,7 +261,7 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
}
} else {
retval = -EBADRQC;
- dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n ");
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n");
}
return retval;
@@ -284,7 +284,7 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
if (!str_info)
return -EINVAL;
if (str_info->status == STREAM_RUNNING)
- return 0;
+ return 0;
if (str_info->status == STREAM_PAUSED) {
retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 6f75470..d4e1036 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -1,183 +1,183 @@
-config SND_SOC_INTEL_MACH
- tristate "Intel Audio machine drivers"
+menuconfig SND_SOC_INTEL_MACH
+ bool "Intel Machine drivers"
depends on SND_SOC_INTEL_SST_TOPLEVEL
- select SND_SOC_ACPI_INTEL_MATCH if ACPI
+ help
+ Intel ASoC Machine Drivers. If you have a Intel machine that
+ has an audio controller with a DSP and I2S or DMIC port, then
+ enable this option by saying Y
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Intel ASoC machine drivers.
if SND_SOC_INTEL_MACH
-config SND_MFLD_MACHINE
- tristate "SOC Machine Audio driver for Intel Medfield MID platform"
- depends on INTEL_SCU_IPC
- select SND_SOC_SN95031
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_PCI
- help
- This adds support for ASoC machine driver for Intel(R) MID Medfield platform
- used as alsa device in audio substem in Intel(R) MID devices
- Say Y if you have such a device.
- If unsure select "N".
+if SND_SOC_INTEL_HASWELL
config SND_SOC_INTEL_HASWELL_MACH
- tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
+ tristate "Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
- depends on SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
- Ultrabook platforms.
- Say Y if you have such a device.
+ Ultrabook platforms. This is a recommended option.
+ Say Y or m if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_BDW_RT5677_MACH
- tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
- depends on X86_INTEL_LPSS && GPIOLIB && I2C
- depends on SND_SOC_INTEL_HASWELL
+ tristate "Broadwell with RT5677 codec"
+ depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB
select SND_SOC_RT5677
help
This adds support for Intel Broadwell platform based boards with
- the RT5677 audio codec.
+ the RT5677 audio codec. This is a recommended option.
+ Say Y or m if you have such a device.
+ If unsure select "N".
config SND_SOC_INTEL_BROADWELL_MACH
- tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
+ tristate "Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
- depends on SND_SOC_INTEL_HASWELL
select SND_SOC_RT286
help
This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
Ultrabook platforms.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+endif ## SND_SOC_INTEL_HASWELL
+
+if SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_BYT_MAX98090_MACH
- tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
+ tristate "Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C
- depends on SND_SST_IPC_ACPI = n
- depends on SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
help
This adds audio driver for Intel Baytrail platform based boards
- with the MAX98090 audio codec.
+ with the MAX98090 audio codec. This driver is deprecated, use
+ SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH instead for better
+ functionality.
config SND_SOC_INTEL_BYT_RT5640_MACH
- tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
+ tristate "Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C
- depends on SND_SST_IPC_ACPI = n
- depends on SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
This adds audio driver for Intel Baytrail platform based boards
with the RT5640 audio codec. This driver is deprecated, use
SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality.
+endif ## SND_SOC_INTEL_BAYTRAIL
+
+if SND_SST_ATOM_HIFI2_PLATFORM
+
config SND_SOC_INTEL_BYTCR_RT5640_MACH
- tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
- depends on X86 && I2C && ACPI
+ tristate "Baytrail and Baytrail-CR with RT5640 codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_ACPI
select SND_SOC_RT5640
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
- This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
- platforms with RT5640 audio codec.
- Say Y if you have such a device.
- If unsure select "N".
+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+ platforms with RT5640 audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
config SND_SOC_INTEL_BYTCR_RT5651_MACH
- tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
- depends on X86 && I2C && ACPI
+ tristate "Baytrail and Baytrail-CR with RT5651 codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_ACPI
select SND_SOC_RT5651
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
- This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
- platforms with RT5651 audio codec.
- Say Y if you have such a device.
- If unsure select "N".
+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+ platforms with RT5651 audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
+ tristate "Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SOC_RT5670
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
+ select SND_SOC_ACPI
+ select SND_SOC_RT5670
help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5672 audio codec.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
+ tristate "Cherrytrail & Braswell with RT5645/5650 codec"
depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_ACPI
select SND_SOC_RT5645
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5645/5650 audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec"
+ tristate "Cherrytrail & Braswell with MAX98090 & TI codec"
depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_MAX98090
select SND_SOC_TS3A227E
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
- tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec"
+ tristate "Baytrail & Cherrytrail with DA7212/7213 codec"
depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_ACPI
select SND_SOC_DA7213
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail
platforms with DA7212/7213 audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
- tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec"
+ tristate "Baytrail & Cherrytrail with ES8316 codec"
depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_ACPI
select SND_SOC_ES8316
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
This adds support for ASoC machine driver for Intel(R) Baytrail &
Cherrytrail platforms with ES8316 audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
- tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
+ tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
depends on X86_INTEL_LPSS && I2C && ACPI
- depends on SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
help
This adds support for ASoC machine driver for the MinnowBoard Max or
Up boards and provides access to I2S signals on the Low-Speed
- connector
+ connector. This is not a recommended option outside of these cases.
+ It is not intended to be enabled by distros by default.
+ Say Y or m if you have such a device.
+
If unsure select "N".
+endif ## SND_SST_ATOM_HIFI2_PLATFORM
+
+if SND_SOC_INTEL_SKYLAKE
+
config SND_SOC_INTEL_SKL_RT286_MACH
- tristate "ASoC Audio driver for SKL with RT286 I2S mode"
- depends on X86 && ACPI && I2C
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "SKL with RT286 I2S mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT286
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec.
- Say Y if you have such a device.
+ Say Y or m if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
- tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "SKL with NAU88L25 and SSM4567 in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_NAU8825
select SND_SOC_SSM4567
select SND_SOC_DMIC
@@ -185,13 +185,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + SSM4567.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
- tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "SKL with NAU88L25 and MAX98357A in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_NAU8825
select SND_SOC_MAX98357A
select SND_SOC_DMIC
@@ -199,13 +198,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + MAX98357A.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
- tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
- depends on X86 && ACPI && I2C
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_DA7219
select SND_SOC_MAX98357A
select SND_SOC_DMIC
@@ -214,13 +212,12 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
help
This adds support for ASoC machine driver for Broxton-P platforms
with DA7219 + MAX98357A I2S audio codec.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_BXT_RT298_MACH
- tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
- depends on X86 && ACPI && I2C
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "Broxton with RT298 I2S mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT298
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
@@ -228,14 +225,12 @@ config SND_SOC_INTEL_BXT_RT298_MACH
help
This adds support for ASoC machine driver for Broxton platforms
with RT286 I2S audio codec.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
- tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
- select SND_SOC_INTEL_SST
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "KBL with RT5663 and MAX98927 in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5663
select SND_SOC_MAX98927
select SND_SOC_DMIC
@@ -243,14 +238,13 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5663 + MAX98927.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
- tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C && SPI
- select SND_SOC_INTEL_SST
- depends on SND_SOC_INTEL_SKYLAKE
+ tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
+ depends on SPI
select SND_SOC_RT5663
select SND_SOC_RT5514
select SND_SOC_RT5514_SPI
@@ -259,7 +253,8 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5663 + RT5514 + MAX98927.
- Say Y if you have such a device.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+endif ## SND_SOC_INTEL_SKYLAKE
-endif
+endif ## SND_SOC_INTEL_MACH
diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
index c4d82ad..2179ded 100644
--- a/sound/soc/intel/boards/bytcht_da7213.c
+++ b/sound/soc/intel/boards/bytcht_da7213.c
@@ -219,7 +219,7 @@ static struct snd_soc_card bytcht_da7213_card = {
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
-static char codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+static char codec_name[SND_ACPI_I2C_ID_LEN];
static int bytcht_da7213_probe(struct platform_device *pdev)
{
@@ -243,7 +243,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
if (i2c_name) {
snprintf(codec_name, sizeof(codec_name),
"%s%s", "i2c-", i2c_name);
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 8088396..305e7f4 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -232,15 +232,39 @@ static struct snd_soc_card byt_cht_es8316_card = {
.fully_routed = true,
};
+static char codec_name[SND_ACPI_I2C_ID_LEN];
+
static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
{
- int ret = 0;
struct byt_cht_es8316_private *priv;
+ struct snd_soc_acpi_mach *mach;
+ const char *i2c_name = NULL;
+ int dai_index = 0;
+ int i;
+ int ret = 0;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv)
return -ENOMEM;
+ mach = (&pdev->dev)->platform_data;
+ /* fix index of codec dai */
+ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) {
+ if (!strcmp(byt_cht_es8316_dais[i].codec_name,
+ "i2c-ESSX8316:00")) {
+ dai_index = i;
+ break;
+ }
+ }
+
+ /* fixup codec name based on HID */
+ i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
+ if (i2c_name) {
+ snprintf(codec_name, sizeof(codec_name),
+ "%s%s", "i2c-", i2c_name);
+ byt_cht_es8316_dais[dai_index].codec_name = codec_name;
+ }
+
/* register the soc card */
byt_cht_es8316_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index f2c0fc4..b6a1cfe 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -713,7 +713,7 @@ static struct snd_soc_card byt_rt5640_card = {
.fully_routed = true,
};
-static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
@@ -762,7 +762,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
if (i2c_name) {
snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
"%s%s", "i2c-", i2c_name);
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index d955836..456526a 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -38,6 +38,8 @@ enum {
BYT_RT5651_DMIC_MAP,
BYT_RT5651_IN1_MAP,
BYT_RT5651_IN2_MAP,
+ BYT_RT5651_IN1_IN2_MAP,
+ BYT_RT5651_IN3_MAP,
};
#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0))
@@ -62,6 +64,8 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk IN1_MAP enabled");
if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
dev_info(dev, "quirk IN2_MAP enabled");
+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN3_MAP)
+ dev_info(dev, "quirk IN3_MAP enabled");
if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN)
dev_info(dev, "quirk DMIC enabled");
if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
@@ -127,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Internal Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
@@ -138,6 +143,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"Headset Mic", NULL, "Platform Clock"},
{"Internal Mic", NULL, "Platform Clock"},
{"Speaker", NULL, "Platform Clock"},
+ {"Line In", NULL, "Platform Clock"},
{"AIF1 Playback", NULL, "ssp2 Tx"},
{"ssp2 Tx", NULL, "codec_out0"},
@@ -151,6 +157,9 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"Headphone", NULL, "HPOR"},
{"Speaker", NULL, "LOUTL"},
{"Speaker", NULL, "LOUTR"},
+ {"IN2P", NULL, "Line In"},
+ {"IN2N", NULL, "Line In"},
+
};
static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = {
@@ -171,11 +180,25 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
{"IN2P", NULL, "Internal Mic"},
};
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
+ {"Internal Mic", NULL, "micbias1"},
+ {"IN1P", NULL, "Internal Mic"},
+ {"IN2P", NULL, "Internal Mic"},
+ {"IN3P", NULL, "Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in3_map[] = {
+ {"Internal Mic", NULL, "micbias1"},
+ {"IN3P", NULL, "Headset Mic"},
+ {"IN1P", NULL, "Internal Mic"},
+};
+
static const struct snd_kcontrol_new byt_rt5651_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Internal Mic"),
SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Line In"),
};
static struct snd_soc_jack_pin bytcr_jack_pins[] = {
@@ -247,8 +270,16 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
},
- .driver_data = (void *)(BYT_RT5651_DMIC_MAP |
- BYT_RT5651_DMIC_EN),
+ .driver_data = (void *)(BYT_RT5651_IN3_MAP),
+ },
+ {
+ .callback = byt_rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ADI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"),
+ },
+ .driver_data = (void *)(BYT_RT5651_MCLK_EN |
+ BYT_RT5651_IN3_MAP),
},
{
.callback = byt_rt5651_quirk_cb,
@@ -256,7 +287,8 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
},
- .driver_data = (void *)(BYT_RT5651_IN2_MAP),
+ .driver_data = (void *)(BYT_RT5651_MCLK_EN |
+ BYT_RT5651_IN1_IN2_MAP),
},
{}
};
@@ -281,6 +313,14 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
custom_map = byt_rt5651_intmic_in2_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
break;
+ case BYT_RT5651_IN1_IN2_MAP:
+ custom_map = byt_rt5651_intmic_in1_in2_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
+ break;
+ case BYT_RT5651_IN3_MAP:
+ custom_map = byt_rt5651_intmic_in3_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_in3_map);
+ break;
default:
custom_map = byt_rt5651_intmic_dmic_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
@@ -469,7 +509,7 @@ static struct snd_soc_card byt_rt5651_card = {
.fully_routed = true,
};
-static char byt_rt5651_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
{
@@ -499,7 +539,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
if (i2c_name) {
snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name),
"%s%s", "i2c-", i2c_name);
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 18d129c..31641aa 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -49,7 +49,7 @@ struct cht_acpi_card {
struct cht_mc_private {
struct snd_soc_jack jack;
struct cht_acpi_card *acpi_card;
- char codec_name[16];
+ char codec_name[SND_ACPI_I2C_ID_LEN];
struct clk *mclk;
};
@@ -118,6 +118,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Analog Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -128,6 +129,8 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
{"IN1N", NULL, "Headset Mic"},
{"DMIC L1", NULL, "Int Mic"},
{"DMIC R1", NULL, "Int Mic"},
+ {"IN2P", NULL, "Int Analog Mic"},
+ {"IN2N", NULL, "Int Analog Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
{"Ext Spk", NULL, "SPOL"},
@@ -135,6 +138,9 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
{"Headphone", NULL, "Platform Clock"},
{"Headset Mic", NULL, "Platform Clock"},
{"Int Mic", NULL, "Platform Clock"},
+ {"Int Analog Mic", NULL, "Platform Clock"},
+ {"Int Analog Mic", NULL, "micbias1"},
+ {"Int Analog Mic", NULL, "micbias2"},
{"Ext Spk", NULL, "Platform Clock"},
};
@@ -189,6 +195,7 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Analog Mic"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
@@ -499,7 +506,7 @@ static struct cht_acpi_card snd_soc_cards[] = {
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
};
-static char cht_rt5645_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+static char cht_rt5645_codec_name[SND_ACPI_I2C_ID_LEN];
static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */
static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
@@ -566,7 +573,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
if (i2c_name) {
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
"%s%s", "i2c-", i2c_name);
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index f8f21ee..c14a52d 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -35,7 +35,7 @@
struct cht_mc_private {
struct snd_soc_jack headset;
- char codec_name[16];
+ char codec_name[SND_ACPI_I2C_ID_LEN];
struct clk *mclk;
};
@@ -396,7 +396,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* fixup codec name based on HID */
if (mach) {
- i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
if (i2c_name) {
snprintf(drv->codec_name, sizeof(drv->codec_name),
"i2c-%s", i2c_name);
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
index 5e1ea03..3c516077 100644
--- a/sound/soc/intel/boards/haswell.c
+++ b/sound/soc/intel/boards/haswell.c
@@ -76,7 +76,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
}
/* set correct codec filter for DAI format and clock config */
- snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
+ snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
return ret;
}
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 6f9a8bc..bf7014c 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -101,7 +101,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "hs_out" },
+ { "ssp1 Tx", NULL, "codec1_out" },
{ "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
@@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
}
jack = &ctx->kabylake_headset;
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 6072164..90ea98f 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -109,7 +109,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "hs_out" },
+ { "ssp1 Tx", NULL, "codec1_out" },
{ "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
@@ -195,7 +195,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
}
jack = &ctx->kabylake_headset;
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c
deleted file mode 100644
index 6f44acf..0000000
--- a/sound/soc/intel/boards/mfld_machine.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
- *
- * Copyright (C) 2010 Intel Corp
- * Author: Vinod Koul <vinod.koul@intel.com>
- * Author: Harsha Priya <priya.harsha@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include "../codecs/sn95031.h"
-
-#define MID_MONO 1
-#define MID_STEREO 2
-#define MID_MAX_CAP 5
-#define MFLD_JACK_INSERT 0x04
-
-enum soc_mic_bias_zones {
- MFLD_MV_START = 0,
- /* mic bias volutage range for Headphones*/
- MFLD_MV_HP = 400,
- /* mic bias volutage range for American Headset*/
- MFLD_MV_AM_HS = 650,
- /* mic bias volutage range for Headset*/
- MFLD_MV_HS = 2000,
- MFLD_MV_UNDEFINED,
-};
-
-static unsigned int hs_switch;
-static unsigned int lo_dac;
-static struct snd_soc_codec *mfld_codec;
-
-struct mfld_mc_private {
- void __iomem *int_base;
- u8 interrupt_status;
-};
-
-struct snd_soc_jack mfld_jack;
-
-/*Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin mfld_jack_pins[] = {
- {
- .pin = "Headphones",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "AMIC1",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-/* jack detection voltage zones */
-static struct snd_soc_jack_zone mfld_zones[] = {
- {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
- {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
-};
-
-/* sound card controls */
-static const char * const headset_switch_text[] = {"Earpiece", "Headset"};
-
-static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"};
-
-static const struct soc_enum headset_enum =
- SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
-
-static const struct soc_enum lo_enum =
- SOC_ENUM_SINGLE_EXT(4, lo_text);
-
-static int headset_get_switch(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] = hs_switch;
- return 0;
-}
-
-static int headset_set_switch(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = &card->dapm;
-
- if (ucontrol->value.enumerated.item[0] == hs_switch)
- return 0;
-
- snd_soc_dapm_mutex_lock(dapm);
-
- if (ucontrol->value.enumerated.item[0]) {
- pr_debug("hs_set HS path\n");
- snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
- snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
- } else {
- pr_debug("hs_set EP path\n");
- snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
- snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
- }
-
- snd_soc_dapm_sync_unlocked(dapm);
-
- snd_soc_dapm_mutex_unlock(dapm);
-
- hs_switch = ucontrol->value.enumerated.item[0];
-
- return 0;
-}
-
-static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
-{
- snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
- snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
- snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
- snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
- snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
- snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
- if (hs_switch) {
- snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
- snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
- } else {
- snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
- snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
- }
-}
-
-static int lo_get_switch(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] = lo_dac;
- return 0;
-}
-
-static int lo_set_switch(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = &card->dapm;
-
- if (ucontrol->value.enumerated.item[0] == lo_dac)
- return 0;
-
- snd_soc_dapm_mutex_lock(dapm);
-
- /* we dont want to work with last state of lineout so just enable all
- * pins and then disable pins not required
- */
- lo_enable_out_pins(dapm);
-
- switch (ucontrol->value.enumerated.item[0]) {
- case 0:
- pr_debug("set vibra path\n");
- snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
- snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
- snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
- break;
-
- case 1:
- pr_debug("set hs path\n");
- snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
- snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
- snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
- break;
-
- case 2:
- pr_debug("set spkr path\n");
- snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
- snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
- snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
- break;
-
- case 3:
- pr_debug("set null path\n");
- snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
- snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
- snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
- break;
- }
-
- snd_soc_dapm_sync_unlocked(dapm);
-
- snd_soc_dapm_mutex_unlock(dapm);
-
- lo_dac = ucontrol->value.enumerated.item[0];
- return 0;
-}
-
-static const struct snd_kcontrol_new mfld_snd_controls[] = {
- SOC_ENUM_EXT("Playback Switch", headset_enum,
- headset_get_switch, headset_set_switch),
- SOC_ENUM_EXT("Lineout Mux", lo_enum,
- lo_get_switch, lo_set_switch),
-};
-
-static const struct snd_soc_dapm_widget mfld_widgets[] = {
- SND_SOC_DAPM_HP("Headphones", NULL),
- SND_SOC_DAPM_MIC("Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route mfld_map[] = {
- {"Headphones", NULL, "HPOUTR"},
- {"Headphones", NULL, "HPOUTL"},
- {"Mic", NULL, "AMIC1"},
-};
-
-static void mfld_jack_check(unsigned int intr_status)
-{
- struct mfld_jack_data jack_data;
-
- if (!mfld_codec)
- return;
-
- jack_data.mfld_jack = &mfld_jack;
- jack_data.intr_id = intr_status;
-
- sn95031_jack_detection(mfld_codec, &jack_data);
- /* TODO: add american headset detection post gpiolib support */
-}
-
-static int mfld_init(struct snd_soc_pcm_runtime *runtime)
-{
- struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
- int ret_val;
-
- /* default is earpiece pin, userspace sets it explcitly */
- snd_soc_dapm_disable_pin(dapm, "Headphones");
- /* default is lineout NC, userspace sets it explcitly */
- snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
- snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
- lo_dac = 3;
- hs_switch = 0;
- /* we dont use linein in this so set to NC */
- snd_soc_dapm_disable_pin(dapm, "LINEINL");
- snd_soc_dapm_disable_pin(dapm, "LINEINR");
-
- /* Headset and button jack detection */
- ret_val = snd_soc_card_jack_new(runtime->card,
- "Intel(R) MID Audio Jack", SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
- mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
- if (ret_val) {
- pr_err("jack creation failed\n");
- return ret_val;
- }
-
- ret_val = snd_soc_jack_add_zones(&mfld_jack,
- ARRAY_SIZE(mfld_zones), mfld_zones);
- if (ret_val) {
- pr_err("adding jack zones failed\n");
- return ret_val;
- }
-
- mfld_codec = runtime->codec;
-
- /* we want to check if anything is inserted at boot,
- * so send a fake event to codec and it will read adc
- * to find if anything is there or not */
- mfld_jack_check(MFLD_JACK_INSERT);
- return ret_val;
-}
-
-static struct snd_soc_dai_link mfld_msic_dailink[] = {
- {
- .name = "Medfield Headset",
- .stream_name = "Headset",
- .cpu_dai_name = "Headset-cpu-dai",
- .codec_dai_name = "SN95031 Headset",
- .codec_name = "sn95031",
- .platform_name = "sst-platform",
- .init = mfld_init,
- },
- {
- .name = "Medfield Speaker",
- .stream_name = "Speaker",
- .cpu_dai_name = "Speaker-cpu-dai",
- .codec_dai_name = "SN95031 Speaker",
- .codec_name = "sn95031",
- .platform_name = "sst-platform",
- .init = NULL,
- },
- {
- .name = "Medfield Vibra",
- .stream_name = "Vibra1",
- .cpu_dai_name = "Vibra1-cpu-dai",
- .codec_dai_name = "SN95031 Vibra1",
- .codec_name = "sn95031",
- .platform_name = "sst-platform",
- .init = NULL,
- },
- {
- .name = "Medfield Haptics",
- .stream_name = "Vibra2",
- .cpu_dai_name = "Vibra2-cpu-dai",
- .codec_dai_name = "SN95031 Vibra2",
- .codec_name = "sn95031",
- .platform_name = "sst-platform",
- .init = NULL,
- },
- {
- .name = "Medfield Compress",
- .stream_name = "Speaker",
- .cpu_dai_name = "Compress-cpu-dai",
- .codec_dai_name = "SN95031 Speaker",
- .codec_name = "sn95031",
- .platform_name = "sst-platform",
- .init = NULL,
- },
-};
-
-/* SoC card */
-static struct snd_soc_card snd_soc_card_mfld = {
- .name = "medfield_audio",
- .owner = THIS_MODULE,
- .dai_link = mfld_msic_dailink,
- .num_links = ARRAY_SIZE(mfld_msic_dailink),
-
- .controls = mfld_snd_controls,
- .num_controls = ARRAY_SIZE(mfld_snd_controls),
- .dapm_widgets = mfld_widgets,
- .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
- .dapm_routes = mfld_map,
- .num_dapm_routes = ARRAY_SIZE(mfld_map),
-};
-
-static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
-{
- struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
-
- memcpy_fromio(&mc_private->interrupt_status,
- ((void *)(mc_private->int_base)),
- sizeof(u8));
- return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
-{
- struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
-
- mfld_jack_check(mc_drv_ctx->interrupt_status);
-
- return IRQ_HANDLED;
-}
-
-static int snd_mfld_mc_probe(struct platform_device *pdev)
-{
- int ret_val = 0, irq;
- struct mfld_mc_private *mc_drv_ctx;
- struct resource *irq_mem;
-
- pr_debug("snd_mfld_mc_probe called\n");
-
- /* retrive the irq number */
- irq = platform_get_irq(pdev, 0);
-
- /* audio interrupt base of SRAM location where
- * interrupts are stored by System FW */
- mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
- if (!mc_drv_ctx)
- return -ENOMEM;
-
- irq_mem = platform_get_resource_byname(
- pdev, IORESOURCE_MEM, "IRQ_BASE");
- if (!irq_mem) {
- pr_err("no mem resource given\n");
- return -ENODEV;
- }
- mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
- resource_size(irq_mem));
- if (!mc_drv_ctx->int_base) {
- pr_err("Mapping of cache failed\n");
- return -ENOMEM;
- }
- /* register for interrupt */
- ret_val = devm_request_threaded_irq(&pdev->dev, irq,
- snd_mfld_jack_intr_handler,
- snd_mfld_jack_detection,
- IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
- if (ret_val) {
- pr_err("cannot register IRQ\n");
- return ret_val;
- }
- /* register the soc card */
- snd_soc_card_mfld.dev = &pdev->dev;
- ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
- if (ret_val) {
- pr_debug("snd_soc_register_card failed %d\n", ret_val);
- return ret_val;
- }
- platform_set_drvdata(pdev, mc_drv_ctx);
- pr_debug("successfully exited probe\n");
- return 0;
-}
-
-static struct platform_driver snd_mfld_mc_driver = {
- .driver = {
- .name = "msic_audio",
- },
- .probe = snd_mfld_mc_probe,
-};
-
-module_platform_driver(snd_mfld_mc_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:msic-audio");
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
index 11c0805..fd82f4b 100644
--- a/sound/soc/intel/common/sst-dsp.c
+++ b/sound/soc/intel/common/sst-dsp.c
@@ -269,7 +269,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
*/
timeout = jiffies + msecs_to_jiffies(time);
- while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target)
+ while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
&& time_before(jiffies, timeout)) {
k++;
if (k > 10)
@@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
usleep_range(s, 2*s);
}
- reg = sst_dsp_shim_read_unlocked(ctx, offset);
-
if ((reg & mask) == target) {
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
reg, operation);
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index 4524211..440bca7 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -595,7 +595,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
skl->d0i3.state = SKL_DSP_D0I3_NONE;
- return 0;
+ return skl_dsp_acquire_irq(sst);
}
EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
index 387de38..245df10 100644
--- a/sound/soc/intel/skylake/cnl-sst.c
+++ b/sound/soc/intel/skylake/cnl-sst.c
@@ -458,7 +458,7 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
cnl->boot_complete = false;
init_waitqueue_head(&cnl->boot_wait);
- return 0;
+ return skl_dsp_acquire_irq(sst);
}
EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h
new file mode 100644
index 0000000..dcf819b
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-i2s.h
@@ -0,0 +1,64 @@
+/*
+ * skl-i2s.h - i2s blob mapping
+ *
+ * Copyright (C) 2017 Intel Corp
+ * Author: Subhransu S. Prusty < subhransu.s.prusty@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef __SOUND_SOC_SKL_I2S_H
+#define __SOUND_SOC_SKL_I2S_H
+
+#define SKL_I2S_MAX_TIME_SLOTS 8
+#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16)
+
+#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20)
+#define SKL_SHIFT(x) (ffs(x) - 1)
+#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0)
+
+struct skl_i2s_config {
+ u32 ssc0;
+ u32 ssc1;
+ u32 sscto;
+ u32 sspsp;
+ u32 sstsa;
+ u32 ssrsa;
+ u32 ssc2;
+ u32 sspsp2;
+ u32 ssc3;
+ u32 ssioc;
+} __packed;
+
+struct skl_i2s_config_mclk {
+ u32 mdivctrl;
+ u32 mdivr;
+};
+
+/**
+ * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway
+ * configuration legacy blob
+ *
+ * @gtw_attr: Gateway attribute for the I2S Gateway
+ * @tdm_ts_group: TDM slot mapping against channels in the Gateway.
+ * @i2s_cfg: I2S HW registers
+ * @mclk: MCLK clock source and divider values
+ */
+struct skl_i2s_config_blob_legacy {
+ u32 gtw_attr;
+ u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
+ struct skl_i2s_config i2s_cfg;
+ struct skl_i2s_config_mclk mclk;
+};
+
+#endif /* __SOUND_SOC_SKL_I2S_H */
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 61b5bfa..8cbf080 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -55,6 +55,19 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
return 0;
}
+#define SKL_ASTATE_PARAM_ID 4
+
+void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data)
+{
+ struct skl_ipc_large_config_msg msg = {0};
+
+ msg.large_param_id = SKL_ASTATE_PARAM_ID;
+ msg.param_data_size = (cnt * sizeof(struct skl_astate_param) +
+ sizeof(cnt));
+
+ skl_ipc_set_large_config(&ctx->ipc, &msg, data);
+}
+
#define NOTIFICATION_PARAM_ID 3
#define NOTIFICATION_MASK 0xf
@@ -404,11 +417,20 @@ int skl_resume_dsp(struct skl *skl)
if (skl->skl_sst->is_first_boot == true)
return 0;
+ /* disable dynamic clock gating during fw and lib download */
+ ctx->enable_miscbdcge(ctx->dev, false);
+
ret = skl_dsp_wake(ctx->dsp);
+ ctx->enable_miscbdcge(ctx->dev, true);
if (ret < 0)
return ret;
skl_dsp_enable_notification(skl->skl_sst, false);
+
+ if (skl->cfg.astate_cfg != NULL) {
+ skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count,
+ skl->cfg.astate_cfg);
+ }
return ret;
}
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index d14c50a..3b1d2b8 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -19,6 +19,7 @@
*/
#include <linux/pci.h>
#include "skl.h"
+#include "skl-i2s.h"
#define NHLT_ACPI_HEADER_SIG "NHLT"
@@ -43,7 +44,8 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL);
if (obj && obj->type == ACPI_TYPE_BUFFER) {
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
- nhlt_table = (struct nhlt_acpi_table *)
+ if (nhlt_ptr->length)
+ nhlt_table = (struct nhlt_acpi_table *)
memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
MEMREMAP_WB);
ACPI_FREE(obj);
@@ -119,11 +121,16 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
if ((epnt->virtual_bus_id == instance_id) &&
(epnt->linktype == link_type) &&
- (epnt->direction == dirn) &&
- (epnt->device_type == dev_type))
- return true;
- else
- return false;
+ (epnt->direction == dirn)) {
+ /* do not check dev_type for DMIC link type */
+ if (epnt->linktype == NHLT_LINK_DMIC)
+ return true;
+
+ if (epnt->device_type == dev_type)
+ return true;
+ }
+
+ return false;
}
struct nhlt_specific_cfg
@@ -271,3 +278,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl)
sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
}
+
+/*
+ * Queries NHLT for all the fmt configuration for a particular endpoint and
+ * stores all possible rates supported in a rate table for the corresponding
+ * sclk/sclkfs.
+ */
+static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
+ struct nhlt_fmt *fmt, u8 id)
+{
+ struct skl_i2s_config_blob_legacy *i2s_config;
+ struct skl_clk_parent_src *parent;
+ struct skl_ssp_clk *sclk, *sclkfs;
+ struct nhlt_fmt_cfg *fmt_cfg;
+ struct wav_fmt_ext *wav_fmt;
+ unsigned long rate = 0;
+ bool present = false;
+ int rate_index = 0;
+ u16 channels, bps;
+ u8 clk_src;
+ int i, j;
+ u32 fs;
+
+ sclk = &ssp_clks[SKL_SCLK_OFS];
+ sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
+
+ if (fmt->fmt_count == 0)
+ return;
+
+ for (i = 0; i < fmt->fmt_count; i++) {
+ fmt_cfg = &fmt->fmt_config[i];
+ wav_fmt = &fmt_cfg->fmt_ext;
+
+ channels = wav_fmt->fmt.channels;
+ bps = wav_fmt->fmt.bits_per_sample;
+ fs = wav_fmt->fmt.samples_per_sec;
+
+ /*
+ * In case of TDM configuration on a ssp, there can
+ * be more than one blob in which channel masks are
+ * different for each usecase for a specific rate and bps.
+ * But the sclk rate will be generated for the total
+ * number of channels used for that endpoint.
+ *
+ * So for the given fs and bps, choose blob which has
+ * the superset of all channels for that endpoint and
+ * derive the rate.
+ */
+ for (j = i; j < fmt->fmt_count; j++) {
+ fmt_cfg = &fmt->fmt_config[j];
+ wav_fmt = &fmt_cfg->fmt_ext;
+ if ((fs == wav_fmt->fmt.samples_per_sec) &&
+ (bps == wav_fmt->fmt.bits_per_sample))
+ channels = max_t(u16, channels,
+ wav_fmt->fmt.channels);
+ }
+
+ rate = channels * bps * fs;
+
+ /* check if the rate is added already to the given SSP's sclk */
+ for (j = 0; (j < SKL_MAX_CLK_RATES) &&
+ (sclk[id].rate_cfg[j].rate != 0); j++) {
+ if (sclk[id].rate_cfg[j].rate == rate) {
+ present = true;
+ break;
+ }
+ }
+
+ /* Fill rate and parent for sclk/sclkfs */
+ if (!present) {
+ /* MCLK Divider Source Select */
+ i2s_config = (struct skl_i2s_config_blob_legacy *)
+ fmt->fmt_config[0].config.caps;
+ clk_src = ((i2s_config->mclk.mdivctrl)
+ & SKL_MNDSS_DIV_CLK_SRC_MASK) >>
+ SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK);
+
+ parent = skl_get_parent_clk(clk_src);
+
+ /*
+ * Do not copy the config data if there is no parent
+ * clock available for this clock source select
+ */
+ if (!parent)
+ continue;
+
+ sclk[id].rate_cfg[rate_index].rate = rate;
+ sclk[id].rate_cfg[rate_index].config = fmt_cfg;
+ sclkfs[id].rate_cfg[rate_index].rate = rate;
+ sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
+ sclk[id].parent_name = parent->name;
+ sclkfs[id].parent_name = parent->name;
+
+ rate_index++;
+ }
+ }
+}
+
+static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
+ struct nhlt_fmt *fmt, u8 id)
+{
+ struct skl_i2s_config_blob_legacy *i2s_config;
+ struct nhlt_specific_cfg *fmt_cfg;
+ struct skl_clk_parent_src *parent;
+ u32 clkdiv, div_ratio;
+ u8 clk_src;
+
+ fmt_cfg = &fmt->fmt_config[0].config;
+ i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps;
+
+ /* MCLK Divider Source Select */
+ clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >>
+ SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK);
+
+ clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK;
+
+ /* bypass divider */
+ div_ratio = 1;
+
+ if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
+ /* Divider is 2 + clkdiv */
+ div_ratio = clkdiv + 2;
+
+ /* Calculate MCLK rate from source using div value */
+ parent = skl_get_parent_clk(clk_src);
+ if (!parent)
+ return;
+
+ mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
+ mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
+ mclk[id].parent_name = parent->name;
+}
+
+void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks)
+{
+ struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
+ struct nhlt_endpoint *epnt;
+ struct nhlt_fmt *fmt;
+ int i;
+ u8 id;
+
+ epnt = (struct nhlt_endpoint *)nhlt->desc;
+ for (i = 0; i < nhlt->endpoint_count; i++) {
+ if (epnt->linktype == NHLT_LINK_SSP) {
+ id = epnt->virtual_bus_id;
+
+ fmt = (struct nhlt_fmt *)(epnt->config.caps
+ + epnt->config.size);
+
+ skl_get_ssp_clks(skl, ssp_clks, fmt, id);
+ skl_get_mclk(skl, ssp_clks, fmt, id);
+ }
+ epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
+ }
+}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 1dd9747..e468285 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -537,7 +537,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
+ link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -620,7 +620,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
link_dev->link_prepared = 0;
- link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
+ link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -1343,7 +1343,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
return -EIO;
}
+ /* disable dynamic clock gating during fw and lib download */
+ skl->skl_sst->enable_miscbdcge(platform->dev, false);
+
ret = ops->init_fw(platform->dev, skl->skl_sst);
+ skl->skl_sst->enable_miscbdcge(platform->dev, true);
if (ret < 0) {
dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
return ret;
@@ -1351,6 +1355,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
skl_populate_modules(skl);
skl->skl_sst->update_d0i3c = skl_update_d0i3c;
skl_dsp_enable_notification(skl->skl_sst, false);
+
+ if (skl->cfg.astate_cfg != NULL) {
+ skl_dsp_set_astate_cfg(skl->skl_sst,
+ skl->cfg.astate_cfg->count,
+ skl->cfg.astate_cfg);
+ }
}
pm_runtime_mark_last_busy(platform->dev);
pm_runtime_put_autosuspend(platform->dev);
diff --git a/sound/soc/intel/skylake/skl-ssp-clk.h b/sound/soc/intel/skylake/skl-ssp-clk.h
new file mode 100644
index 0000000..c9ea840
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-ssp-clk.h
@@ -0,0 +1,79 @@
+/*
+ * skl-ssp-clk.h - Skylake ssp clock information and ipc structure
+ *
+ * Copyright (C) 2017 Intel Corp
+ * Author: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
+ * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef SOUND_SOC_SKL_SSP_CLK_H
+#define SOUND_SOC_SKL_SSP_CLK_H
+
+#define SKL_MAX_SSP 6
+/* xtal/cardinal/pll, parent of ssp clocks and mclk */
+#define SKL_MAX_CLK_SRC 3
+#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */
+
+#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES)
+
+/* Max number of configurations supported for each clock */
+#define SKL_MAX_CLK_RATES 10
+
+#define SKL_SCLK_OFS SKL_MAX_SSP
+#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP)
+
+enum skl_clk_type {
+ SKL_MCLK,
+ SKL_SCLK,
+ SKL_SCLK_FS,
+};
+
+enum skl_clk_src_type {
+ SKL_XTAL,
+ SKL_CARDINAL,
+ SKL_PLL,
+};
+
+struct skl_clk_parent_src {
+ u8 clk_id;
+ const char *name;
+ unsigned long rate;
+ const char *parent_name;
+};
+
+struct skl_clk_rate_cfg_table {
+ unsigned long rate;
+ void *config;
+};
+
+/*
+ * rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store
+ * all possible clocks ssp can generate for that platform.
+ */
+struct skl_ssp_clk {
+ const char *name;
+ const char *parent_name;
+ struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES];
+};
+
+struct skl_clk_pdata {
+ struct skl_clk_parent_src *parent_clks;
+ int num_clks;
+ struct skl_ssp_clk *ssp_clks;
+ void *pvt_data;
+};
+
+#endif /* SOUND_SOC_SKL_SSP_CLK_H */
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c
index 19ee1d4..71e31ad 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.c
+++ b/sound/soc/intel/skylake/skl-sst-dsp.c
@@ -435,16 +435,22 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
return NULL;
}
+ return sst;
+}
+
+int skl_dsp_acquire_irq(struct sst_dsp *sst)
+{
+ struct sst_dsp_device *sst_dev = sst->sst_dev;
+ int ret;
+
/* Register the ISR */
ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
- if (ret) {
+ if (ret)
dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
sst->irq);
- return NULL;
- }
- return sst;
+ return ret;
}
void skl_dsp_free(struct sst_dsp *dsp)
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index eba20d3..12fc9a7 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -206,6 +206,7 @@ int skl_cldma_wait_interruptible(struct sst_dsp *ctx);
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq);
+int skl_dsp_acquire_irq(struct sst_dsp *sst);
bool is_skl_dsp_running(struct sst_dsp *ctx);
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
@@ -251,6 +252,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx);
int skl_dsp_strip_extended_manifest(struct firmware *fw);
void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable);
+
+void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data);
+
int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
struct sst_dsp_device *skl_dev);
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 8ff8928..2ae4056 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -178,7 +178,8 @@ static inline int skl_pvtid_128(struct uuid_module *module)
* skl_get_pvt_id: generate a private id for use as module id
*
* @ctx: driver context
- * @mconfig: module configuration data
+ * @uuid_mod: module's uuid
+ * @instance_id: module's instance id
*
* This generates a 128 bit private unique id for a module TYPE so that
* module instance is unique
@@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
* skl_put_pvt_id: free up the private id allocated
*
* @ctx: driver context
- * @mconfig: module configuration data
+ * @uuid_mod: module's uuid
+ * @pvt_id: module pvt id
*
* This frees a 128 bit private unique id previously generated
*/
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index a436abf..5a7e41b6 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst->fw_ops = skl_fw_ops;
- return 0;
+ return skl_dsp_acquire_irq(sst);
}
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index a072bcf..73af6e1 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -190,7 +190,6 @@ skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
u8 res_idx = mconfig->res_idx;
struct skl_module_res *res = &mconfig->module->resources[res_idx];
- res = &mconfig->module->resources[res_idx];
skl->resource.mcps -= res->cps;
}
@@ -2908,7 +2907,7 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
break;
default:
- dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
+ dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
hdr->ops.get, hdr->ops.put, hdr->ops.info);
break;
}
@@ -3056,11 +3055,13 @@ static int skl_tplg_get_int_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl *skl)
{
- int tkn_count = 0, ret;
+ int tkn_count = 0, ret, size;
static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
struct skl_module_res *res = NULL;
struct skl_module_iface *fmt = NULL;
struct skl_module *mod = NULL;
+ static struct skl_astate_param *astate_table;
+ static int astate_cfg_idx, count;
int i;
if (skl->modules) {
@@ -3093,6 +3094,46 @@ static int skl_tplg_get_int_tkn(struct device *dev,
mod_idx = tkn_elem->value;
break;
+ case SKL_TKN_U32_ASTATE_COUNT:
+ if (astate_table != NULL) {
+ dev_err(dev, "More than one entry for A-State count");
+ return -EINVAL;
+ }
+
+ if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
+ dev_err(dev, "Invalid A-State count %d\n",
+ tkn_elem->value);
+ return -EINVAL;
+ }
+
+ size = tkn_elem->value * sizeof(struct skl_astate_param) +
+ sizeof(count);
+ skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (!skl->cfg.astate_cfg)
+ return -ENOMEM;
+
+ astate_table = skl->cfg.astate_cfg->astate_table;
+ count = skl->cfg.astate_cfg->count = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_ASTATE_IDX:
+ if (tkn_elem->value >= count) {
+ dev_err(dev, "Invalid A-State index %d\n",
+ tkn_elem->value);
+ return -EINVAL;
+ }
+
+ astate_cfg_idx = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_ASTATE_KCPS:
+ astate_table[astate_cfg_idx].kcps = tkn_elem->value;
+ break;
+
+ case SKL_TKN_U32_ASTATE_CLK_SRC:
+ astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
+ break;
+
case SKL_TKN_U8_IN_PIN_TYPE:
case SKL_TKN_U8_OUT_PIN_TYPE:
case SKL_TKN_U8_IN_QUEUE_COUNT:
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 31d8634..32ce64c 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -355,6 +355,7 @@ static int skl_resume(struct device *dev)
if (ebus->cmd_dma_state)
snd_hdac_bus_init_cmd_io(&ebus->bus);
+ ret = 0;
} else {
ret = _skl_resume(ebus);
@@ -435,19 +436,51 @@ static int skl_free(struct hdac_ext_bus *ebus)
return 0;
}
-static int skl_machine_device_register(struct skl *skl, void *driver_data)
+/*
+ * For each ssp there are 3 clocks (mclk/sclk/sclkfs).
+ * e.g. for ssp0, clocks will be named as
+ * "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs"
+ * So for skl+, there are 6 ssps, so 18 clocks will be created.
+ */
+static struct skl_ssp_clk skl_ssp_clks[] = {
+ {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"},
+ {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"},
+ {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"},
+ {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"},
+ {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"},
+ {.name = "ssp2_sclkfs"},
+ {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"},
+ {.name = "ssp5_sclkfs"},
+};
+
+static int skl_find_machine(struct skl *skl, void *driver_data)
{
- struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
- struct platform_device *pdev;
struct snd_soc_acpi_mach *mach = driver_data;
- int ret;
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct skl_machine_pdata *pdata;
mach = snd_soc_acpi_find_machine(mach);
if (mach == NULL) {
dev_err(bus->dev, "No matching machine driver found\n");
return -ENODEV;
}
+
+ skl->mach = mach;
skl->fw_name = mach->fw_filename;
+ pdata = skl->mach->pdata;
+
+ if (mach->pdata)
+ skl->use_tplg_pcm = pdata->use_tplg_pcm;
+
+ return 0;
+}
+
+static int skl_machine_device_register(struct skl *skl)
+{
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct snd_soc_acpi_mach *mach = skl->mach;
+ struct platform_device *pdev;
+ int ret;
pdev = platform_device_alloc(mach->drv_name, -1);
if (pdev == NULL) {
@@ -462,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
return -EIO;
}
- if (mach->pdata) {
- skl->use_tplg_pcm =
- ((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm;
+ if (mach->pdata)
dev_set_drvdata(&pdev->dev, mach->pdata);
- }
skl->i2s_dev = pdev;
@@ -509,6 +539,74 @@ static void skl_dmic_device_unregister(struct skl *skl)
platform_device_unregister(skl->dmic_dev);
}
+static struct skl_clk_parent_src skl_clk_src[] = {
+ { .clk_id = SKL_XTAL, .name = "xtal" },
+ { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 },
+ { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 },
+};
+
+struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) {
+ if (skl_clk_src[i].clk_id == clk_id)
+ return &skl_clk_src[i];
+ }
+
+ return NULL;
+}
+
+static void init_skl_xtal_rate(int pci_id)
+{
+ switch (pci_id) {
+ case 0x9d70:
+ case 0x9d71:
+ skl_clk_src[0].rate = 24000000;
+ return;
+
+ default:
+ skl_clk_src[0].rate = 19200000;
+ return;
+ }
+}
+
+static int skl_clock_device_register(struct skl *skl)
+{
+ struct platform_device_info pdevinfo = {NULL};
+ struct skl_clk_pdata *clk_pdata;
+
+ clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
+ GFP_KERNEL);
+ if (!clk_pdata)
+ return -ENOMEM;
+
+ init_skl_xtal_rate(skl->pci->device);
+
+ clk_pdata->parent_clks = skl_clk_src;
+ clk_pdata->ssp_clks = skl_ssp_clks;
+ clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks);
+
+ /* Query NHLT to fill the rates and parent */
+ skl_get_clks(skl, clk_pdata->ssp_clks);
+ clk_pdata->pvt_data = skl;
+
+ /* Register Platform device */
+ pdevinfo.parent = &skl->pci->dev;
+ pdevinfo.id = -1;
+ pdevinfo.name = "skl-ssp-clk";
+ pdevinfo.data = clk_pdata;
+ pdevinfo.size_data = sizeof(*clk_pdata);
+ skl->clk_dev = platform_device_register_full(&pdevinfo);
+ return PTR_ERR_OR_ZERO(skl->clk_dev);
+}
+
+static void skl_clock_device_unregister(struct skl *skl)
+{
+ if (skl->clk_dev)
+ platform_device_unregister(skl->clk_dev);
+}
+
/*
* Probe the given codec address
*/
@@ -615,18 +713,30 @@ static void skl_probe_work(struct work_struct *work)
/* create codec instances */
skl_codec_create(ebus);
+ /* register platform dai and controls */
+ err = skl_platform_register(bus->dev);
+ if (err < 0) {
+ dev_err(bus->dev, "platform register failed: %d\n", err);
+ return;
+ }
+
+ if (bus->ppcap) {
+ err = skl_machine_device_register(skl);
+ if (err < 0) {
+ dev_err(bus->dev, "machine register failed: %d\n", err);
+ goto out_err;
+ }
+ }
+
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = snd_hdac_display_power(bus, false);
if (err < 0) {
dev_err(bus->dev, "Cannot turn off display power on i915\n");
+ skl_machine_device_unregister(skl);
return;
}
}
- /* register platform dai and controls */
- err = skl_platform_register(bus->dev);
- if (err < 0)
- return;
/*
* we are done probing so decrement link counts
*/
@@ -791,18 +901,21 @@ static int skl_probe(struct pci_dev *pci,
/* check if dsp is there */
if (bus->ppcap) {
- err = skl_machine_device_register(skl,
- (void *)pci_id->driver_data);
+ /* create device for dsp clk */
+ err = skl_clock_device_register(skl);
+ if (err < 0)
+ goto out_clk_free;
+
+ err = skl_find_machine(skl, (void *)pci_id->driver_data);
if (err < 0)
goto out_nhlt_free;
err = skl_init_dsp(skl);
if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n");
- goto out_mach_free;
+ goto out_nhlt_free;
}
skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
-
}
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(ebus);
@@ -820,8 +933,8 @@ static int skl_probe(struct pci_dev *pci,
out_dsp_free:
skl_free_dsp(skl);
-out_mach_free:
- skl_machine_device_unregister(skl);
+out_clk_free:
+ skl_clock_device_unregister(skl);
out_nhlt_free:
skl_nhlt_free(skl->nhlt);
out_free:
@@ -872,6 +985,7 @@ static void skl_remove(struct pci_dev *pci)
skl_free_dsp(skl);
skl_machine_device_unregister(skl);
skl_dmic_device_unregister(skl);
+ skl_clock_device_unregister(skl);
skl_nhlt_remove_sysfs(skl);
skl_nhlt_free(skl->nhlt);
skl_free(ebus);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index e00cde8..f411579 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -25,9 +25,12 @@
#include <sound/hdaudio_ext.h>
#include <sound/soc.h>
#include "skl-nhlt.h"
+#include "skl-ssp-clk.h"
#define SKL_SUSPEND_DELAY 2000
+#define SKL_MAX_ASTATE_CFG 3
+
#define AZX_PCIREG_PGCTL 0x44
#define AZX_PGCTL_LSRMD_MASK (1 << 4)
#define AZX_PCIREG_CGCTL 0x48
@@ -45,6 +48,20 @@ struct skl_dsp_resource {
struct skl_debug;
+struct skl_astate_param {
+ u32 kcps;
+ u32 clk_src;
+};
+
+struct skl_astate_config {
+ u32 count;
+ struct skl_astate_param astate_table[0];
+};
+
+struct skl_fw_config {
+ struct skl_astate_config *astate_cfg;
+};
+
struct skl {
struct hdac_ext_bus ebus;
struct pci_dev *pci;
@@ -52,6 +69,7 @@ struct skl {
unsigned int init_done:1; /* delayed init status */
struct platform_device *dmic_dev;
struct platform_device *i2s_dev;
+ struct platform_device *clk_dev;
struct snd_soc_platform *platform;
struct snd_soc_dai_driver *dais;
@@ -75,6 +93,8 @@ struct skl {
u8 nr_modules;
struct skl_module **modules;
bool use_tplg_pcm;
+ struct skl_fw_config cfg;
+ struct snd_soc_acpi_mach *mach;
};
#define skl_to_ebus(s) (&(s)->ebus)
@@ -125,6 +145,8 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
void skl_update_d0i3c(struct device *dev, bool enable);
int skl_nhlt_create_sysfs(struct skl *skl);
void skl_nhlt_remove_sysfs(struct skl *skl);
+void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks);
+struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id);
struct skl_module_cfg;
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
index affa7fb..949fc3a 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -14,451 +14,285 @@
* GNU General Public License for more details.
*/
-#include <sound/soc.h>
-#include <linux/regmap.h>
-#include <linux/pm_runtime.h>
-
#include "mt2701-afe-common.h"
#include "mt2701-afe-clock-ctrl.h"
-static const char *aud_clks[MT2701_CLOCK_NUM] = {
- [MT2701_AUD_INFRA_SYS_AUDIO] = "infra_sys_audio_clk",
- [MT2701_AUD_AUD_MUX1_SEL] = "top_audio_mux1_sel",
- [MT2701_AUD_AUD_MUX2_SEL] = "top_audio_mux2_sel",
- [MT2701_AUD_AUD_MUX1_DIV] = "top_audio_mux1_div",
- [MT2701_AUD_AUD_MUX2_DIV] = "top_audio_mux2_div",
- [MT2701_AUD_AUD_48K_TIMING] = "top_audio_48k_timing",
- [MT2701_AUD_AUD_44K_TIMING] = "top_audio_44k_timing",
- [MT2701_AUD_AUDPLL_MUX_SEL] = "top_audpll_mux_sel",
- [MT2701_AUD_APLL_SEL] = "top_apll_sel",
- [MT2701_AUD_AUD1PLL_98M] = "top_aud1_pll_98M",
- [MT2701_AUD_AUD2PLL_90M] = "top_aud2_pll_90M",
- [MT2701_AUD_HADDS2PLL_98M] = "top_hadds2_pll_98M",
- [MT2701_AUD_HADDS2PLL_294M] = "top_hadds2_pll_294M",
- [MT2701_AUD_AUDPLL] = "top_audpll",
- [MT2701_AUD_AUDPLL_D4] = "top_audpll_d4",
- [MT2701_AUD_AUDPLL_D8] = "top_audpll_d8",
- [MT2701_AUD_AUDPLL_D16] = "top_audpll_d16",
- [MT2701_AUD_AUDPLL_D24] = "top_audpll_d24",
- [MT2701_AUD_AUDINTBUS] = "top_audintbus_sel",
- [MT2701_AUD_CLK_26M] = "clk_26m",
- [MT2701_AUD_SYSPLL1_D4] = "top_syspll1_d4",
- [MT2701_AUD_AUD_K1_SRC_SEL] = "top_aud_k1_src_sel",
- [MT2701_AUD_AUD_K2_SRC_SEL] = "top_aud_k2_src_sel",
- [MT2701_AUD_AUD_K3_SRC_SEL] = "top_aud_k3_src_sel",
- [MT2701_AUD_AUD_K4_SRC_SEL] = "top_aud_k4_src_sel",
- [MT2701_AUD_AUD_K5_SRC_SEL] = "top_aud_k5_src_sel",
- [MT2701_AUD_AUD_K6_SRC_SEL] = "top_aud_k6_src_sel",
- [MT2701_AUD_AUD_K1_SRC_DIV] = "top_aud_k1_src_div",
- [MT2701_AUD_AUD_K2_SRC_DIV] = "top_aud_k2_src_div",
- [MT2701_AUD_AUD_K3_SRC_DIV] = "top_aud_k3_src_div",
- [MT2701_AUD_AUD_K4_SRC_DIV] = "top_aud_k4_src_div",
- [MT2701_AUD_AUD_K5_SRC_DIV] = "top_aud_k5_src_div",
- [MT2701_AUD_AUD_K6_SRC_DIV] = "top_aud_k6_src_div",
- [MT2701_AUD_AUD_I2S1_MCLK] = "top_aud_i2s1_mclk",
- [MT2701_AUD_AUD_I2S2_MCLK] = "top_aud_i2s2_mclk",
- [MT2701_AUD_AUD_I2S3_MCLK] = "top_aud_i2s3_mclk",
- [MT2701_AUD_AUD_I2S4_MCLK] = "top_aud_i2s4_mclk",
- [MT2701_AUD_AUD_I2S5_MCLK] = "top_aud_i2s5_mclk",
- [MT2701_AUD_AUD_I2S6_MCLK] = "top_aud_i2s6_mclk",
- [MT2701_AUD_ASM_M_SEL] = "top_asm_m_sel",
- [MT2701_AUD_ASM_H_SEL] = "top_asm_h_sel",
- [MT2701_AUD_UNIVPLL2_D4] = "top_univpll2_d4",
- [MT2701_AUD_UNIVPLL2_D2] = "top_univpll2_d2",
- [MT2701_AUD_SYSPLL_D5] = "top_syspll_d5",
+static const char *const base_clks[] = {
+ [MT2701_INFRA_SYS_AUDIO] = "infra_sys_audio_clk",
+ [MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel",
+ [MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel",
+ [MT2701_TOP_AUD_A1SYS] = "top_audio_a1sys_hp",
+ [MT2701_TOP_AUD_A2SYS] = "top_audio_a2sys_hp",
+ [MT2701_AUDSYS_AFE] = "audio_afe_pd",
+ [MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd",
+ [MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd",
+ [MT2701_AUDSYS_A2SYS] = "audio_a2sys_pd",
};
int mt2701_init_clock(struct mtk_base_afe *afe)
{
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- int i = 0;
-
- for (i = 0; i < MT2701_CLOCK_NUM; i++) {
- afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
- if (IS_ERR(afe_priv->clocks[i])) {
- dev_warn(afe->dev, "%s devm_clk_get %s fail\n",
- __func__, aud_clks[i]);
- return PTR_ERR(aud_clks[i]);
+ int i;
+
+ for (i = 0; i < MT2701_BASE_CLK_NUM; i++) {
+ afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]);
+ if (IS_ERR(afe_priv->base_ck[i])) {
+ dev_err(afe->dev, "failed to get %s\n", base_clks[i]);
+ return PTR_ERR(afe_priv->base_ck[i]);
+ }
+ }
+
+ /* Get I2S related clocks */
+ for (i = 0; i < MT2701_I2S_NUM; i++) {
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i];
+ char name[13];
+
+ snprintf(name, sizeof(name), "i2s%d_src_sel", i);
+ i2s_path->sel_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->sel_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->sel_ck);
+ }
+
+ snprintf(name, sizeof(name), "i2s%d_src_div", i);
+ i2s_path->div_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->div_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->div_ck);
+ }
+
+ snprintf(name, sizeof(name), "i2s%d_mclk_en", i);
+ i2s_path->mclk_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->mclk_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->mclk_ck);
+ }
+
+ snprintf(name, sizeof(name), "i2so%d_hop_ck", i);
+ i2s_path->hop_ck[I2S_OUT] = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->hop_ck[I2S_OUT])) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->hop_ck[I2S_OUT]);
+ }
+
+ snprintf(name, sizeof(name), "i2si%d_hop_ck", i);
+ i2s_path->hop_ck[I2S_IN] = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->hop_ck[I2S_IN])) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->hop_ck[I2S_IN]);
+ }
+
+ snprintf(name, sizeof(name), "asrc%d_out_ck", i);
+ i2s_path->asrco_ck = devm_clk_get(afe->dev, name);
+ if (IS_ERR(i2s_path->asrco_ck)) {
+ dev_err(afe->dev, "failed to get %s\n", name);
+ return PTR_ERR(i2s_path->asrco_ck);
}
}
+ /* Some platforms may support BT path */
+ afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd");
+ if (IS_ERR(afe_priv->mrgif_ck)) {
+ if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ afe_priv->mrgif_ck = NULL;
+ }
+
return 0;
}
-int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
+int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir)
{
- int ret = 0;
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
+ int ret;
- ret = mt2701_turn_on_a1sys_clock(afe);
+ ret = clk_prepare_enable(i2s_path->asrco_ck);
if (ret) {
- dev_err(afe->dev, "%s turn_on_a1sys_clock fail %d\n",
- __func__, ret);
+ dev_err(afe->dev, "failed to enable ASRC clock %d\n", ret);
return ret;
}
- ret = mt2701_turn_on_a2sys_clock(afe);
+ ret = clk_prepare_enable(i2s_path->hop_ck[dir]);
if (ret) {
- dev_err(afe->dev, "%s turn_on_a2sys_clock fail %d\n",
- __func__, ret);
- mt2701_turn_off_a1sys_clock(afe);
- return ret;
+ dev_err(afe->dev, "failed to enable I2S clock %d\n", ret);
+ goto err_hop_ck;
}
- ret = mt2701_turn_on_afe_clock(afe);
- if (ret) {
- dev_err(afe->dev, "%s turn_on_afe_clock fail %d\n",
- __func__, ret);
- mt2701_turn_off_a1sys_clock(afe);
- mt2701_turn_off_a2sys_clock(afe);
- return ret;
- }
+ return 0;
- regmap_update_bits(afe->regmap, ASYS_TOP_CON,
- AUDIO_TOP_CON0_A1SYS_A2SYS_ON,
- AUDIO_TOP_CON0_A1SYS_A2SYS_ON);
- regmap_update_bits(afe->regmap, AFE_DAC_CON0,
- AFE_DAC_CON0_AFE_ON,
- AFE_DAC_CON0_AFE_ON);
- regmap_write(afe->regmap, PWR2_TOP_CON,
- PWR2_TOP_CON_INIT_VAL);
- regmap_write(afe->regmap, PWR1_ASM_CON1,
- PWR1_ASM_CON1_INIT_VAL);
- regmap_write(afe->regmap, PWR2_ASM_CON1,
- PWR2_ASM_CON1_INIT_VAL);
+err_hop_ck:
+ clk_disable_unprepare(i2s_path->asrco_ck);
- return 0;
+ return ret;
}
-void mt2701_afe_disable_clock(struct mtk_base_afe *afe)
+void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir)
{
- mt2701_turn_off_afe_clock(afe);
- mt2701_turn_off_a1sys_clock(afe);
- mt2701_turn_off_a2sys_clock(afe);
- regmap_update_bits(afe->regmap, ASYS_TOP_CON,
- AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0);
- regmap_update_bits(afe->regmap, AFE_DAC_CON0,
- AFE_DAC_CON0_AFE_ON, 0);
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
+
+ clk_disable_unprepare(i2s_path->hop_ck[dir]);
+ clk_disable_unprepare(i2s_path->asrco_ck);
}
-int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe)
+int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id)
{
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- int ret = 0;
-
- /* Set Mux */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret);
- goto A1SYS_CLK_AUD_MUX1_SEL_ERR;
- }
-
- ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL],
- afe_priv->clocks[MT2701_AUD_AUD1PLL_98M]);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
- aud_clks[MT2701_AUD_AUD_MUX1_SEL],
- aud_clks[MT2701_AUD_AUD1PLL_98M], ret);
- goto A1SYS_CLK_AUD_MUX1_SEL_ERR;
- }
-
- /* Set Divider */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__,
- aud_clks[MT2701_AUD_AUD_MUX1_DIV],
- ret);
- goto A1SYS_CLK_AUD_MUX1_DIV_ERR;
- }
-
- ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV],
- MT2701_AUD_AUD_MUX1_DIV_RATE);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__,
- aud_clks[MT2701_AUD_AUD_MUX1_DIV],
- MT2701_AUD_AUD_MUX1_DIV_RATE, ret);
- goto A1SYS_CLK_AUD_MUX1_DIV_ERR;
- }
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
- /* Enable clock gate */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_AUD_48K_TIMING], ret);
- goto A1SYS_CLK_AUD_48K_ERR;
- }
+ return clk_prepare_enable(i2s_path->mclk_ck);
+}
- /* Enable infra audio */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
- goto A1SYS_CLK_INFRA_ERR;
- }
+void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
- return 0;
+ clk_disable_unprepare(i2s_path->mclk_ck);
+}
-A1SYS_CLK_INFRA_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
-A1SYS_CLK_AUD_48K_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
-A1SYS_CLK_AUD_MUX1_DIV_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
-A1SYS_CLK_AUD_MUX1_SEL_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
+int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe)
+{
+ struct mt2701_afe_private *afe_priv = afe->platform_priv;
- return ret;
+ return clk_prepare_enable(afe_priv->mrgif_ck);
}
-void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe)
+void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe)
{
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
+ clk_disable_unprepare(afe_priv->mrgif_ck);
}
-int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe)
+static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe)
{
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- int ret = 0;
+ int ret;
- /* Set Mux */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret);
- goto A2SYS_CLK_AUD_MUX2_SEL_ERR;
- }
+ /* Enable infra clock gate */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
+ if (ret)
+ return ret;
- ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL],
- afe_priv->clocks[MT2701_AUD_AUD2PLL_90M]);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
- aud_clks[MT2701_AUD_AUD_MUX2_SEL],
- aud_clks[MT2701_AUD_AUD2PLL_90M], ret);
- goto A2SYS_CLK_AUD_MUX2_SEL_ERR;
- }
+ /* Enable top a1sys clock gate */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
+ if (ret)
+ goto err_a1sys;
- /* Set Divider */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_AUD_MUX2_DIV], ret);
- goto A2SYS_CLK_AUD_MUX2_DIV_ERR;
- }
+ /* Enable top a2sys clock gate */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
+ if (ret)
+ goto err_a2sys;
- ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV],
- MT2701_AUD_AUD_MUX2_DIV_RATE);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__,
- aud_clks[MT2701_AUD_AUD_MUX2_DIV],
- MT2701_AUD_AUD_MUX2_DIV_RATE, ret);
- goto A2SYS_CLK_AUD_MUX2_DIV_ERR;
- }
+ /* Internal clock gates */
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
+ if (ret)
+ goto err_afe;
- /* Enable clock gate */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_AUD_44K_TIMING], ret);
- goto A2SYS_CLK_AUD_44K_ERR;
- }
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
+ if (ret)
+ goto err_audio_a1sys;
- /* Enable infra audio */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
- goto A2SYS_CLK_INFRA_ERR;
- }
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
+ if (ret)
+ goto err_audio_a2sys;
+
+ ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
+ if (ret)
+ goto err_afe_conn;
return 0;
-A2SYS_CLK_INFRA_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
-A2SYS_CLK_AUD_44K_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
-A2SYS_CLK_AUD_MUX2_DIV_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
-A2SYS_CLK_AUD_MUX2_SEL_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
+err_afe_conn:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
+err_audio_a2sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
+err_audio_a1sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
+err_afe:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
+err_a2sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
+err_a1sys:
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
return ret;
}
-void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe)
+static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe)
{
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
+ clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
}
-int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe)
+int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
{
- struct mt2701_afe_private *afe_priv = afe->platform_priv;
int ret;
- /* enable INFRA_SYS */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
- goto AFE_AUD_INFRA_ERR;
- }
-
- /* Set MT2701_AUD_AUDINTBUS to MT2701_AUD_SYSPLL1_D4 */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_AUDINTBUS], ret);
- goto AFE_AUD_AUDINTBUS_ERR;
- }
-
- ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUDINTBUS],
- afe_priv->clocks[MT2701_AUD_SYSPLL1_D4]);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
- aud_clks[MT2701_AUD_AUDINTBUS],
- aud_clks[MT2701_AUD_SYSPLL1_D4], ret);
- goto AFE_AUD_AUDINTBUS_ERR;
- }
-
- /* Set MT2701_AUD_ASM_H_SEL to MT2701_AUD_UNIVPLL2_D2 */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
+ /* Enable audio system */
+ ret = mt2701_afe_enable_audsys(afe);
if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_ASM_H_SEL], ret);
- goto AFE_AUD_ASM_H_ERR;
- }
-
- ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_H_SEL],
- afe_priv->clocks[MT2701_AUD_UNIVPLL2_D2]);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
- aud_clks[MT2701_AUD_ASM_H_SEL],
- aud_clks[MT2701_AUD_UNIVPLL2_D2], ret);
- goto AFE_AUD_ASM_H_ERR;
- }
-
- /* Set MT2701_AUD_ASM_M_SEL to MT2701_AUD_UNIVPLL2_D4 */
- ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
- if (ret) {
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[MT2701_AUD_ASM_M_SEL], ret);
- goto AFE_AUD_ASM_M_ERR;
+ dev_err(afe->dev, "failed to enable audio system %d\n", ret);
+ return ret;
}
- ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_M_SEL],
- afe_priv->clocks[MT2701_AUD_UNIVPLL2_D4]);
- if (ret) {
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
- aud_clks[MT2701_AUD_ASM_M_SEL],
- aud_clks[MT2701_AUD_UNIVPLL2_D4], ret);
- goto AFE_AUD_ASM_M_ERR;
- }
+ regmap_update_bits(afe->regmap, ASYS_TOP_CON,
+ ASYS_TOP_CON_ASYS_TIMING_ON,
+ ASYS_TOP_CON_ASYS_TIMING_ON);
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+ AFE_DAC_CON0_AFE_ON,
+ AFE_DAC_CON0_AFE_ON);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
- AUDIO_TOP_CON0_PDN_AFE, 0);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
- AUDIO_TOP_CON0_PDN_APLL_CK, 0);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_A1SYS, 0);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_A2SYS, 0);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_AFE_CONN, 0);
+ /* Configure ASRC */
+ regmap_write(afe->regmap, PWR1_ASM_CON1, PWR1_ASM_CON1_INIT_VAL);
+ regmap_write(afe->regmap, PWR2_ASM_CON1, PWR2_ASM_CON1_INIT_VAL);
return 0;
-
-AFE_AUD_ASM_M_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
-AFE_AUD_ASM_H_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
-AFE_AUD_AUDINTBUS_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
-AFE_AUD_INFRA_ERR:
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
-
- return ret;
}
-void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe)
+int mt2701_afe_disable_clock(struct mtk_base_afe *afe)
{
- struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ regmap_update_bits(afe->regmap, ASYS_TOP_CON,
+ ASYS_TOP_CON_ASYS_TIMING_ON, 0);
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+ AFE_DAC_CON0_AFE_ON, 0);
+
+ mt2701_afe_disable_audsys(afe);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
-
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
- clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
-
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
- AUDIO_TOP_CON0_PDN_AFE, AUDIO_TOP_CON0_PDN_AFE);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
- AUDIO_TOP_CON0_PDN_APLL_CK,
- AUDIO_TOP_CON0_PDN_APLL_CK);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_A1SYS,
- AUDIO_TOP_CON4_PDN_A1SYS);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_A2SYS,
- AUDIO_TOP_CON4_PDN_A2SYS);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_AFE_CONN,
- AUDIO_TOP_CON4_PDN_AFE_CONN);
+ return 0;
}
void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
int mclk)
{
- struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ struct mt2701_afe_private *priv = afe->platform_priv;
+ struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id];
int ret;
- int aud_src_div_id = MT2701_AUD_AUD_K1_SRC_DIV + id;
- int aud_src_clk_id = MT2701_AUD_AUD_K1_SRC_SEL + id;
- /* Set MCLK Kx_SRC_SEL(domain) */
- ret = clk_prepare_enable(afe_priv->clocks[aud_src_clk_id]);
- if (ret)
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[aud_src_clk_id], ret);
-
- if (domain == 0) {
- ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id],
- afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
- if (ret)
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
- __func__, aud_clks[aud_src_clk_id],
- aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret);
- } else {
- ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id],
- afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
- if (ret)
- dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
- __func__, aud_clks[aud_src_clk_id],
- aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret);
- }
- clk_disable_unprepare(afe_priv->clocks[aud_src_clk_id]);
+ /* Set mclk source */
+ if (domain == 0)
+ ret = clk_set_parent(i2s_path->sel_ck,
+ priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]);
+ else
+ ret = clk_set_parent(i2s_path->sel_ck,
+ priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]);
- /* Set MCLK Kx_SRC_DIV(divider) */
- ret = clk_prepare_enable(afe_priv->clocks[aud_src_div_id]);
if (ret)
- dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[aud_src_div_id], ret);
+ dev_err(afe->dev, "failed to set domain%d mclk source %d\n",
+ domain, ret);
- ret = clk_set_rate(afe_priv->clocks[aud_src_div_id], mclk);
+ /* Set mclk divider */
+ ret = clk_set_rate(i2s_path->div_ck, mclk);
if (ret)
- dev_err(afe->dev, "%s clk_set_rate %s-%d fail %d\n", __func__,
- aud_clks[aud_src_div_id], mclk, ret);
- clk_disable_unprepare(afe_priv->clocks[aud_src_div_id]);
+ dev_err(afe->dev, "failed to set mclk divider %d\n", ret);
}
-
-MODULE_DESCRIPTION("MT2701 afe clock control");
-MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
index 6497d57..15417d9 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
@@ -21,16 +21,15 @@ struct mtk_base_afe;
int mt2701_init_clock(struct mtk_base_afe *afe);
int mt2701_afe_enable_clock(struct mtk_base_afe *afe);
-void mt2701_afe_disable_clock(struct mtk_base_afe *afe);
+int mt2701_afe_disable_clock(struct mtk_base_afe *afe);
-int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe);
-void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe);
+int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir);
+void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir);
+int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id);
+void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id);
-int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe);
-void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe);
-
-int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe);
-void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe);
+int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe);
+void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe);
void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
int mclk);
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
index c19430e..ae8ddea 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -16,6 +16,7 @@
#ifndef _MT_2701_AFE_COMMON_H_
#define _MT_2701_AFE_COMMON_H_
+
#include <sound/soc.h>
#include <linux/clk.h>
#include <linux/regmap.h>
@@ -25,16 +26,7 @@
#define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1)
#define MT2701_PLL_DOMAIN_0_RATE 98304000
#define MT2701_PLL_DOMAIN_1_RATE 90316800
-#define MT2701_AUD_AUD_MUX1_DIV_RATE (MT2701_PLL_DOMAIN_0_RATE / 2)
-#define MT2701_AUD_AUD_MUX2_DIV_RATE (MT2701_PLL_DOMAIN_1_RATE / 2)
-
-enum {
- MT2701_I2S_1,
- MT2701_I2S_2,
- MT2701_I2S_3,
- MT2701_I2S_4,
- MT2701_I2S_NUM,
-};
+#define MT2701_I2S_NUM 4
enum {
MT2701_MEMIF_DL1,
@@ -62,60 +54,23 @@ enum {
};
enum {
- MT2701_IRQ_ASYS_START,
- MT2701_IRQ_ASYS_IRQ1 = MT2701_IRQ_ASYS_START,
+ MT2701_IRQ_ASYS_IRQ1,
MT2701_IRQ_ASYS_IRQ2,
MT2701_IRQ_ASYS_IRQ3,
MT2701_IRQ_ASYS_END,
};
-/* 2701 clock def */
-enum audio_system_clock_type {
- MT2701_AUD_INFRA_SYS_AUDIO,
- MT2701_AUD_AUD_MUX1_SEL,
- MT2701_AUD_AUD_MUX2_SEL,
- MT2701_AUD_AUD_MUX1_DIV,
- MT2701_AUD_AUD_MUX2_DIV,
- MT2701_AUD_AUD_48K_TIMING,
- MT2701_AUD_AUD_44K_TIMING,
- MT2701_AUD_AUDPLL_MUX_SEL,
- MT2701_AUD_APLL_SEL,
- MT2701_AUD_AUD1PLL_98M,
- MT2701_AUD_AUD2PLL_90M,
- MT2701_AUD_HADDS2PLL_98M,
- MT2701_AUD_HADDS2PLL_294M,
- MT2701_AUD_AUDPLL,
- MT2701_AUD_AUDPLL_D4,
- MT2701_AUD_AUDPLL_D8,
- MT2701_AUD_AUDPLL_D16,
- MT2701_AUD_AUDPLL_D24,
- MT2701_AUD_AUDINTBUS,
- MT2701_AUD_CLK_26M,
- MT2701_AUD_SYSPLL1_D4,
- MT2701_AUD_AUD_K1_SRC_SEL,
- MT2701_AUD_AUD_K2_SRC_SEL,
- MT2701_AUD_AUD_K3_SRC_SEL,
- MT2701_AUD_AUD_K4_SRC_SEL,
- MT2701_AUD_AUD_K5_SRC_SEL,
- MT2701_AUD_AUD_K6_SRC_SEL,
- MT2701_AUD_AUD_K1_SRC_DIV,
- MT2701_AUD_AUD_K2_SRC_DIV,
- MT2701_AUD_AUD_K3_SRC_DIV,
- MT2701_AUD_AUD_K4_SRC_DIV,
- MT2701_AUD_AUD_K5_SRC_DIV,
- MT2701_AUD_AUD_K6_SRC_DIV,
- MT2701_AUD_AUD_I2S1_MCLK,
- MT2701_AUD_AUD_I2S2_MCLK,
- MT2701_AUD_AUD_I2S3_MCLK,
- MT2701_AUD_AUD_I2S4_MCLK,
- MT2701_AUD_AUD_I2S5_MCLK,
- MT2701_AUD_AUD_I2S6_MCLK,
- MT2701_AUD_ASM_M_SEL,
- MT2701_AUD_ASM_H_SEL,
- MT2701_AUD_UNIVPLL2_D4,
- MT2701_AUD_UNIVPLL2_D2,
- MT2701_AUD_SYSPLL_D5,
- MT2701_CLOCK_NUM
+enum audio_base_clock {
+ MT2701_INFRA_SYS_AUDIO,
+ MT2701_TOP_AUD_MCLK_SRC0,
+ MT2701_TOP_AUD_MCLK_SRC1,
+ MT2701_TOP_AUD_A1SYS,
+ MT2701_TOP_AUD_A2SYS,
+ MT2701_AUDSYS_AFE,
+ MT2701_AUDSYS_AFE_CONN,
+ MT2701_AUDSYS_A1SYS,
+ MT2701_AUDSYS_A2SYS,
+ MT2701_BASE_CLK_NUM,
};
static const unsigned int mt2701_afe_backup_list[] = {
@@ -139,12 +94,8 @@ static const unsigned int mt2701_afe_backup_list[] = {
AFE_MEMIF_PBUF_SIZE,
};
-struct snd_pcm_substream;
-struct mtk_base_irq_data;
-
struct mt2701_i2s_data {
int i2s_ctrl_reg;
- int i2s_pwn_shift;
int i2s_asrc_fs_shift;
int i2s_asrc_fs_mask;
};
@@ -160,12 +111,18 @@ struct mt2701_i2s_path {
int mclk_rate;
int on[I2S_DIR_NUM];
int occupied[I2S_DIR_NUM];
- const struct mt2701_i2s_data *i2s_data[2];
+ const struct mt2701_i2s_data *i2s_data[I2S_DIR_NUM];
+ struct clk *hop_ck[I2S_DIR_NUM];
+ struct clk *sel_ck;
+ struct clk *div_ck;
+ struct clk *mclk_ck;
+ struct clk *asrco_ck;
};
struct mt2701_afe_private {
- struct clk *clocks[MT2701_CLOCK_NUM];
struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM];
+ struct clk *base_ck[MT2701_BASE_CLK_NUM];
+ struct clk *mrgif_ck;
bool mrg_enable[MT2701_STREAM_DIR_NUM];
};
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 8fda182..5bc4e00 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -17,19 +17,16 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
-#include <sound/soc.h>
#include "mt2701-afe-common.h"
-
#include "mt2701-afe-clock-ctrl.h"
#include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-afe-fe-dai.h"
-#define AFE_IRQ_STATUS_BITS 0xff
-
static const struct snd_pcm_hardware mt2701_afe_hardware = {
.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID,
@@ -97,40 +94,26 @@ static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
- struct mt2701_afe_private *afe_priv = afe->platform_priv;
int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
- int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num;
- int ret = 0;
if (i2s_num < 0)
return i2s_num;
- /* enable mclk */
- ret = clk_prepare_enable(afe_priv->clocks[clk_num]);
- if (ret)
- dev_err(afe->dev, "Failed to enable mclk for I2S: %d\n",
- i2s_num);
-
- return ret;
+ return mt2701_afe_enable_mclk(afe, i2s_num);
}
static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai,
+ int i2s_num,
int dir_invert)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
- struct mt2701_i2s_path *i2s_path;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num];
const struct mt2701_i2s_data *i2s_data;
int stream_dir = substream->stream;
- if (i2s_num < 0)
- return i2s_num;
-
- i2s_path = &afe_priv->i2s_path[i2s_num];
-
if (dir_invert) {
if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
stream_dir = SNDRV_PCM_STREAM_CAPTURE;
@@ -151,9 +134,9 @@ static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
/* disable i2s */
regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
ASYS_I2S_CON_I2S_EN, 0);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- 1 << i2s_data->i2s_pwn_shift,
- 1 << i2s_data->i2s_pwn_shift);
+
+ mt2701_afe_disable_i2s(afe, i2s_num, stream_dir);
+
return 0;
}
@@ -165,7 +148,6 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
struct mt2701_afe_private *afe_priv = afe->platform_priv;
int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
struct mt2701_i2s_path *i2s_path;
- int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num;
if (i2s_num < 0)
return;
@@ -177,37 +159,32 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
else
goto I2S_UNSTART;
- mt2701_afe_i2s_path_shutdown(substream, dai, 0);
+ mt2701_afe_i2s_path_shutdown(substream, dai, i2s_num, 0);
/* need to disable i2s-out path when disable i2s-in */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- mt2701_afe_i2s_path_shutdown(substream, dai, 1);
+ mt2701_afe_i2s_path_shutdown(substream, dai, i2s_num, 1);
I2S_UNSTART:
/* disable mclk */
- clk_disable_unprepare(afe_priv->clocks[clk_num]);
+ mt2701_afe_disable_mclk(afe, i2s_num);
}
static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai,
+ int i2s_num,
int dir_invert)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
struct mt2701_afe_private *afe_priv = afe->platform_priv;
- int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
- struct mt2701_i2s_path *i2s_path;
+ struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num];
const struct mt2701_i2s_data *i2s_data;
struct snd_pcm_runtime * const runtime = substream->runtime;
int reg, fs, w_len = 1; /* now we support bck 64bits only */
int stream_dir = substream->stream;
unsigned int mask = 0, val = 0;
- if (i2s_num < 0)
- return i2s_num;
-
- i2s_path = &afe_priv->i2s_path[i2s_num];
-
if (dir_invert) {
if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK)
stream_dir = SNDRV_PCM_STREAM_CAPTURE;
@@ -251,9 +228,7 @@ static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
fs << i2s_data->i2s_asrc_fs_shift);
/* enable i2s */
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- 1 << i2s_data->i2s_pwn_shift,
- 0 << i2s_data->i2s_pwn_shift);
+ mt2701_afe_enable_i2s(afe, i2s_num, stream_dir);
/* reset i2s hw status before enable */
regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg,
@@ -300,13 +275,13 @@ static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mt2701_i2s_path_prepare_enable(substream, dai, 0);
+ mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 0);
} else {
/* need to enable i2s-out path when enable i2s-in */
/* prepare for another direction "out" */
- mt2701_i2s_path_prepare_enable(substream, dai, 1);
+ mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 1);
/* prepare for "in" */
- mt2701_i2s_path_prepare_enable(substream, dai, 0);
+ mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 0);
}
return 0;
@@ -339,9 +314,11 @@ static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
struct mt2701_afe_private *afe_priv = afe->platform_priv;
+ int ret;
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_MRGIF, 0);
+ ret = mt2701_enable_btmrg_clk(afe);
+ if (ret)
+ return ret;
afe_priv->mrg_enable[substream->stream] = 1;
return 0;
@@ -406,9 +383,7 @@ static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
AFE_MRGIF_CON_MRG_EN, 0);
regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
AFE_MRGIF_CON_MRG_I2S_EN, 0);
- regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
- AUDIO_TOP_CON4_PDN_MRGIF,
- AUDIO_TOP_CON4_PDN_MRGIF);
+ mt2701_disable_btmrg_clk(afe);
}
afe_priv->mrg_enable[substream->stream] = 0;
}
@@ -574,7 +549,6 @@ static const struct snd_soc_dai_ops mt2701_single_memif_dai_ops = {
.hw_free = mtk_afe_fe_hw_free,
.prepare = mtk_afe_fe_prepare,
.trigger = mtk_afe_fe_trigger,
-
};
static const struct snd_soc_dai_ops mt2701_dlm_memif_dai_ops = {
@@ -915,31 +889,6 @@ static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = {
PWR2_TOP_CON, 19, 1, 0),
};
-static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc0[] = {
- SOC_DAPM_SINGLE_AUTODISABLE("Asrc0 out Switch", AUDIO_TOP_CON4, 14, 1,
- 1),
-};
-
-static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc1[] = {
- SOC_DAPM_SINGLE_AUTODISABLE("Asrc1 out Switch", AUDIO_TOP_CON4, 15, 1,
- 1),
-};
-
-static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc2[] = {
- SOC_DAPM_SINGLE_AUTODISABLE("Asrc2 out Switch", PWR2_TOP_CON, 6, 1,
- 1),
-};
-
-static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc3[] = {
- SOC_DAPM_SINGLE_AUTODISABLE("Asrc3 out Switch", PWR2_TOP_CON, 7, 1,
- 1),
-};
-
-static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc4[] = {
- SOC_DAPM_SINGLE_AUTODISABLE("Asrc4 out Switch", PWR2_TOP_CON, 8, 1,
- 1),
-};
-
static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = {
/* inter-connections */
SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -999,19 +948,6 @@ static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = {
SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0,
mt2701_afe_multi_ch_out_i2s3,
ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)),
-
- SND_SOC_DAPM_MIXER("ASRC_O0", SND_SOC_NOPM, 0, 0,
- mt2701_afe_multi_ch_out_asrc0,
- ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc0)),
- SND_SOC_DAPM_MIXER("ASRC_O1", SND_SOC_NOPM, 0, 0,
- mt2701_afe_multi_ch_out_asrc1,
- ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc1)),
- SND_SOC_DAPM_MIXER("ASRC_O2", SND_SOC_NOPM, 0, 0,
- mt2701_afe_multi_ch_out_asrc2,
- ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc2)),
- SND_SOC_DAPM_MIXER("ASRC_O3", SND_SOC_NOPM, 0, 0,
- mt2701_afe_multi_ch_out_asrc3,
- ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc3)),
};
static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
@@ -1021,7 +957,6 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
{"I2S0 Playback", NULL, "O15"},
{"I2S0 Playback", NULL, "O16"},
-
{"I2S1 Playback", NULL, "O17"},
{"I2S1 Playback", NULL, "O18"},
{"I2S2 Playback", NULL, "O19"},
@@ -1038,7 +973,6 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
{"I00", NULL, "I2S0 Capture"},
{"I01", NULL, "I2S0 Capture"},
-
{"I02", NULL, "I2S1 Capture"},
{"I03", NULL, "I2S1 Capture"},
/* I02,03 link to UL2, also need to open I2S0 */
@@ -1046,15 +980,10 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
{"I26", NULL, "BT Capture"},
- {"ASRC_O0", "Asrc0 out Switch", "DLM"},
- {"ASRC_O1", "Asrc1 out Switch", "DLM"},
- {"ASRC_O2", "Asrc2 out Switch", "DLM"},
- {"ASRC_O3", "Asrc3 out Switch", "DLM"},
-
- {"I12I13", "Multich I2S0 Out Switch", "ASRC_O0"},
- {"I14I15", "Multich I2S1 Out Switch", "ASRC_O1"},
- {"I16I17", "Multich I2S2 Out Switch", "ASRC_O2"},
- {"I18I19", "Multich I2S3 Out Switch", "ASRC_O3"},
+ {"I12I13", "Multich I2S0 Out Switch", "DLM"},
+ {"I14I15", "Multich I2S1 Out Switch", "DLM"},
+ {"I16I17", "Multich I2S2 Out Switch", "DLM"},
+ {"I18I19", "Multich I2S3 Out Switch", "DLM"},
{ "I12", NULL, "I12I13" },
{ "I13", NULL, "I12I13" },
@@ -1079,7 +1008,6 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
{ "O21", "I18 Switch", "I18" },
{ "O22", "I19 Switch", "I19" },
{ "O31", "I35 Switch", "I35" },
-
};
static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = {
@@ -1386,14 +1314,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
{
{
.i2s_ctrl_reg = ASYS_I2SO1_CON,
- .i2s_pwn_shift = 6,
.i2s_asrc_fs_shift = 0,
.i2s_asrc_fs_mask = 0x1f,
},
{
.i2s_ctrl_reg = ASYS_I2SIN1_CON,
- .i2s_pwn_shift = 0,
.i2s_asrc_fs_shift = 0,
.i2s_asrc_fs_mask = 0x1f,
@@ -1402,14 +1328,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
{
{
.i2s_ctrl_reg = ASYS_I2SO2_CON,
- .i2s_pwn_shift = 7,
.i2s_asrc_fs_shift = 5,
.i2s_asrc_fs_mask = 0x1f,
},
{
.i2s_ctrl_reg = ASYS_I2SIN2_CON,
- .i2s_pwn_shift = 1,
.i2s_asrc_fs_shift = 5,
.i2s_asrc_fs_mask = 0x1f,
@@ -1418,14 +1342,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
{
{
.i2s_ctrl_reg = ASYS_I2SO3_CON,
- .i2s_pwn_shift = 8,
.i2s_asrc_fs_shift = 10,
.i2s_asrc_fs_mask = 0x1f,
},
{
.i2s_ctrl_reg = ASYS_I2SIN3_CON,
- .i2s_pwn_shift = 2,
.i2s_asrc_fs_shift = 10,
.i2s_asrc_fs_mask = 0x1f,
@@ -1434,14 +1356,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
{
{
.i2s_ctrl_reg = ASYS_I2SO4_CON,
- .i2s_pwn_shift = 9,
.i2s_asrc_fs_shift = 15,
.i2s_asrc_fs_mask = 0x1f,
},
{
.i2s_ctrl_reg = ASYS_I2SIN4_CON,
- .i2s_pwn_shift = 3,
.i2s_asrc_fs_shift = 15,
.i2s_asrc_fs_mask = 0x1f,
@@ -1449,14 +1369,6 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = {
},
};
-static const struct regmap_config mt2701_afe_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = AFE_END_ADDR,
- .cache_type = REGCACHE_NONE,
-};
-
static irqreturn_t mt2701_asys_isr(int irq_id, void *dev)
{
int id;
@@ -1483,8 +1395,7 @@ static int mt2701_afe_runtime_suspend(struct device *dev)
{
struct mtk_base_afe *afe = dev_get_drvdata(dev);
- mt2701_afe_disable_clock(afe);
- return 0;
+ return mt2701_afe_disable_clock(afe);
}
static int mt2701_afe_runtime_resume(struct device *dev)
@@ -1496,21 +1407,22 @@ static int mt2701_afe_runtime_resume(struct device *dev)
static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
{
+ struct snd_soc_component *component;
struct mtk_base_afe *afe;
struct mt2701_afe_private *afe_priv;
- struct resource *res;
struct device *dev;
int i, irq_id, ret;
afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
if (!afe)
return -ENOMEM;
+
afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
GFP_KERNEL);
if (!afe->platform_priv)
return -ENOMEM;
- afe_priv = afe->platform_priv;
+ afe_priv = afe->platform_priv;
afe->dev = &pdev->dev;
dev = afe->dev;
@@ -1527,17 +1439,11 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
return ret;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
-
- if (IS_ERR(afe->base_addr))
- return PTR_ERR(afe->base_addr);
-
- afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
- &mt2701_afe_regmap_config);
- if (IS_ERR(afe->regmap))
+ afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(afe->regmap)) {
+ dev_err(dev, "could not get regmap from parent\n");
return PTR_ERR(afe->regmap);
+ }
mutex_init(&afe->irq_alloc_lock);
@@ -1545,7 +1451,6 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
afe->memif_size = MT2701_MEMIF_NUM;
afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
GFP_KERNEL);
-
if (!afe->memif)
return -ENOMEM;
@@ -1558,7 +1463,6 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
afe->irqs_size = MT2701_IRQ_ASYS_END;
afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
GFP_KERNEL);
-
if (!afe->irqs)
return -ENOMEM;
@@ -1573,10 +1477,15 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
= &mt2701_i2s_data[i][I2S_IN];
}
+ component = kzalloc(sizeof(*component), GFP_KERNEL);
+ if (!component)
+ return -ENOMEM;
+
+ component->regmap = afe->regmap;
+
afe->mtk_afe_hardware = &mt2701_afe_hardware;
afe->memif_fs = mt2701_memif_fs;
afe->irq_fs = mt2701_irq_fs;
-
afe->reg_back_up_list = mt2701_afe_backup_list;
afe->reg_back_up_list_num = ARRAY_SIZE(mt2701_afe_backup_list);
afe->runtime_resume = mt2701_afe_runtime_resume;
@@ -1586,59 +1495,58 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
ret = mt2701_init_clock(afe);
if (ret) {
dev_err(dev, "init clock error\n");
- return ret;
+ goto err_init_clock;
}
platform_set_drvdata(pdev, afe);
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev))
- goto err_pm_disable;
- pm_runtime_get_sync(&pdev->dev);
- ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform);
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = mt2701_afe_runtime_resume(dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+ pm_runtime_get_sync(dev);
+
+ ret = snd_soc_register_platform(dev, &mtk_afe_pcm_platform);
if (ret) {
dev_warn(dev, "err_platform\n");
goto err_platform;
}
- ret = snd_soc_register_component(&pdev->dev,
- &mt2701_afe_pcm_dai_component,
- mt2701_afe_pcm_dais,
- ARRAY_SIZE(mt2701_afe_pcm_dais));
+ ret = snd_soc_add_component(dev, component,
+ &mt2701_afe_pcm_dai_component,
+ mt2701_afe_pcm_dais,
+ ARRAY_SIZE(mt2701_afe_pcm_dais));
if (ret) {
dev_warn(dev, "err_dai_component\n");
goto err_dai_component;
}
- mt2701_afe_runtime_resume(&pdev->dev);
-
return 0;
err_dai_component:
- snd_soc_unregister_component(&pdev->dev);
-
+ snd_soc_unregister_platform(dev);
err_platform:
- snd_soc_unregister_platform(&pdev->dev);
-
+ pm_runtime_put_sync(dev);
err_pm_disable:
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(dev);
+err_init_clock:
+ kfree(component);
return ret;
}
static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev)
{
- struct mtk_base_afe *afe = platform_get_drvdata(pdev);
-
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
mt2701_afe_runtime_suspend(&pdev->dev);
- pm_runtime_put_sync(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
snd_soc_unregister_platform(&pdev->dev);
- /* disable afe clock */
- mt2701_afe_disable_clock(afe);
+
return 0;
}
@@ -1670,4 +1578,3 @@ module_platform_driver(mt2701_afe_pcm_driver);
MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701");
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
MODULE_LICENSE("GPL v2");
-
diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h
index bb62b1c..18e6769 100644
--- a/sound/soc/mediatek/mt2701/mt2701-reg.h
+++ b/sound/soc/mediatek/mt2701/mt2701-reg.h
@@ -17,17 +17,6 @@
#ifndef _MT2701_REG_H_
#define _MT2701_REG_H_
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/pm_runtime.h>
-#include <sound/soc.h>
-#include "mt2701-afe-common.h"
-
-/*****************************************************************************
- * R E G I S T E R D E F I N I T I O N
- *****************************************************************************/
#define AUDIO_TOP_CON0 0x0000
#define AUDIO_TOP_CON4 0x0010
#define AUDIO_TOP_CON5 0x0014
@@ -109,18 +98,6 @@
#define AFE_DAI_BASE 0x1370
#define AFE_DAI_CUR 0x137c
-/* AUDIO_TOP_CON0 (0x0000) */
-#define AUDIO_TOP_CON0_A1SYS_A2SYS_ON (0x3 << 0)
-#define AUDIO_TOP_CON0_PDN_AFE (0x1 << 2)
-#define AUDIO_TOP_CON0_PDN_APLL_CK (0x1 << 23)
-
-/* AUDIO_TOP_CON4 (0x0010) */
-#define AUDIO_TOP_CON4_I2SO1_PWN (0x1 << 6)
-#define AUDIO_TOP_CON4_PDN_A1SYS (0x1 << 21)
-#define AUDIO_TOP_CON4_PDN_A2SYS (0x1 << 22)
-#define AUDIO_TOP_CON4_PDN_AFE_CONN (0x1 << 23)
-#define AUDIO_TOP_CON4_PDN_MRGIF (0x1 << 25)
-
/* AFE_DAIBT_CON0 (0x001c) */
#define AFE_DAIBT_CON0_DAIBT_EN (0x1 << 0)
#define AFE_DAIBT_CON0_BT_FUNC_EN (0x1 << 1)
@@ -137,22 +114,8 @@
#define AFE_MRGIF_CON_I2S_MODE_MASK (0xf << 20)
#define AFE_MRGIF_CON_I2S_MODE_32K (0x4 << 20)
-/* ASYS_I2SO1_CON (0x061c) */
-#define ASYS_I2SO1_CON_FS (0x1f << 8)
-#define ASYS_I2SO1_CON_FS_SET(x) ((x) << 8)
-#define ASYS_I2SO1_CON_MULTI_CH (0x1 << 16)
-#define ASYS_I2SO1_CON_SIDEGEN (0x1 << 30)
-#define ASYS_I2SO1_CON_I2S_EN (0x1 << 0)
-/* 0:EIAJ 1:I2S */
-#define ASYS_I2SO1_CON_I2S_MODE (0x1 << 3)
-#define ASYS_I2SO1_CON_WIDE_MODE (0x1 << 1)
-#define ASYS_I2SO1_CON_WIDE_MODE_SET(x) ((x) << 1)
-
-/* PWR2_TOP_CON (0x0634) */
-#define PWR2_TOP_CON_INIT_VAL (0xffe1ffff)
-
-/* ASYS_IRQ_CLR (0x07c0) */
-#define ASYS_IRQ_CLR_ALL (0xffffffff)
+/* ASYS_TOP_CON (0x0600) */
+#define ASYS_TOP_CON_ASYS_TIMING_ON (0x3 << 0)
/* PWR2_ASM_CON1 (0x1070) */
#define PWR2_ASM_CON1_INIT_VAL (0x492492)
@@ -182,5 +145,4 @@
#define ASYS_I2S_CON_WIDE_MODE_SET(x) ((x) << 1)
#define ASYS_I2S_IN_PHASE_FIX (0x1 << 31)
-#define AFE_END_ADDR 0x15e0
#endif
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 8a643a3..c7f7f8a 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1083,7 +1083,7 @@ static int mt8173_afe_init_audio_clk(struct mtk_base_afe *afe)
static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
{
int ret, i;
- unsigned int irq_id;
+ int irq_id;
struct mtk_base_afe *afe;
struct mt8173_afe_private *afe_priv;
struct resource *res;
@@ -1105,9 +1105,9 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
afe->dev = &pdev->dev;
irq_id = platform_get_irq(pdev, 0);
- if (!irq_id) {
+ if (irq_id <= 0) {
dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
- return -ENXIO;
+ return irq_id < 0 ? irq_id : -ENXIO;
}
ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
0, "Afe_ISR_Handle", (void *)afe);
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 99c1521..5a9a548 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -37,8 +37,6 @@ static const struct snd_soc_dapm_route mt8173_rt5650_rt5514_routes[] = {
{"Sub DMIC1R", NULL, "Int Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
- {"Headset Mic", NULL, "micbias1"},
- {"Headset Mic", NULL, "micbias2"},
{"IN1P", NULL, "Headset Mic"},
{"IN1N", NULL, "Headset Mic"},
};
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index 42de84c..b724808 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -40,8 +40,6 @@ static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
{"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */
- {"Headset Mic", NULL, "micbias1"},
- {"Headset Mic", NULL, "micbias2"},
{"IN1P", NULL, "Headset Mic"},
{"IN1N", NULL, "Headset Mic"},
{"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650 */
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index e69c141..40ebefd 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -51,8 +51,6 @@ static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = {
{"DMIC R1", NULL, "Int Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
- {"Headset Mic", NULL, "micbias1"},
- {"Headset Mic", NULL, "micbias2"},
{"IN1P", NULL, "Headset Mic"},
{"IN1N", NULL, "Headset Mic"},
};
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 2ed3240..2b3f240 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -93,6 +93,14 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
},
};
+static const struct snd_soc_dapm_widget mxs_sgtl5000_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_LINE("Line In Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Line Out Jack", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
static struct snd_soc_card mxs_sgtl5000 = {
.name = "mxs_sgtl5000",
.owner = THIS_MODULE,
@@ -141,10 +149,23 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
+ if (of_find_property(np, "audio-routing", NULL)) {
+ card->dapm_widgets = mxs_sgtl5000_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(mxs_sgtl5000_dapm_widgets);
+
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
- ret);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
return ret;
}
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index b6615af..81b09d7 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -67,7 +67,7 @@ static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,
/* polling the AC_R_FINISH */
while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH)
- && timeout--)
+ && --timeout)
mdelay(1);
if (!timeout) {
@@ -121,7 +121,7 @@ static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
/* polling the AC_W_FINISH */
while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH)
- && timeout--)
+ && --timeout)
mdelay(1);
if (!timeout)
@@ -345,11 +345,10 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
goto out;
}
- nuc900_audio->irq_num = platform_get_irq(pdev, 0);
- if (!nuc900_audio->irq_num) {
- ret = -EBUSY;
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
goto out;
- }
+ nuc900_audio->irq_num = ret;
nuc900_ac97_data = nuc900_audio;
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index d402196..cb72c1e 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -105,7 +105,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
int pin, changed = 0;
/* Refuse any mode changes if we are not able to control the codec. */
- if (!cx20442_codec->hw_write)
+ if (!cx20442_codec->component.card->pop_time)
return -EUNATCH;
if (ucontrol->value.enumerated.item[0] >= control->items)
@@ -345,7 +345,7 @@ static void cx81801_receive(struct tty_struct *tty,
if (!codec)
return;
- if (!codec->hw_write) {
+ if (!codec->component.card->pop_time) {
/* First modem response, complete setup procedure */
/* Initialize timer used for config pulse generation */
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index d49adc8..7044287 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -43,7 +43,7 @@ struct apq8016_sbc_data {
static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_card *card = rtd->card;
struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
@@ -92,7 +92,7 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
jack = pdata->jack.jack;
- snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
@@ -102,15 +102,15 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
for (i = 0 ; i < dai_link->num_codecs; i++) {
struct snd_soc_dai *dai = rtd->codec_dais[i];
- codec = dai->codec;
+ component = dai->component;
/* Set default mclk for internal codec */
- rval = snd_soc_codec_set_sysclk(codec, 0, 0, DEFAULT_MCLK_RATE,
+ rval = snd_soc_component_set_sysclk(component, 0, 0, DEFAULT_MCLK_RATE,
SND_SOC_CLOCK_IN);
if (rval != 0 && rval != -ENOTSUPP) {
dev_warn(card->dev, "Failed to set mclk: %d\n", rval);
return rval;
}
- rval = snd_soc_codec_set_jack(codec, &pdata->jack, NULL);
+ rval = snd_soc_component_set_jack(component, &pdata->jack, NULL);
if (rval != 0 && rval != -ENOTSUPP) {
dev_warn(card->dev, "Failed to set jack: %d\n", rval);
return rval;
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index d64fbbd..fa6cd1d 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -206,7 +206,8 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(
+ rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(
rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 908211e..950823d6 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -328,6 +328,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
val |= I2S_CHN_4;
break;
case 2:
+ case 1:
val |= I2S_CHN_2;
break;
default:
@@ -460,7 +461,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
},
.capture = {
.stream_name = "Capture",
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = (SNDRV_PCM_FMTBIT_S8 |
@@ -504,6 +505,7 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
case I2S_INTCR:
case I2S_XFER:
case I2S_CLR:
+ case I2S_TXDR:
case I2S_RXDR:
case I2S_FIFOLR:
case I2S_INTSR:
@@ -518,6 +520,9 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case I2S_INTSR:
case I2S_CLR:
+ case I2S_FIFOLR:
+ case I2S_TXDR:
+ case I2S_RXDR:
return true;
default:
return false;
@@ -527,6 +532,8 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case I2S_RXDR:
+ return true;
default:
return false;
}
@@ -654,7 +661,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
}
if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
- if (val >= 2 && val <= 8)
+ if (val >= 1 && val <= 8)
soc_dai->capture.channels_max = val;
}
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index ee5055d..a89fe9b 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -322,26 +322,30 @@ static int rk_spdif_probe(struct platform_device *pdev)
spdif->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(spdif->mclk)) {
dev_err(&pdev->dev, "Can't retrieve rk_spdif master clock\n");
- return PTR_ERR(spdif->mclk);
+ ret = PTR_ERR(spdif->mclk);
+ goto err_disable_hclk;
}
ret = clk_prepare_enable(spdif->mclk);
if (ret) {
dev_err(spdif->dev, "clock enable failed %d\n", ret);
- return ret;
+ goto err_disable_clocks;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(regs))
- return PTR_ERR(regs);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
+ goto err_disable_clocks;
+ }
spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs,
&rk_spdif_regmap_config);
if (IS_ERR(spdif->regmap)) {
dev_err(&pdev->dev,
"Failed to initialise managed register map\n");
- return PTR_ERR(spdif->regmap);
+ ret = PTR_ERR(spdif->regmap);
+ goto err_disable_clocks;
}
spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR;
@@ -373,6 +377,10 @@ static int rk_spdif_probe(struct platform_device *pdev)
err_pm_runtime:
pm_runtime_disable(&pdev->dev);
+err_disable_clocks:
+ clk_disable_unprepare(spdif->mclk);
+err_disable_hclk:
+ clk_disable_unprepare(spdif->hclk);
return ret;
}
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 34deba4..0e66cd8 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -60,13 +60,13 @@ static int bells_set_bias_level(struct snd_soc_card *card,
{
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *codec_dai;
- struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
struct bells_drvdata *bells = card->drvdata;
int ret;
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
codec_dai = rtd->codec_dai;
- codec = codec_dai->codec;
+ component = codec_dai->component;
if (dapm->dev != codec_dai->dev)
return 0;
@@ -76,7 +76,7 @@ static int bells_set_bias_level(struct snd_soc_card *card,
if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
break;
- ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
+ ret = snd_soc_component_set_pll(component, WM5102_FLL1,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
bells->sysclk_rate);
@@ -84,7 +84,7 @@ static int bells_set_bias_level(struct snd_soc_card *card,
pr_err("Failed to start FLL: %d\n", ret);
if (bells->asyncclk_rate) {
- ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
+ ret = snd_soc_component_set_pll(component, WM5102_FLL2,
ARIZONA_FLL_SRC_AIF2BCLK,
BCLK2_RATE,
bells->asyncclk_rate);
@@ -106,27 +106,27 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
{
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *codec_dai;
- struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
struct bells_drvdata *bells = card->drvdata;
int ret;
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
codec_dai = rtd->codec_dai;
- codec = codec_dai->codec;
+ component = codec_dai->component;
if (dapm->dev != codec_dai->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_STANDBY:
- ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
+ ret = snd_soc_component_set_pll(component, WM5102_FLL1, 0, 0, 0);
if (ret < 0) {
pr_err("Failed to stop FLL: %d\n", ret);
return ret;
}
if (bells->asyncclk_rate) {
- ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
+ ret = snd_soc_component_set_pll(component, WM5102_FLL2,
0, 0, 0);
if (ret < 0) {
pr_err("Failed to stop FLL: %d\n", ret);
@@ -148,8 +148,8 @@ static int bells_late_probe(struct snd_soc_card *card)
{
struct bells_drvdata *bells = card->drvdata;
struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_codec *wm0010;
- struct snd_soc_codec *codec;
+ struct snd_soc_component *wm0010;
+ struct snd_soc_component *component;
struct snd_soc_dai *aif1_dai;
struct snd_soc_dai *aif2_dai;
struct snd_soc_dai *aif3_dai;
@@ -157,22 +157,22 @@ static int bells_late_probe(struct snd_soc_card *card)
int ret;
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name);
- wm0010 = rtd->codec;
+ wm0010 = rtd->codec_dai->component;
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
- codec = rtd->codec;
+ component = rtd->codec_dai->component;
aif1_dai = rtd->codec_dai;
- ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+ ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1,
bells->sysclk_rate,
SND_SOC_CLOCK_IN);
if (ret != 0) {
- dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+ dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret);
return ret;
}
- ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0);
+ ret = snd_soc_component_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0);
if (ret != 0) {
dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret);
return ret;
@@ -182,20 +182,20 @@ static int bells_late_probe(struct snd_soc_card *card)
if (ret != 0)
dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
- ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
+ ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_OPCLK, 0,
SYS_MCLK_RATE, SND_SOC_CLOCK_OUT);
if (ret != 0)
- dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
+ dev_err(component->dev, "Failed to set OPCLK: %d\n", ret);
if (card->num_rtd == DAI_CODEC_CP)
return 0;
- ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
+ ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK,
ARIZONA_CLK_SRC_FLL2,
bells->asyncclk_rate,
SND_SOC_CLOCK_IN);
if (ret != 0) {
- dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret);
+ dev_err(component->dev, "Failed to set ASYNCCLK: %d\n", ret);
return ret;
}
@@ -221,7 +221,7 @@ static int bells_late_probe(struct snd_soc_card *card)
return ret;
}
- ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
+ ret = snd_soc_component_set_sysclk(wm9081_dai->component, WM9081_SYSCLK_MCLK,
0, SYS_MCLK_RATE, 0);
if (ret != 0) {
dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 8ddb087..4672688 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -222,7 +222,7 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
NULL, &val, NULL);
val = val << shift;
- mask = 0xffff << shift;
+ mask = 0x0f1f << shift;
rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
@@ -250,7 +250,7 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
in = in << shift;
out = out << shift;
- mask = 0xffff << shift;
+ mask = 0x0f1f << shift;
switch (id / 2) {
case 0:
@@ -380,7 +380,7 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
ckr = 0x80000000;
}
- rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr);
+ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
rsnd_mod_write(adg_mod, BRRA, adg->rbga);
rsnd_mod_write(adg_mod, BRRB, adg->rbgb);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index c70eb20..64d5ecb 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
return 0;
}
-int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
+int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
+ struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- return runtime->channels;
+ /*
+ * params will be added when refine
+ * see
+ * __rsnd_soc_hw_rule_rate()
+ * __rsnd_soc_hw_rule_channels()
+ */
+ if (params)
+ return params_channels(params);
+ else
+ return runtime->channels;
}
-int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
+int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
+ struct snd_pcm_hw_params *params)
{
- int chan = rsnd_runtime_channel_original(io);
+ int chan = rsnd_runtime_channel_original_with_params(io, params);
struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
if (ctu_mod) {
@@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
return chan;
}
-int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
+int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
+ struct snd_pcm_hw_params *params)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
int chan = rsnd_io_is_play(io) ?
- rsnd_runtime_channel_after_ctu(io) :
- rsnd_runtime_channel_original(io);
+ rsnd_runtime_channel_after_ctu_with_params(io, params) :
+ rsnd_runtime_channel_original_with_params(io, params);
/* Use Multi SSI */
if (rsnd_runtime_is_ssi_multi(io))
@@ -262,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
- switch (runtime->sample_bits) {
+ switch (snd_pcm_format_width(runtime->format)) {
case 16:
return 8 << 16;
- case 32:
+ case 24:
return 0 << 16;
}
@@ -282,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
struct rsnd_mod *target;
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- u32 val = 0x76543210;
- u32 mask = ~0;
/*
- * *Hardware* L/R and *Software* L/R are inverted.
+ * *Hardware* L/R and *Software* L/R are inverted for 16bit data.
+ * 31..16 15...0
+ * HW: [L ch] [R ch]
+ * SW: [R ch] [L ch]
* We need to care about inversion timing to control
* Playback/Capture correctly.
* The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
@@ -313,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
target = cmd ? cmd : ssiu;
}
- mask <<= runtime->channels * 4;
- val = val & mask;
-
- switch (runtime->sample_bits) {
- case 16:
- val |= 0x67452301 & ~mask;
- break;
- case 32:
- val |= 0x76543210 & ~mask;
- break;
- }
-
- /*
- * exchange channeles on SRC if possible,
- * otherwise, R/L volume settings on DVC
- * changes inverted channels
- */
- if (mod == target)
- return val;
- else
+ /* Non target mod or 24bit data needs normal DALIGN */
+ if ((snd_pcm_format_width(runtime->format) != 16) ||
+ (mod != target))
return 0x76543210;
+ /* Target mod needs inverted DALIGN when 16bit */
+ else
+ return 0x67452301;
}
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
@@ -363,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
* HW 24bit data is located as 0x******00
*
*/
- switch (runtime->sample_bits) {
- case 16:
+ if (snd_pcm_format_width(runtime->format) == 16)
return 0;
- case 32:
- break;
- }
for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
tmod = rsnd_io_to_mod(io, mods[i]);
@@ -616,8 +611,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
- rsnd_dai_stream_init(io, substream);
-
ret = rsnd_dai_call(init, io, priv);
if (ret < 0)
goto dai_trigger_end;
@@ -639,7 +632,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
ret |= rsnd_dai_call(quit, io, priv);
- rsnd_dai_stream_quit(io);
break;
default:
ret = -EINVAL;
@@ -784,8 +776,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
return snd_interval_refine(iv, &p);
}
-static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule,
+ int is_play)
{
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
@@ -793,25 +786,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai = rule->private;
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
/*
* possible sampling rate limitation is same as
* 2ch if it supports multi ssi
+ * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
*/
ic = *ic_;
- if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
- ic.min = 2;
- ic.max = 2;
- }
+ ic.min =
+ ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
ARRAY_SIZE(rsnd_soc_hw_rate_list),
&ic, ir);
}
+static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ return __rsnd_soc_hw_rule_rate(params, rule, 1);
+}
+
+static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ return __rsnd_soc_hw_rule_rate(params, rule, 0);
+}
-static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule,
+ int is_play)
{
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
@@ -819,22 +824,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai = rule->private;
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
/*
* possible sampling rate limitation is same as
* 2ch if it supports multi ssi
+ * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
*/
ic = *ic_;
- if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
- ic.min = 2;
- ic.max = 2;
- }
+ ic.min =
+ ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
ARRAY_SIZE(rsnd_soc_hw_channels_list),
ir, &ic);
}
+static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ return __rsnd_soc_hw_rule_channels(params, rule, 1);
+}
+
+static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ return __rsnd_soc_hw_rule_channels(params, rule, 0);
+}
+
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
@@ -859,6 +876,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
int ret;
int i;
+ rsnd_dai_stream_init(io, substream);
+
/*
* Channel Limitation
* It depends on Platform design
@@ -886,11 +905,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
* It depends on Clock Master Mode
*/
if (rsnd_rdai_is_clk_master(rdai)) {
+ int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- rsnd_soc_hw_rule_rate, dai,
+ is_play ? rsnd_soc_hw_rule_rate_playback :
+ rsnd_soc_hw_rule_rate_capture,
+ dai,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- rsnd_soc_hw_rule_channels, dai,
+ is_play ? rsnd_soc_hw_rule_channels_playback :
+ rsnd_soc_hw_rule_channels_capture,
+ dai,
SNDRV_PCM_HW_PARAM_RATE, -1);
}
@@ -915,6 +940,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
* call rsnd_dai_call without spinlock
*/
rsnd_dai_call(nolock_stop, io, priv);
+
+ rsnd_dai_stream_quit(io);
}
static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
@@ -990,7 +1017,7 @@ of_node_compatible:
static void __rsnd_dai_probe(struct rsnd_priv *priv,
struct device_node *dai_np,
- int dai_i, int is_graph)
+ int dai_i)
{
struct device_node *playback, *capture;
struct rsnd_dai_stream *io_playback;
@@ -1089,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
dai_i = 0;
if (is_graph) {
for_each_endpoint_of_node(dai_node, dai_np) {
- __rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
+ __rsnd_dai_probe(priv, dai_np, dai_i);
rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
dai_i++;
}
} else {
for_each_child_of_node(dai_node, dai_np)
- __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
+ __rsnd_dai_probe(priv, dai_np, dai_i++);
}
return 0;
@@ -1332,8 +1359,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
return snd_pcm_lib_preallocate_pages_for_all(
rtd->pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
+ SNDRV_DMA_TYPE_DEV,
+ rtd->card->snd_card->dev,
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
}
@@ -1496,6 +1523,8 @@ static int rsnd_remove(struct platform_device *pdev)
};
int ret = 0, i;
+ snd_soc_disconnect_sync(&pdev->dev);
+
pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) {
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index fd557ab..41de234 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -26,10 +26,7 @@
struct rsnd_dmaen {
struct dma_chan *chan;
dma_cookie_t cookie;
- dma_addr_t dma_buf;
unsigned int dma_len;
- unsigned int dma_period;
- unsigned int dma_cnt;
};
struct rsnd_dmapp {
@@ -71,69 +68,10 @@ static struct rsnd_mod mem = {
/*
* Audio DMAC
*/
-#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1)
-#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0)
-static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io,
- int i, int sync)
-{
- struct device *dev = dmaen->chan->device->dev;
- enum dma_data_direction dir;
- int is_play = rsnd_io_is_play(io);
- dma_addr_t buf;
- int len, max;
- size_t period;
-
- len = dmaen->dma_len;
- period = dmaen->dma_period;
- max = len / period;
- i = i % max;
- buf = dmaen->dma_buf + (period * i);
-
- dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-
- if (sync)
- dma_sync_single_for_device(dev, buf, period, dir);
- else
- dma_sync_single_for_cpu(dev, buf, period, dir);
-}
-
static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
- struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- bool elapsed = false;
- unsigned long flags;
-
- /*
- * Renesas sound Gen1 needs 1 DMAC,
- * Gen2 needs 2 DMAC.
- * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
- * But, Audio-DMAC-peri-peri doesn't have interrupt,
- * and this driver is assuming that here.
- */
- spin_lock_irqsave(&priv->lock, flags);
-
- if (rsnd_io_is_working(io)) {
- rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt);
-
- /*
- * Next period is already started.
- * Let's sync Next Next period
- * see
- * rsnd_dmaen_start()
- */
- rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2);
-
- elapsed = true;
-
- dmaen->dma_cnt++;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (elapsed)
+ if (rsnd_io_is_working(io))
rsnd_dai_period_elapsed(io);
}
@@ -165,14 +103,8 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- if (dmaen->chan) {
- int is_play = rsnd_io_is_play(io);
-
+ if (dmaen->chan)
dmaengine_terminate_all(dmaen->chan);
- dma_unmap_single(dmaen->chan->device->dev,
- dmaen->dma_buf, dmaen->dma_len,
- is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- }
return 0;
}
@@ -237,11 +169,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc;
struct dma_slave_config cfg = {};
- dma_addr_t buf;
- size_t len;
- size_t period;
int is_play = rsnd_io_is_play(io);
- int i;
int ret;
cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
@@ -258,19 +186,10 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
if (ret < 0)
return ret;
- len = snd_pcm_lib_buffer_bytes(substream);
- period = snd_pcm_lib_period_bytes(substream);
- buf = dma_map_single(dmaen->chan->device->dev,
- substream->runtime->dma_area,
- len,
- is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (dma_mapping_error(dmaen->chan->device->dev, buf)) {
- dev_err(dev, "dma map failed\n");
- return -EIO;
- }
-
desc = dmaengine_prep_dma_cyclic(dmaen->chan,
- buf, len, period,
+ substream->runtime->dma_addr,
+ snd_pcm_lib_buffer_bytes(substream),
+ snd_pcm_lib_period_bytes(substream),
is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -282,18 +201,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
desc->callback = rsnd_dmaen_complete;
desc->callback_param = rsnd_mod_get(dma);
- dmaen->dma_buf = buf;
- dmaen->dma_len = len;
- dmaen->dma_period = period;
- dmaen->dma_cnt = 0;
-
- /*
- * synchronize this and next period
- * see
- * __rsnd_dmaen_complete()
- */
- for (i = 0; i < 2; i++)
- rsnd_dmaen_sync(dmaen, io, i);
+ dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream);
dmaen->cookie = dmaengine_submit(desc);
if (dmaen->cookie < 0) {
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 57cd2bc..ad65235 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
struct device_node *playback,
struct device_node *capture);
-int rsnd_runtime_channel_original(struct rsnd_dai_stream *io);
-int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io);
-int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
+#define rsnd_runtime_channel_original(io) \
+ rsnd_runtime_channel_original_with_params(io, NULL)
+int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
+ struct snd_pcm_hw_params *params);
+#define rsnd_runtime_channel_after_ctu(io) \
+ rsnd_runtime_channel_after_ctu_with_params(io, NULL)
+int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
+ struct snd_pcm_hw_params *params);
+#define rsnd_runtime_channel_for_ssi(io) \
+ rsnd_runtime_channel_for_ssi_with_params(io, NULL)
+int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
+ struct snd_pcm_hw_params *params);
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index fece1e5f..97a9db8 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -79,8 +79,8 @@ struct rsnd_ssi {
int irq;
unsigned int usrcnt;
+ /* for PIO */
int byte_pos;
- int period_pos;
int byte_per_period;
int next_period_byte;
};
@@ -371,11 +371,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
if (rsnd_io_is_play(io))
cr_own |= TRMD;
- switch (runtime->sample_bits) {
+ switch (snd_pcm_format_width(runtime->format)) {
case 16:
cr_own |= DWL_16;
break;
- case 32:
+ case 24:
cr_own |= DWL_24;
break;
}
@@ -414,59 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
ssi->cr_en);
}
-static void rsnd_ssi_pointer_init(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-
- ssi->byte_pos = 0;
- ssi->period_pos = 0;
- ssi->byte_per_period = runtime->period_size *
- runtime->channels *
- samples_to_bytes(runtime, 1);
- ssi->next_period_byte = ssi->byte_per_period;
-}
-
-static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- int additional)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- int pos = ssi->byte_pos + additional;
-
- pos %= (runtime->periods * ssi->byte_per_period);
-
- return pos;
-}
-
-static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- int byte)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
- ssi->byte_pos += byte;
-
- if (ssi->byte_pos >= ssi->next_period_byte) {
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-
- ssi->period_pos++;
- ssi->next_period_byte += ssi->byte_per_period;
-
- if (ssi->period_pos >= runtime->periods) {
- ssi->byte_pos = 0;
- ssi->period_pos = 0;
- ssi->next_period_byte = ssi->byte_per_period;
- }
-
- return true;
- }
-
- return false;
-}
-
/*
* SSI mod common functions
*/
@@ -480,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
if (!rsnd_ssi_is_run_mods(mod, io))
return 0;
- rsnd_ssi_pointer_init(mod, io);
-
ssi->usrcnt++;
rsnd_mod_power_on(mod);
@@ -652,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
return 0;
}
+static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io);
static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
@@ -670,30 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
status = rsnd_ssi_status_get(mod);
/* PIO only */
- if (!is_dma && (status & DIRQ)) {
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- u32 *buf = (u32 *)(runtime->dma_area +
- rsnd_ssi_pointer_offset(mod, io, 0));
- int shift = 0;
-
- switch (runtime->sample_bits) {
- case 32:
- shift = 8;
- break;
- }
-
- /*
- * 8/16/32 data can be assesse to TDR/RDR register
- * directly as 32bit data
- * see rsnd_ssi_init()
- */
- if (rsnd_io_is_play(io))
- rsnd_mod_write(mod, SSITDR, (*buf) << shift);
- else
- *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
-
- elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf));
- }
+ if (!is_dma && (status & DIRQ))
+ elapsed = rsnd_ssi_pio_interrupt(mod, io);
/* DMA only */
if (is_dma && (status & (UIRQ | OIRQ)))
@@ -831,14 +756,78 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_ssi_pointer(struct rsnd_mod *mod,
+/*
+ * SSI PIO functions
+ */
+static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos);
+ int shift = 0;
+ int byte_pos;
+ bool elapsed = false;
+
+ if (snd_pcm_format_width(runtime->format) == 24)
+ shift = 8;
+
+ /*
+ * 8/16/32 data can be assesse to TDR/RDR register
+ * directly as 32bit data
+ * see rsnd_ssi_init()
+ */
+ if (rsnd_io_is_play(io))
+ rsnd_mod_write(mod, SSITDR, (*buf) << shift);
+ else
+ *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
+
+ byte_pos = ssi->byte_pos + sizeof(*buf);
+
+ if (byte_pos >= ssi->next_period_byte) {
+ int period_pos = byte_pos / ssi->byte_per_period;
+
+ if (period_pos >= runtime->periods) {
+ byte_pos = 0;
+ period_pos = 0;
+ }
+
+ ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period;
+
+ elapsed = true;
+ }
+
+ WRITE_ONCE(ssi->byte_pos, byte_pos);
+
+ return elapsed;
+}
+
+static int rsnd_ssi_pio_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+ if (!rsnd_ssi_is_parent(mod, io)) {
+ ssi->byte_pos = 0;
+ ssi->byte_per_period = runtime->period_size *
+ runtime->channels *
+ samples_to_bytes(runtime, 1);
+ ssi->next_period_byte = ssi->byte_per_period;
+ }
+
+ return rsnd_ssi_init(mod, io, priv);
+}
+
+static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
snd_pcm_uframes_t *pointer)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- *pointer = bytes_to_frames(runtime, ssi->byte_pos);
+ *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos));
return 0;
}
@@ -847,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = SSI_NAME,
.probe = rsnd_ssi_common_probe,
.remove = rsnd_ssi_common_remove,
- .init = rsnd_ssi_init,
+ .init = rsnd_ssi_pio_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_start,
.stop = rsnd_ssi_stop,
.irq = rsnd_ssi_irq,
- .pointer= rsnd_ssi_pointer,
+ .pointer = rsnd_ssi_pio_pointer,
.pcm_new = rsnd_ssi_pcm_new,
.hw_params = rsnd_ssi_hw_params,
};
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 4d94875..6ff8a36 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -125,6 +125,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
{
int hdmi = rsnd_ssi_hdmi_port(io);
int ret;
+ u32 mode = 0;
ret = rsnd_ssiu_init(mod, io, priv);
if (ret < 0)
@@ -136,9 +137,11 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
* see
* rsnd_ssi_config_init()
*/
- rsnd_mod_write(mod, SSI_MODE, 0x1);
+ mode = 0x1;
}
+ rsnd_mod_write(mod, SSI_MODE, mode);
+
if (rsnd_ssi_use_busif(io)) {
rsnd_mod_write(mod, SSI_BUSIF_ADINR,
rsnd_get_adinr_bit(mod, io) |
diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c
index f21df28..3d7e1ff 100644
--- a/sound/soc/soc-acpi.c
+++ b/sound/soc/soc-acpi.c
@@ -16,79 +16,16 @@
#include <sound/soc-acpi.h>
-static acpi_status snd_soc_acpi_find_name(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- struct acpi_device *adev;
- const char *name = NULL;
-
- if (acpi_bus_get_device(handle, &adev))
- return AE_OK;
-
- if (adev->status.present && adev->status.functional) {
- name = acpi_dev_name(adev);
- *(const char **)ret = name;
- return AE_CTRL_TERMINATE;
- }
-
- return AE_OK;
-}
-
-const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
-{
- const char *name = NULL;
- acpi_status status;
-
- status = acpi_get_devices(hid, snd_soc_acpi_find_name, NULL,
- (void **)&name);
-
- if (ACPI_FAILURE(status) || name[0] == '\0')
- return NULL;
-
- return name;
-}
-EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid);
-
-static acpi_status snd_soc_acpi_mach_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- unsigned long long sta;
- acpi_status status;
-
- *(bool *)context = true;
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
- *(bool *)context = false;
-
- return AE_OK;
-}
-
-bool snd_soc_acpi_check_hid(const u8 hid[ACPI_ID_LEN])
-{
- acpi_status status;
- bool found = false;
-
- status = acpi_get_devices(hid, snd_soc_acpi_mach_match, &found, NULL);
-
- if (ACPI_FAILURE(status))
- return false;
-
- return found;
-}
-EXPORT_SYMBOL_GPL(snd_soc_acpi_check_hid);
-
struct snd_soc_acpi_mach *
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
{
struct snd_soc_acpi_mach *mach;
for (mach = machines; mach->id[0]; mach++) {
- if (snd_soc_acpi_check_hid(mach->id) == true) {
- if (mach->machine_quirk == NULL)
- return mach;
-
- if (mach->machine_quirk(mach) != NULL)
- return mach;
+ if (acpi_dev_present(mach->id, NULL, -1)) {
+ if (mach->machine_quirk)
+ mach = mach->machine_quirk(mach);
+ return mach;
}
}
return NULL;
@@ -163,7 +100,7 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
return mach;
for (i = 0; i < codec_list->num_codecs; i++) {
- if (snd_soc_acpi_check_hid(codec_list->codecs[i]) != true)
+ if (!acpi_dev_present(codec_list->codecs[i], NULL, -1))
return NULL;
}
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index d9b1e64..81232f4 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -1096,7 +1096,6 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
*/
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
{
- struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom;
@@ -1199,8 +1198,9 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
ret = snd_compress_new(rtd->card->snd_card, num, direction,
new_name, compr);
if (ret < 0) {
+ component = rtd->codec_dai->component;
pr_err("compress asoc: can't create compress for codec %s\n",
- codec->component.name);
+ component->name);
goto compr_err;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c0edac8..e918795 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -213,7 +213,7 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_pmdown_time.attr)
return attr->mode; /* always visible */
- return rtd->codec ? attr->mode : 0; /* enabled only with codec */
+ return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */
}
static const struct attribute_group soc_dapm_dev_group = {
@@ -349,120 +349,84 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component)
"ASoC: Failed to create codec register debugfs file\n");
}
-static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+static int codec_list_seq_show(struct seq_file *m, void *v)
{
- char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- ssize_t len, ret = 0;
struct snd_soc_codec *codec;
- if (!buf)
- return -ENOMEM;
-
mutex_lock(&client_mutex);
- list_for_each_entry(codec, &codec_list, list) {
- len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
- codec->component.name);
- if (len >= 0)
- ret += len;
- if (ret > PAGE_SIZE) {
- ret = PAGE_SIZE;
- break;
- }
- }
+ list_for_each_entry(codec, &codec_list, list)
+ seq_printf(m, "%s\n", codec->component.name);
mutex_unlock(&client_mutex);
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- kfree(buf);
+ return 0;
+}
- return ret;
+static int codec_list_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, codec_list_seq_show, NULL);
}
static const struct file_operations codec_list_fops = {
- .read = codec_list_read_file,
- .llseek = default_llseek,/* read accesses f_pos */
+ .open = codec_list_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
-static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+static int dai_list_seq_show(struct seq_file *m, void *v)
{
- char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- ssize_t len, ret = 0;
struct snd_soc_component *component;
struct snd_soc_dai *dai;
- if (!buf)
- return -ENOMEM;
-
mutex_lock(&client_mutex);
- list_for_each_entry(component, &component_list, list) {
- list_for_each_entry(dai, &component->dai_list, list) {
- len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
- dai->name);
- if (len >= 0)
- ret += len;
- if (ret > PAGE_SIZE) {
- ret = PAGE_SIZE;
- break;
- }
- }
- }
+ list_for_each_entry(component, &component_list, list)
+ list_for_each_entry(dai, &component->dai_list, list)
+ seq_printf(m, "%s\n", dai->name);
mutex_unlock(&client_mutex);
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- kfree(buf);
+ return 0;
+}
- return ret;
+static int dai_list_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dai_list_seq_show, NULL);
}
static const struct file_operations dai_list_fops = {
- .read = dai_list_read_file,
- .llseek = default_llseek,/* read accesses f_pos */
+ .open = dai_list_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
-static ssize_t platform_list_read_file(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
+static int platform_list_seq_show(struct seq_file *m, void *v)
{
- char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- ssize_t len, ret = 0;
struct snd_soc_platform *platform;
- if (!buf)
- return -ENOMEM;
-
mutex_lock(&client_mutex);
- list_for_each_entry(platform, &platform_list, list) {
- len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
- platform->component.name);
- if (len >= 0)
- ret += len;
- if (ret > PAGE_SIZE) {
- ret = PAGE_SIZE;
- break;
- }
- }
+ list_for_each_entry(platform, &platform_list, list)
+ seq_printf(m, "%s\n", platform->component.name);
mutex_unlock(&client_mutex);
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- kfree(buf);
+ return 0;
+}
- return ret;
+static int platform_list_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, platform_list_seq_show, NULL);
}
static const struct file_operations platform_list_fops = {
- .read = platform_list_read_file,
- .llseek = default_llseek,/* read accesses f_pos */
+ .open = platform_list_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
static void soc_init_card_debugfs(struct snd_soc_card *card)
@@ -491,7 +455,6 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
debugfs_remove_recursive(card->debugfs_card_root);
}
-
static void snd_soc_debugfs_init(void)
{
snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
@@ -598,6 +561,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
return NULL;
}
+EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
const char *dai_link, int stream)
@@ -1392,6 +1356,17 @@ static int soc_init_dai_link(struct snd_soc_card *card,
return 0;
}
+void snd_soc_disconnect_sync(struct device *dev)
+{
+ struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL);
+
+ if (!component || !component->card)
+ return;
+
+ snd_card_disconnect_sync(component->card->snd_card);
+}
+EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync);
+
/**
* snd_soc_add_dai_link - Add a DAI link dynamically
* @card: The ASoC card to which the DAI link is added
@@ -1945,7 +1920,9 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
}
/* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */
- if (cpu_dai->codec) {
+ /* the component which has non_legacy_dai_naming is Codec */
+ if (cpu_dai->codec ||
+ cpu_dai->component->driver->non_legacy_dai_naming) {
unsigned int inv_dai_fmt;
inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
@@ -3149,7 +3126,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
- list_add(&dai->list, &component->dai_list);
+ list_add_tail(&dai->list, &component->dai_list);
component->num_dai++;
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
@@ -3176,8 +3153,6 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count);
- component->dai_drv = dai_drv;
-
for (i = 0; i < count; i++) {
dai = soc_add_dai(component, dai_drv + i,
@@ -4354,6 +4329,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args,
args,
dai_name);
} else {
+ struct snd_soc_dai *dai;
int id = -1;
switch (args->args_count) {
@@ -4375,7 +4351,14 @@ int snd_soc_get_dai_name(struct of_phandle_args *args,
ret = 0;
- *dai_name = pos->dai_drv[id].name;
+ /* find target DAI */
+ list_for_each_entry(dai, &pos->dai_list, list) {
+ if (id == 0)
+ break;
+ id--;
+ }
+
+ *dai_name = dai->driver->name;
if (!*dai_name)
*dai_name = pos->name;
}
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 20340ad..2bc1c4c 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -34,6 +34,10 @@ int snd_soc_component_read(struct snd_soc_component *component,
ret = regmap_read(component->regmap, reg, val);
else if (component->read)
ret = component->read(component, reg, val);
+ else if (component->driver->read) {
+ *val = component->driver->read(component, reg);
+ ret = 0;
+ }
else
ret = -EIO;
@@ -70,6 +74,8 @@ int snd_soc_component_write(struct snd_soc_component *component,
return regmap_write(component->regmap, reg, val);
else if (component->write)
return component->write(component, reg, val);
+ else if (component->driver->write)
+ return component->driver->write(component, reg, val);
else
return -EIO;
}
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 500f98c..7144a51 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -378,7 +378,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
unsigned int rshift = mc->rshift;
int max = mc->max;
int min = mc->min;
- int mask = (1 << (fls(min + max) - 1)) - 1;
+ unsigned int mask = (1 << (fls(min + max) - 1)) - 1;
unsigned int val;
int ret;
@@ -423,7 +423,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
unsigned int rshift = mc->rshift;
int max = mc->max;
int min = mc->min;
- int mask = (1 << (fls(min + max) - 1)) - 1;
+ unsigned int mask = (1 << (fls(min + max) - 1)) - 1;
int err = 0;
unsigned int val, val_mask, val2 = 0;
diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig
index 3398e6c..3ad881f 100644
--- a/sound/soc/stm/Kconfig
+++ b/sound/soc/stm/Kconfig
@@ -28,4 +28,16 @@ config SND_SOC_STM32_SPDIFRX
help
Say Y if you want to enable S/PDIF capture for STM32
+config SND_SOC_STM32_DFSDM
+ tristate "SoC Audio support for STM32 DFSDM"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on SND_SOC
+ depends on STM32_DFSDM_ADC
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select SND_SOC_DMIC
+ select IIO_BUFFER_CB
+ help
+ Select this option to enable the STM32 Digital Filter
+ for Sigma Delta Modulators (DFSDM) driver used
+ in various STM32 series for digital microphone capture.
endmenu
diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile
index 5b7f0fa..3143c0b 100644
--- a/sound/soc/stm/Makefile
+++ b/sound/soc/stm/Makefile
@@ -13,3 +13,6 @@ obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o
# SPDIFRX
snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o
obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o
+
+#DFSDM
+obj-$(CONFIG_SND_SOC_STM32_DFSDM) += stm32_adfsdm.o
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
new file mode 100644
index 0000000..7306e3e
--- /dev/null
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is part of STM32 DFSDM ASoC DAI driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ * Olivier Moysan <olivier.moysan@st.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/adc/stm32-dfsdm-adc.h>
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#define STM32_ADFSDM_DRV_NAME "stm32-adfsdm"
+
+#define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2)
+#define DFSDM_MAX_PERIODS 6
+
+struct stm32_adfsdm_priv {
+ struct snd_soc_dai_driver dai_drv;
+ struct snd_pcm_substream *substream;
+ struct device *dev;
+
+ /* IIO */
+ struct iio_channel *iio_ch;
+ struct iio_cb_buffer *iio_cb;
+ bool iio_active;
+
+ /* PCM buffer */
+ unsigned char *pcm_buff;
+ unsigned int pos;
+};
+
+static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+
+ .rate_min = 8000,
+ .rate_max = 32000,
+
+ .channels_min = 1,
+ .channels_max = 1,
+
+ .periods_min = 2,
+ .periods_max = DFSDM_MAX_PERIODS,
+
+ .period_bytes_max = DFSDM_MAX_PERIOD_SIZE,
+ .buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE
+};
+
+static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+ if (priv->iio_active) {
+ iio_channel_stop_all_cb(priv->iio_cb);
+ priv->iio_active = false;
+ }
+}
+
+static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = iio_write_channel_attribute(priv->iio_ch,
+ substream->runtime->rate, 0,
+ IIO_CHAN_INFO_SAMP_FREQ);
+ if (ret < 0) {
+ dev_err(dai->dev, "%s: Failed to set %d sampling rate\n",
+ __func__, substream->runtime->rate);
+ return ret;
+ }
+
+ if (!priv->iio_active) {
+ ret = iio_channel_start_all_cb(priv->iio_cb);
+ if (!ret)
+ priv->iio_active = true;
+ else
+ dev_err(dai->dev, "%s: IIO channel start failed (%d)\n",
+ __func__, ret);
+ }
+
+ return ret;
+}
+
+static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
+ ssize_t size;
+ char str_freq[10];
+
+ dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq);
+
+ /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */
+
+ snprintf(str_freq, sizeof(str_freq), "%d\n", freq);
+ size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq",
+ str_freq, sizeof(str_freq));
+ if (size != sizeof(str_freq)) {
+ dev_err(dai->dev, "%s: Failed to set SPI clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = {
+ .shutdown = stm32_adfsdm_shutdown,
+ .prepare = stm32_adfsdm_dai_prepare,
+ .set_sysclk = stm32_adfsdm_set_sysclk,
+};
+
+static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000),
+ },
+ .ops = &stm32_adfsdm_dai_ops,
+};
+
+static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
+ .name = "stm32_dfsdm_audio",
+};
+
+static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
+{
+ struct stm32_adfsdm_priv *priv = private;
+ struct snd_soc_pcm_runtime *rtd = priv->substream->private_data;
+ u8 *pcm_buff = priv->pcm_buff;
+ u8 *src_buff = (u8 *)data;
+ unsigned int buff_size = snd_pcm_lib_buffer_bytes(priv->substream);
+ unsigned int period_size = snd_pcm_lib_period_bytes(priv->substream);
+ unsigned int old_pos = priv->pos;
+ unsigned int cur_size = size;
+
+ dev_dbg(rtd->dev, "%s: buff_add :%p, pos = %d, size = %zu\n",
+ __func__, &pcm_buff[priv->pos], priv->pos, size);
+
+ if ((priv->pos + size) > buff_size) {
+ memcpy(&pcm_buff[priv->pos], src_buff, buff_size - priv->pos);
+ cur_size -= buff_size - priv->pos;
+ priv->pos = 0;
+ }
+
+ memcpy(&pcm_buff[priv->pos], &src_buff[size - cur_size], cur_size);
+ priv->pos = (priv->pos + cur_size) % buff_size;
+
+ if (cur_size != size || (old_pos && (old_pos % period_size < size)))
+ snd_pcm_period_elapsed(priv->substream);
+
+ return 0;
+}
+
+static int stm32_adfsdm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct stm32_adfsdm_priv *priv =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ priv->pos = 0;
+ return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev,
+ stm32_afsdm_pcm_cb, priv);
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev);
+ }
+
+ return -EINVAL;
+}
+
+static int stm32_adfsdm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ int ret;
+
+ ret = snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw);
+ if (!ret)
+ priv->substream = substream;
+
+ return ret;
+}
+
+static int stm32_adfsdm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct stm32_adfsdm_priv *priv =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ snd_pcm_lib_free_pages(substream);
+ priv->substream = NULL;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct stm32_adfsdm_priv *priv =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ return bytes_to_frames(substream->runtime, priv->pos);
+}
+
+static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct stm32_adfsdm_priv *priv =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ int ret;
+
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ if (ret < 0)
+ return ret;
+ priv->pcm_buff = substream->runtime->dma_area;
+
+ return iio_channel_cb_set_buffer_watermark(priv->iio_cb,
+ params_period_size(params));
+}
+
+static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+
+ return 0;
+}
+
+static struct snd_pcm_ops stm32_adfsdm_pcm_ops = {
+ .open = stm32_adfsdm_pcm_open,
+ .close = stm32_adfsdm_pcm_close,
+ .hw_params = stm32_adfsdm_pcm_hw_params,
+ .hw_free = stm32_adfsdm_pcm_hw_free,
+ .trigger = stm32_adfsdm_trigger,
+ .pointer = stm32_adfsdm_pcm_pointer,
+};
+
+static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ struct stm32_adfsdm_priv *priv =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE;
+
+ return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ priv->dev, size, size);
+}
+
+static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_soc_pcm_runtime *rtd;
+ struct stm32_adfsdm_priv *priv;
+
+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ if (substream) {
+ rtd = substream->private_data;
+ priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+ }
+}
+
+static struct snd_soc_platform_driver stm32_adfsdm_soc_platform = {
+ .ops = &stm32_adfsdm_pcm_ops,
+ .pcm_new = stm32_adfsdm_pcm_new,
+ .pcm_free = stm32_adfsdm_pcm_free,
+};
+
+static const struct of_device_id stm32_adfsdm_of_match[] = {
+ {.compatible = "st,stm32h7-dfsdm-dai"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match);
+
+static int stm32_adfsdm_probe(struct platform_device *pdev)
+{
+ struct stm32_adfsdm_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->dai_drv = stm32_adfsdm_dai;
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &stm32_adfsdm_dai_component,
+ &priv->dai_drv, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Associate iio channel */
+ priv->iio_ch = devm_iio_channel_get_all(&pdev->dev);
+ if (IS_ERR(priv->iio_ch))
+ return PTR_ERR(priv->iio_ch);
+
+ priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL);
+ if (IS_ERR(priv->iio_cb))
+ return PTR_ERR(priv->iio_cb);
+
+ ret = devm_snd_soc_register_platform(&pdev->dev,
+ &stm32_adfsdm_soc_platform);
+ if (ret < 0)
+ dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
+ __func__);
+
+ return ret;
+}
+
+static struct platform_driver stm32_adfsdm_driver = {
+ .driver = {
+ .name = STM32_ADFSDM_DRV_NAME,
+ .of_match_table = stm32_adfsdm_of_match,
+ },
+ .probe = stm32_adfsdm_probe,
+};
+
+module_platform_driver(stm32_adfsdm_driver);
+
+MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
+MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME);
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d6f71a3..d743b7d 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -28,16 +28,6 @@
#include "stm32_sai.h"
-static LIST_HEAD(sync_providers);
-static DEFINE_MUTEX(sync_mutex);
-
-struct sync_provider {
- struct list_head link;
- struct device_node *node;
- int (*sync_conf)(void *data, int synco);
- void *data;
-};
-
static const struct stm32_sai_conf stm32_sai_conf_f4 = {
.version = SAI_STM32F4,
};
@@ -70,9 +60,8 @@ static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
return 0;
}
-static int stm32_sai_sync_conf_provider(void *data, int synco)
+static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
{
- struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
u32 prev_synco;
int ret;
@@ -103,83 +92,42 @@ static int stm32_sai_sync_conf_provider(void *data, int synco)
return 0;
}
-static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+static int stm32_sai_set_sync(struct stm32_sai_data *sai_client,
+ struct device_node *np_provider,
+ int synco, int synci)
{
- struct sync_provider *provider;
+ struct platform_device *pdev = of_find_device_by_node(np_provider);
+ struct stm32_sai_data *sai_provider;
int ret;
- mutex_lock(&sync_mutex);
- list_for_each_entry(provider, &sync_providers, link) {
- if (provider->node == np) {
- ret = provider->sync_conf(provider->data, synco);
- mutex_unlock(&sync_mutex);
- return ret;
- }
+ if (!pdev) {
+ dev_err(&sai_client->pdev->dev,
+ "Device not found for node %s\n", np_provider->name);
+ return -ENODEV;
}
- mutex_unlock(&sync_mutex);
- /* SAI sync provider not found */
- return -ENODEV;
-}
-
-static int stm32_sai_set_sync(struct stm32_sai_data *sai,
- struct device_node *np_provider,
- int synco, int synci)
-{
- int ret;
+ sai_provider = platform_get_drvdata(pdev);
+ if (!sai_provider) {
+ dev_err(&sai_client->pdev->dev,
+ "SAI sync provider data not found\n");
+ return -EINVAL;
+ }
/* Configure sync client */
- stm32_sai_sync_conf_client(sai, synci);
+ ret = stm32_sai_sync_conf_client(sai_client, synci);
+ if (ret < 0)
+ return ret;
/* Configure sync provider */
- ret = stm32_sai_set_sync_provider(np_provider, synco);
-
- return ret;
-}
-
-static int stm32_sai_sync_add_provider(struct platform_device *pdev,
- void *data)
-{
- struct sync_provider *sp;
-
- sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
- if (!sp)
- return -ENOMEM;
-
- sp->node = of_node_get(pdev->dev.of_node);
- sp->data = data;
- sp->sync_conf = &stm32_sai_sync_conf_provider;
-
- mutex_lock(&sync_mutex);
- list_add(&sp->link, &sync_providers);
- mutex_unlock(&sync_mutex);
-
- return 0;
-}
-
-static void stm32_sai_sync_del_provider(struct device_node *np)
-{
- struct sync_provider *sp;
-
- mutex_lock(&sync_mutex);
- list_for_each_entry(sp, &sync_providers, link) {
- if (sp->node == np) {
- list_del(&sp->link);
- of_node_put(sp->node);
- break;
- }
- }
- mutex_unlock(&sync_mutex);
+ return stm32_sai_sync_conf_provider(sai_provider, synco);
}
static int stm32_sai_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct stm32_sai_data *sai;
struct reset_control *rst;
struct resource *res;
const struct of_device_id *of_id;
- int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
@@ -231,28 +179,11 @@ static int stm32_sai_probe(struct platform_device *pdev)
reset_control_deassert(rst);
}
- ret = stm32_sai_sync_add_provider(pdev, sai);
- if (ret < 0)
- return ret;
- sai->set_sync = &stm32_sai_set_sync;
-
sai->pdev = pdev;
+ sai->set_sync = &stm32_sai_set_sync;
platform_set_drvdata(pdev, sai);
- ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
- if (ret < 0)
- stm32_sai_sync_del_provider(np);
-
- return ret;
-}
-
-static int stm32_sai_remove(struct platform_device *pdev)
-{
- of_platform_depopulate(&pdev->dev);
-
- stm32_sai_sync_del_provider(pdev->dev.of_node);
-
- return 0;
+ return devm_of_platform_populate(&pdev->dev);
}
MODULE_DEVICE_TABLE(of, stm32_sai_ids);
@@ -263,7 +194,6 @@ static struct platform_driver stm32_sai_driver = {
.of_match_table = stm32_sai_ids,
},
.probe = stm32_sai_probe,
- .remove = stm32_sai_remove,
};
module_platform_driver(stm32_sai_driver);
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 5da4efe..8862816 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -590,12 +590,28 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
hwrate);
}
+
+static unsigned int sun4i_codec_src_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ 44100, 48000, 96000, 192000
+};
+
+
+static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
+ .count = ARRAY_SIZE(sun4i_codec_src_rates),
+ .list = sun4i_codec_src_rates,
+};
+
+
static int sun4i_codec_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
+
/*
* Stop issuing DRQ when we have room for less than 16 samples
* in our TX FIFO
@@ -633,9 +649,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
- .rates = SNDRV_PCM_RATE_8000_48000 |
- SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 24,
@@ -645,11 +659,8 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
- .rate_max = 192000,
- .rates = SNDRV_PCM_RATE_8000_48000 |
- SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000 |
- SNDRV_PCM_RATE_KNOT,
+ .rate_max = 48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 24,
@@ -1128,7 +1139,7 @@ static const struct snd_soc_component_driver sun4i_codec_component = {
.name = "sun4i-codec",
};
-#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_8000_192000
+#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS
#define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 04f9258..dca1143 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -269,10 +269,11 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
return false;
}
-static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
+static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
unsigned int rate,
unsigned int word_size)
{
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int oversample_rate, clk_rate;
int bclk_div, mclk_div;
int ret;
@@ -300,6 +301,7 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
break;
default:
+ dev_err(dai->dev, "Unsupported sample rate: %u\n", rate);
return -EINVAL;
}
@@ -308,18 +310,25 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
return ret;
oversample_rate = i2s->mclk_freq / rate;
- if (!sun4i_i2s_oversample_is_valid(oversample_rate))
+ if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {
+ dev_err(dai->dev, "Unsupported oversample rate: %d\n",
+ oversample_rate);
return -EINVAL;
+ }
bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
word_size);
- if (bclk_div < 0)
+ if (bclk_div < 0) {
+ dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
return -EINVAL;
+ }
mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
clk_rate, rate);
- if (mclk_div < 0)
+ if (mclk_div < 0) {
+ dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);
return -EINVAL;
+ }
/* Adjust the clock division values if needed */
bclk_div += i2s->variant->bclk_offset;
@@ -349,8 +358,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
u32 width;
channels = params_channels(params);
- if (channels != 2)
+ if (channels != 2) {
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
+ channels);
return -EINVAL;
+ }
if (i2s->variant->has_chcfg) {
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
@@ -382,6 +394,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
default:
+ dev_err(dai->dev, "Unsupported physical sample width: %d\n",
+ params_physical_width(params));
return -EINVAL;
}
i2s->playback_dma_data.addr_width = width;
@@ -393,6 +407,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
break;
default:
+ dev_err(dai->dev, "Unsupported sample width: %d\n",
+ params_width(params));
return -EINVAL;
}
@@ -401,7 +417,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
regmap_field_write(i2s->field_fmt_sr,
sr + i2s->variant->fmt_offset);
- return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
+ return sun4i_i2s_set_clk_rate(dai, params_rate(params),
params_width(params));
}
@@ -426,6 +442,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
break;
default:
+ dev_err(dai->dev, "Unsupported format: %d\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
@@ -464,6 +482,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_NB_NF:
break;
default:
+ dev_err(dai->dev, "Unsupported clock polarity: %d\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
return -EINVAL;
}
@@ -482,6 +502,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
val = SUN4I_I2S_CTRL_MODE_SLAVE;
break;
default:
+ dev_err(dai->dev, "Unsupported slave setting: %d\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -504,6 +526,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
val = 0;
break;
default:
+ dev_err(dai->dev, "Unsupported slave setting: %d\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -897,6 +921,23 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
};
+static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
+ .has_reset = true,
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+ .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+ .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .has_slave_select_bit = true,
+ .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+ .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+ .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+ .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+ .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
+
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
@@ -1121,6 +1162,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
.data = &sun6i_a31_i2s_quirks,
},
{
+ .compatible = "allwinner,sun8i-a83t-i2s",
+ .data = &sun8i_a83t_i2s_quirks,
+ },
+ {
.compatible = "allwinner,sun8i-h3-i2s",
.data = &sun8i_h3_i2s_quirks,
},
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 0537c63..2b4ceda 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -204,6 +204,10 @@ static int snd_usb_copy_string_desc(struct mixer_build *state,
int index, char *buf, int maxlen)
{
int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
+
+ if (len < 0)
+ return 0;
+
buf[len] = 0;
return len;
}
@@ -1476,9 +1480,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
return -EINVAL;
}
csize = hdr->bControlSize;
- if (csize <= 1) {
+ if (!csize) {
usb_audio_dbg(state->chip,
- "unit %u: invalid bControlSize <= 1\n",
+ "unit %u: invalid bControlSize == 0\n",
unitid);
return -EINVAL;
}
@@ -2169,19 +2173,25 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
kctl->private_value = (unsigned long)namelist;
kctl->private_free = usb_mixer_selector_elem_free;
- nameid = uac_selector_unit_iSelector(desc);
+ /* check the static mapping table at first */
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
- if (len)
- ;
- else if (nameid)
- snd_usb_copy_string_desc(state, nameid, kctl->id.name,
- sizeof(kctl->id.name));
- else {
- len = get_term_name(state, &state->oterm,
+ if (!len) {
+ /* no mapping ? */
+ /* if iSelector is given, use it */
+ nameid = uac_selector_unit_iSelector(desc);
+ if (nameid)
+ len = snd_usb_copy_string_desc(state, nameid,
+ kctl->id.name,
+ sizeof(kctl->id.name));
+ /* ... or pick up the terminal name at next */
+ if (!len)
+ len = get_term_name(state, &state->oterm,
kctl->id.name, sizeof(kctl->id.name), 0);
+ /* ... or use the fixed string "USB" as the last resort */
if (!len)
strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
+ /* and add the proper suffix */
if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
append_ctl_name(kctl, " Clock Source");
else if ((state->oterm.type & 0xff00) == 0x0100)
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 77eecaa..a66ef57 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1166,10 +1166,11 @@ static bool is_marantz_denon_dac(unsigned int id)
/* TEAC UD-501/UD-503/NT-503 USB DACs need a vendor cmd to switch
* between PCM/DOP and native DSD mode
*/
-static bool is_teac_50X_dac(unsigned int id)
+static bool is_teac_dsd_dac(unsigned int id)
{
switch (id) {
case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */
+ case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
return true;
}
return false;
@@ -1202,7 +1203,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
break;
}
mdelay(20);
- } else if (is_teac_50X_dac(subs->stream->chip->usb_id)) {
+ } else if (is_teac_dsd_dac(subs->stream->chip->usb_id)) {
/* Vendor mode switch cmd is required. */
switch (fmt->altsetting) {
case 3: /* DSD mode (DSD_U32) requested */
@@ -1392,7 +1393,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
}
/* TEAC devices with USB DAC functionality */
- if (is_teac_50X_dac(chip->usb_id)) {
+ if (is_teac_dsd_dac(chip->usb_id)) {
if (fp->altsetting == 3)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
}
OpenPOWER on IntegriCloud