mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
Merge remote-tracking branches 'asoc/fix/compress', 'asoc/fix/core', 'asoc/fix/dapm', 'asoc/fix/mtk' and 'asoc/fix/stm' into asoc-next
This commit is contained in:
commit
ce8ee02d51
2472 changed files with 39315 additions and 19482 deletions
|
|
@ -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(®ister_mutex);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(®ister_mutex);
|
||||
rmidi = snd_rawmidi_search(card, info->device);
|
||||
mutex_unlock(®ister_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(®ister_mutex);
|
||||
ret = __snd_rawmidi_info_select(card, info);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_rawmidi_info_select);
|
||||
|
||||
static int snd_rawmidi_info_select_user(struct snd_card *card,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
@ -6549,6 +6588,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
|
|||
SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
|
||||
{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},
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ source "sound/soc/stm/Kconfig"
|
|||
source "sound/soc/sunxi/Kconfig"
|
||||
source "sound/soc/tegra/Kconfig"
|
||||
source "sound/soc/txx9/Kconfig"
|
||||
source "sound/soc/uniphier/Kconfig"
|
||||
source "sound/soc/ux500/Kconfig"
|
||||
source "sound/soc/xtensa/Kconfig"
|
||||
source "sound/soc/zte/Kconfig"
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ obj-$(CONFIG_SND_SOC) += stm/
|
|||
obj-$(CONFIG_SND_SOC) += sunxi/
|
||||
obj-$(CONFIG_SND_SOC) += tegra/
|
||||
obj-$(CONFIG_SND_SOC) += txx9/
|
||||
obj-$(CONFIG_SND_SOC) += uniphier/
|
||||
obj-$(CONFIG_SND_SOC) += ux500/
|
||||
obj-$(CONFIG_SND_SOC) += xtensa/
|
||||
obj-$(CONFIG_SND_SOC) += zte/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -148,6 +150,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_TAS5086 if I2C
|
||||
select SND_SOC_TAS571X if I2C
|
||||
select SND_SOC_TAS5720 if I2C
|
||||
select SND_SOC_TAS6424 if I2C
|
||||
select SND_SOC_TFA9879 if I2C
|
||||
select SND_SOC_TLV320AIC23_I2C if I2C
|
||||
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
|
||||
|
|
@ -158,6 +161,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_TLV320AIC3X if I2C
|
||||
select SND_SOC_TPA6130A2 if I2C
|
||||
select SND_SOC_TLV320DAC33 if I2C
|
||||
select SND_SOC_TSCS42XX if I2C
|
||||
select SND_SOC_TS3A227E if I2C
|
||||
select SND_SOC_TWL4030 if TWL4030_CORE
|
||||
select SND_SOC_TWL6040 if TWL6040_CORE
|
||||
|
|
@ -623,6 +627,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 +669,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 +841,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"
|
||||
|
||||
|
|
@ -883,6 +903,13 @@ config SND_SOC_TAS5720
|
|||
Enable support for Texas Instruments TAS5720L/M high-efficiency mono
|
||||
Class-D audio power amplifiers.
|
||||
|
||||
config SND_SOC_TAS6424
|
||||
tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
|
||||
depends on I2C
|
||||
help
|
||||
Enable support for Texas Instruments TAS6424 high-efficiency
|
||||
digital input quad-channel Class-D audio power amplifiers.
|
||||
|
||||
config SND_SOC_TFA9879
|
||||
tristate "NXP Semiconductors TFA9879 amplifier"
|
||||
depends on I2C
|
||||
|
|
@ -913,12 +940,12 @@ config SND_SOC_TLV320AIC32X4
|
|||
tristate
|
||||
|
||||
config SND_SOC_TLV320AIC32X4_I2C
|
||||
tristate
|
||||
tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_TLV320AIC32X4
|
||||
|
||||
config SND_SOC_TLV320AIC32X4_SPI
|
||||
tristate
|
||||
tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_TLV320AIC32X4
|
||||
|
||||
|
|
@ -933,6 +960,13 @@ config SND_SOC_TS3A227E
|
|||
tristate "TI Headset/Mic detect and keypress chip"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TSCS42XX
|
||||
tristate "Tempo Semiconductor TSCS42xx CODEC"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Add support for Tempo Semiconductor's TSCS42xx audio CODEC.
|
||||
|
||||
config SND_SOC_TWL4030
|
||||
select MFD_TWL4030_AUDIO
|
||||
tristate
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -156,6 +159,7 @@ snd-soc-sti-sas-objs := sti-sas.o
|
|||
snd-soc-tas5086-objs := tas5086.o
|
||||
snd-soc-tas571x-objs := tas571x.o
|
||||
snd-soc-tas5720-objs := tas5720.o
|
||||
snd-soc-tas6424-objs := tas6424.o
|
||||
snd-soc-tfa9879-objs := tfa9879.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
||||
|
|
@ -167,6 +171,7 @@ snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
|
|||
snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
|
||||
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
|
||||
snd-soc-tlv320dac33-objs := tlv320dac33.o
|
||||
snd-soc-tscs42xx-objs := tscs42xx.o
|
||||
snd-soc-ts3a227e-objs := ts3a227e.o
|
||||
snd-soc-twl4030-objs := twl4030.o
|
||||
snd-soc-twl6040-objs := twl6040.o
|
||||
|
|
@ -330,6 +335,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 +351,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
|
||||
|
|
@ -395,6 +404,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
|
|||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
|
||||
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
|
||||
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
|
||||
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
|
||||
|
|
@ -406,6 +416,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o
|
|||
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
|
||||
obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o
|
||||
obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
|
||||
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
|
||||
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
|
||||
struct cx20442_priv {
|
||||
void *control_data;
|
||||
struct tty_struct *tty;
|
||||
struct regulator *por;
|
||||
};
|
||||
|
||||
|
|
@ -88,17 +88,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
|
|||
{"ADC", NULL, "Input Mixer"},
|
||||
};
|
||||
|
||||
static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
return reg_cache[reg];
|
||||
}
|
||||
|
||||
enum v253_vls {
|
||||
V253_VLS_NONE = 0,
|
||||
V253_VLS_T,
|
||||
|
|
@ -123,6 +112,8 @@ enum v253_vls {
|
|||
V253_VLS_TEST,
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* FIXME : these function will be re-used */
|
||||
static int cx20442_pm_to_v253_vls(u8 value)
|
||||
{
|
||||
switch (value & ~(1 << CX20442_AGC)) {
|
||||
|
|
@ -163,9 +154,9 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
if (reg >= codec->driver->reg_cache_size)
|
||||
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];
|
||||
|
|
@ -194,12 +185,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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Line discpline related code
|
||||
|
|
@ -252,8 +243,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 +266,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 +356,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 +369,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);
|
||||
}
|
||||
|
||||
|
|
@ -402,11 +390,7 @@ 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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
976
sound/soc/codecs/max98373.c
Normal file
976
sound/soc/codecs/max98373.c
Normal file
|
|
@ -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, ®);
|
||||
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 <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
212
sound/soc/codecs/max98373.h
Normal file
212
sound/soc/codecs/max98373.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
69
sound/soc/codecs/pcm186x-i2c.c
Normal file
69
sound/soc/codecs/pcm186x-i2c.c
Normal file
|
|
@ -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 <[email protected]>");
|
||||
MODULE_AUTHOR("Andrew F. Davis <[email protected]>");
|
||||
MODULE_DESCRIPTION("PCM186x Universal Audio ADC I2C Interface Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
69
sound/soc/codecs/pcm186x-spi.c
Normal file
69
sound/soc/codecs/pcm186x-spi.c
Normal file
|
|
@ -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 <[email protected]>");
|
||||
MODULE_AUTHOR("Andrew F. Davis <[email protected]>");
|
||||
MODULE_DESCRIPTION("PCM186x Universal Audio ADC SPI Interface Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
719
sound/soc/codecs/pcm186x.c
Normal file
719
sound/soc/codecs/pcm186x.c
Normal file
|
|
@ -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 <[email protected]>");
|
||||
MODULE_AUTHOR("Andrew F. Davis <[email protected]>");
|
||||
MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
220
sound/soc/codecs/pcm186x.h
Normal file
220
sound/soc/codecs/pcm186x.h
Normal file
|
|
@ -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_ */
|
||||
|
|
@ -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 <[email protected]>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
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);
|
||||
if (red < red_t) {
|
||||
bypass = false;
|
||||
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;
|
||||
m = m_t;
|
||||
k = k_t;
|
||||
goto code_find;
|
||||
}
|
||||
out_t = in_t / (k_t + 2);
|
||||
red = abs(f_out - out_t);
|
||||
if (red < red_t) {
|
||||
bypass = true;
|
||||
n = n_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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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,40 +3625,12 @@ 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[] = {
|
||||
{
|
||||
.ident = "Intel Strago",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Google Chrome",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Google Setzer",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Microsoft Surface 3",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct rt5645_platform_data buddy_platform_data = {
|
||||
.dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
|
||||
.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
|
||||
|
|
@ -3611,22 +3638,61 @@ static const struct rt5645_platform_data buddy_platform_data = {
|
|||
.level_trigger_irq = true,
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_platform_intel_broadwell[] = {
|
||||
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 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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 <[email protected]>");
|
||||
MODULE_AUTHOR("Harsha Priya <[email protected]>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:sn95031");
|
||||
|
|
@ -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
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@
|
|||
/* Define how often to check (and clear) the fault status register (in ms) */
|
||||
#define TAS5720_FAULT_CHECK_INTERVAL 200
|
||||
|
||||
enum tas572x_type {
|
||||
TAS5720,
|
||||
TAS5722,
|
||||
};
|
||||
|
||||
static const char * const tas5720_supply_names[] = {
|
||||
"dvdd", /* Digital power supply. Connect to 3.3-V supply. */
|
||||
"pvdd", /* Class-D amp and analog power supply (connected). */
|
||||
|
|
@ -47,6 +52,7 @@ struct tas5720_data {
|
|||
struct snd_soc_codec *codec;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *tas5720_client;
|
||||
enum tas572x_type devtype;
|
||||
struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES];
|
||||
struct delayed_work fault_check_work;
|
||||
unsigned int last_fault;
|
||||
|
|
@ -264,7 +270,7 @@ out:
|
|||
static int tas5720_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int device_id;
|
||||
unsigned int device_id, expected_device_id;
|
||||
int ret;
|
||||
|
||||
tas5720->codec = codec;
|
||||
|
|
@ -276,6 +282,11 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a liberal approach to checking the device ID to allow the
|
||||
* driver to be used even if the device ID does not match, however
|
||||
* issue a warning if there is a mismatch.
|
||||
*/
|
||||
ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to read device ID register: %d\n",
|
||||
|
|
@ -283,13 +294,22 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
|
|||
goto probe_fail;
|
||||
}
|
||||
|
||||
if (device_id != TAS5720_DEVICE_ID) {
|
||||
dev_err(codec->dev, "wrong device ID. expected: %u read: %u\n",
|
||||
TAS5720_DEVICE_ID, device_id);
|
||||
ret = -ENODEV;
|
||||
goto probe_fail;
|
||||
switch (tas5720->devtype) {
|
||||
case TAS5720:
|
||||
expected_device_id = TAS5720_DEVICE_ID;
|
||||
break;
|
||||
case TAS5722:
|
||||
expected_device_id = TAS5722_DEVICE_ID;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unexpected private driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_id != expected_device_id)
|
||||
dev_warn(codec->dev, "wrong device ID. expected: %u read: %u\n",
|
||||
expected_device_id, device_id);
|
||||
|
||||
/* Set device to mute */
|
||||
ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG,
|
||||
TAS5720_MUTE, TAS5720_MUTE);
|
||||
|
|
@ -446,6 +466,15 @@ static const struct regmap_config tas5720_regmap_config = {
|
|||
.volatile_reg = tas5720_is_volatile_reg,
|
||||
};
|
||||
|
||||
static const struct regmap_config tas5722_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = TAS5722_MAX_REG,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.volatile_reg = tas5720_is_volatile_reg,
|
||||
};
|
||||
|
||||
/*
|
||||
* DAC analog gain. There are four discrete values to select from, ranging
|
||||
* from 19.2 dB to 26.3dB.
|
||||
|
|
@ -544,6 +573,7 @@ static int tas5720_probe(struct i2c_client *client,
|
|||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct tas5720_data *data;
|
||||
const struct regmap_config *regmap_config;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
|
|
@ -552,7 +582,20 @@ static int tas5720_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
data->tas5720_client = client;
|
||||
data->regmap = devm_regmap_init_i2c(client, &tas5720_regmap_config);
|
||||
data->devtype = id->driver_data;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case TAS5720:
|
||||
regmap_config = &tas5720_regmap_config;
|
||||
break;
|
||||
case TAS5722:
|
||||
regmap_config = &tas5722_regmap_config;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unexpected private driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
data->regmap = devm_regmap_init_i2c(client, regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
ret = PTR_ERR(data->regmap);
|
||||
dev_err(dev, "failed to allocate register map: %d\n", ret);
|
||||
|
|
@ -592,7 +635,8 @@ static int tas5720_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id tas5720_id[] = {
|
||||
{ "tas5720", 0 },
|
||||
{ "tas5720", TAS5720 },
|
||||
{ "tas5722", TAS5722 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tas5720_id);
|
||||
|
|
@ -600,6 +644,7 @@ MODULE_DEVICE_TABLE(i2c, tas5720_id);
|
|||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id tas5720_of_match[] = {
|
||||
{ .compatible = "ti,tas5720", },
|
||||
{ .compatible = "ti,tas5722", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tas5720_of_match);
|
||||
|
|
|
|||
|
|
@ -30,8 +30,14 @@
|
|||
#define TAS5720_DIGITAL_CLIP1_REG 0x11
|
||||
#define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG
|
||||
|
||||
/* Additional TAS5722-specific Registers */
|
||||
#define TAS5722_DIGITAL_CTRL2_REG 0x13
|
||||
#define TAS5722_ANALOG_CTRL2_REG 0x14
|
||||
#define TAS5722_MAX_REG TAS5722_ANALOG_CTRL2_REG
|
||||
|
||||
/* TAS5720_DEVICE_ID_REG */
|
||||
#define TAS5720_DEVICE_ID 0x01
|
||||
#define TAS5722_DEVICE_ID 0x12
|
||||
|
||||
/* TAS5720_POWER_CTRL_REG */
|
||||
#define TAS5720_DIG_CLIP_MASK GENMASK(7, 2)
|
||||
|
|
@ -51,6 +57,7 @@
|
|||
#define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0)
|
||||
|
||||
/* TAS5720_DIGITAL_CTRL2_REG */
|
||||
#define TAS5722_VOL_RAMP_RATE BIT(6)
|
||||
#define TAS5720_MUTE BIT(4)
|
||||
#define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0)
|
||||
|
||||
|
|
@ -87,4 +94,28 @@
|
|||
#define TAS5720_CLIP1_MASK GENMASK(7, 2)
|
||||
#define TAS5720_CLIP1_SHIFT (0x2)
|
||||
|
||||
/* TAS5722_DIGITAL_CTRL2_REG */
|
||||
#define TAS5722_HPF_3_7HZ (0x0 << 5)
|
||||
#define TAS5722_HPF_7_4HZ (0x1 << 5)
|
||||
#define TAS5722_HPF_14_9HZ (0x2 << 5)
|
||||
#define TAS5722_HPF_29_7HZ (0x3 << 5)
|
||||
#define TAS5722_HPF_59_4HZ (0x4 << 5)
|
||||
#define TAS5722_HPF_118_4HZ (0x5 << 5)
|
||||
#define TAS5722_HPF_235_0HZ (0x6 << 5)
|
||||
#define TAS5722_HPF_463_2HZ (0x7 << 5)
|
||||
#define TAS5722_HPF_MASK GENMASK(7, 5)
|
||||
#define TAS5722_AUTO_SLEEP_OFF (0x0 << 3)
|
||||
#define TAS5722_AUTO_SLEEP_1024LR (0x1 << 3)
|
||||
#define TAS5722_AUTO_SLEEP_65536LR (0x2 << 3)
|
||||
#define TAS5722_AUTO_SLEEP_262144LR (0x3 << 3)
|
||||
#define TAS5722_AUTO_SLEEP_MASK GENMASK(4, 3)
|
||||
#define TAS5722_TDM_SLOT_16B BIT(2)
|
||||
#define TAS5722_MCLK_PIN_CFG BIT(1)
|
||||
#define TAS5722_VOL_CONTROL_LSB BIT(0)
|
||||
|
||||
/* TAS5722_ANALOG_CTRL2_REG */
|
||||
#define TAS5722_FAULTZ_PU BIT(3)
|
||||
#define TAS5722_VREG_LVL BIT(2)
|
||||
#define TAS5722_PWR_TUNE BIT(0)
|
||||
|
||||
#endif /* __TAS5720_H__ */
|
||||
|
|
|
|||
707
sound/soc/codecs/tas6424.c
Normal file
707
sound/soc/codecs/tas6424.c
Normal file
|
|
@ -0,0 +1,707 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier
|
||||
*
|
||||
* Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Author: Andreas Dannenberg <dannenberg@ti.com>
|
||||
* Andrew F. Davis <afd@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "tas6424.h"
|
||||
|
||||
/* Define how often to check (and clear) the fault status register (in ms) */
|
||||
#define TAS6424_FAULT_CHECK_INTERVAL 200
|
||||
|
||||
static const char * const tas6424_supply_names[] = {
|
||||
"dvdd", /* Digital power supply. Connect to 3.3-V supply. */
|
||||
"vbat", /* Supply used for higher voltage analog circuits. */
|
||||
"pvdd", /* Class-D amp output FETs supply. */
|
||||
};
|
||||
#define TAS6424_NUM_SUPPLIES ARRAY_SIZE(tas6424_supply_names)
|
||||
|
||||
struct tas6424_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES];
|
||||
struct delayed_work fault_check_work;
|
||||
unsigned int last_fault1;
|
||||
unsigned int last_fault2;
|
||||
unsigned int last_warn;
|
||||
};
|
||||
|
||||
/*
|
||||
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
|
||||
* setting the gain below -100 dB (register value <0x7) is effectively a MUTE
|
||||
* as per device datasheet.
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
|
||||
|
||||
static const struct snd_kcontrol_new tas6424_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("Speaker Driver CH1 Playback Volume",
|
||||
TAS6424_CH1_VOL_CTRL, 0, 0xff, 0, dac_tlv),
|
||||
SOC_SINGLE_TLV("Speaker Driver CH2 Playback Volume",
|
||||
TAS6424_CH2_VOL_CTRL, 0, 0xff, 0, dac_tlv),
|
||||
SOC_SINGLE_TLV("Speaker Driver CH3 Playback Volume",
|
||||
TAS6424_CH3_VOL_CTRL, 0, 0xff, 0, dac_tlv),
|
||||
SOC_SINGLE_TLV("Speaker Driver CH4 Playback Volume",
|
||||
TAS6424_CH4_VOL_CTRL, 0, 0xff, 0, dac_tlv),
|
||||
};
|
||||
|
||||
static int tas6424_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 tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(codec->dev, "%s() event=0x%0x\n", __func__, event);
|
||||
|
||||
if (event & SND_SOC_DAPM_POST_PMU) {
|
||||
/* Observe codec shutdown-to-active time */
|
||||
msleep(12);
|
||||
|
||||
/* Turn on TAS6424 periodic fault checking/handling */
|
||||
tas6424->last_fault1 = 0;
|
||||
tas6424->last_fault2 = 0;
|
||||
tas6424->last_warn = 0;
|
||||
schedule_delayed_work(&tas6424->fault_check_work,
|
||||
msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL));
|
||||
} else if (event & SND_SOC_DAPM_PRE_PMD) {
|
||||
/* Disable TAS6424 periodic fault checking/handling */
|
||||
cancel_delayed_work_sync(&tas6424->fault_check_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget tas6424_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas6424_dac_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_OUTPUT("OUT")
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route tas6424_audio_map[] = {
|
||||
{ "DAC", NULL, "DAC IN" },
|
||||
{ "OUT", NULL, "DAC" },
|
||||
};
|
||||
|
||||
static int tas6424_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;
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int width = params_width(params);
|
||||
u8 sap_ctrl = 0;
|
||||
|
||||
dev_dbg(codec->dev, "%s() rate=%u width=%u\n", __func__, rate, width);
|
||||
|
||||
switch (rate) {
|
||||
case 44100:
|
||||
sap_ctrl |= TAS6424_SAP_RATE_44100;
|
||||
break;
|
||||
case 48000:
|
||||
sap_ctrl |= TAS6424_SAP_RATE_48000;
|
||||
break;
|
||||
case 96000:
|
||||
sap_ctrl |= TAS6424_SAP_RATE_96000;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported sample rate: %u\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (width) {
|
||||
case 16:
|
||||
sap_ctrl |= TAS6424_SAP_TDM_SLOT_SZ_16;
|
||||
break;
|
||||
case 24:
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported sample width: %u\n", width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, TAS6424_SAP_CTRL,
|
||||
TAS6424_SAP_RATE_MASK |
|
||||
TAS6424_SAP_TDM_SLOT_SZ_16,
|
||||
sap_ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 serial_format = 0;
|
||||
|
||||
dev_dbg(codec->dev, "%s() fmt=0x%0x\n", __func__, fmt);
|
||||
|
||||
/* clock masters */
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI master/slave interface\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* signal polarity */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
serial_format |= TAS6424_SAP_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
serial_format |= TAS6424_SAP_DSP;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
/*
|
||||
* We can use the fact that the TAS6424 does not care about the
|
||||
* LRCLK duty cycle during TDM to receive DSP_B formatted data
|
||||
* in LEFTJ mode (no delaying of the 1st data bit).
|
||||
*/
|
||||
serial_format |= TAS6424_SAP_LEFTJ;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
serial_format |= TAS6424_SAP_LEFTJ;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI interface format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, TAS6424_SAP_CTRL,
|
||||
TAS6424_SAP_FMT_MASK, serial_format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_set_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;
|
||||
unsigned int first_slot, last_slot;
|
||||
bool sap_tdm_slot_last;
|
||||
|
||||
dev_dbg(codec->dev, "%s() tx_mask=%d rx_mask=%d\n", __func__,
|
||||
tx_mask, rx_mask);
|
||||
|
||||
if (!tx_mask || !rx_mask)
|
||||
return 0; /* nothing needed to disable TDM mode */
|
||||
|
||||
/*
|
||||
* Determine the first slot and last slot that is being requested so
|
||||
* we'll be able to more easily enforce certain constraints as the
|
||||
* TAS6424's TDM interface is not fully configurable.
|
||||
*/
|
||||
first_slot = __ffs(tx_mask);
|
||||
last_slot = __fls(rx_mask);
|
||||
|
||||
if (last_slot - first_slot != 4) {
|
||||
dev_err(codec->dev, "tdm mask must cover 4 contiguous slots\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (first_slot) {
|
||||
case 0:
|
||||
sap_tdm_slot_last = false;
|
||||
break;
|
||||
case 4:
|
||||
sap_tdm_slot_last = true;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "tdm mask must start at slot 0 or 4\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, TAS6424_SAP_CTRL, TAS6424_SAP_TDM_SLOT_LAST,
|
||||
sap_tdm_slot_last ? TAS6424_SAP_TDM_SLOT_LAST : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
unsigned int val;
|
||||
|
||||
dev_dbg(codec->dev, "%s() mute=%d\n", __func__, mute);
|
||||
|
||||
if (mute)
|
||||
val = TAS6424_ALL_STATE_MUTE;
|
||||
else
|
||||
val = TAS6424_ALL_STATE_PLAY;
|
||||
|
||||
snd_soc_write(codec, TAS6424_CH_STATE_CTRL, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_power_off(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_HIZ);
|
||||
|
||||
regcache_cache_only(tas6424->regmap, true);
|
||||
regcache_mark_dirty(tas6424->regmap);
|
||||
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
|
||||
tas6424->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to disable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_power_on(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
|
||||
tas6424->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(tas6424->regmap, false);
|
||||
|
||||
ret = regcache_sync(tas6424->regmap);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to sync regcache: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE);
|
||||
|
||||
/* any time we come out of HIZ, the output channels automatically run DC
|
||||
* load diagnostics, wait here until this completes
|
||||
*/
|
||||
msleep(230);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
dev_dbg(codec->dev, "%s() level=%d\n", __func__, level);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
|
||||
tas6424_power_on(codec);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
tas6424_power_off(codec);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tas6424 = {
|
||||
.set_bias_level = tas6424_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
|
||||
.component_driver = {
|
||||
.controls = tas6424_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(tas6424_snd_controls),
|
||||
.dapm_widgets = tas6424_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tas6424_dapm_widgets),
|
||||
.dapm_routes = tas6424_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(tas6424_audio_map),
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
|
||||
.hw_params = tas6424_hw_params,
|
||||
.set_fmt = tas6424_set_dai_fmt,
|
||||
.set_tdm_slot = tas6424_set_dai_tdm_slot,
|
||||
.digital_mute = tas6424_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver tas6424_dai[] = {
|
||||
{
|
||||
.name = "tas6424-amplifier",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 4,
|
||||
.rates = TAS6424_RATES,
|
||||
.formats = TAS6424_FORMATS,
|
||||
},
|
||||
.ops = &tas6424_speaker_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static void tas6424_fault_check_work(struct work_struct *work)
|
||||
{
|
||||
struct tas6424_data *tas6424 = container_of(work, struct tas6424_data,
|
||||
fault_check_work.work);
|
||||
struct device *dev = tas6424->dev;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read FAULT1 register: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore any clock faults as there is no clean way to check for them.
|
||||
* We would need to start checking for those faults *after* the SAIF
|
||||
* stream has been setup, and stop checking *before* the stream is
|
||||
* stopped to avoid any false-positives. However there are no
|
||||
* appropriate hooks to monitor these events.
|
||||
*/
|
||||
reg &= TAS6424_FAULT_PVDD_OV |
|
||||
TAS6424_FAULT_VBAT_OV |
|
||||
TAS6424_FAULT_PVDD_UV |
|
||||
TAS6424_FAULT_VBAT_UV;
|
||||
|
||||
if (reg)
|
||||
goto check_global_fault2_reg;
|
||||
|
||||
/*
|
||||
* Only flag errors once for a given occurrence. This is needed as
|
||||
* the TAS6424 will take time clearing the fault condition internally
|
||||
* during which we don't want to bombard the system with the same
|
||||
* error message over and over.
|
||||
*/
|
||||
if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV))
|
||||
dev_crit(dev, "experienced a PVDD overvoltage fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_VBAT_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_OV))
|
||||
dev_crit(dev, "experienced a VBAT overvoltage fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_PVDD_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_UV))
|
||||
dev_crit(dev, "experienced a PVDD undervoltage fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_VBAT_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_UV))
|
||||
dev_crit(dev, "experienced a VBAT undervoltage fault\n");
|
||||
|
||||
/* Store current fault1 value so we can detect any changes next time */
|
||||
tas6424->last_fault1 = reg;
|
||||
|
||||
check_global_fault2_reg:
|
||||
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read FAULT2 register: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg &= TAS6424_FAULT_OTSD |
|
||||
TAS6424_FAULT_OTSD_CH1 |
|
||||
TAS6424_FAULT_OTSD_CH2 |
|
||||
TAS6424_FAULT_OTSD_CH3 |
|
||||
TAS6424_FAULT_OTSD_CH4;
|
||||
|
||||
if (!reg)
|
||||
goto check_warn_reg;
|
||||
|
||||
if ((reg & TAS6424_FAULT_OTSD) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD))
|
||||
dev_crit(dev, "experienced a global overtemp shutdown\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OTSD_CH1) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH1))
|
||||
dev_crit(dev, "experienced an overtemp shutdown on CH1\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OTSD_CH2) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH2))
|
||||
dev_crit(dev, "experienced an overtemp shutdown on CH2\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OTSD_CH3) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH3))
|
||||
dev_crit(dev, "experienced an overtemp shutdown on CH3\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OTSD_CH4) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH4))
|
||||
dev_crit(dev, "experienced an overtemp shutdown on CH4\n");
|
||||
|
||||
/* Store current fault2 value so we can detect any changes next time */
|
||||
tas6424->last_fault2 = reg;
|
||||
|
||||
check_warn_reg:
|
||||
ret = regmap_read(tas6424->regmap, TAS6424_WARN, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read WARN register: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg &= TAS6424_WARN_VDD_UV |
|
||||
TAS6424_WARN_VDD_POR |
|
||||
TAS6424_WARN_VDD_OTW |
|
||||
TAS6424_WARN_VDD_OTW_CH1 |
|
||||
TAS6424_WARN_VDD_OTW_CH2 |
|
||||
TAS6424_WARN_VDD_OTW_CH3 |
|
||||
TAS6424_WARN_VDD_OTW_CH4;
|
||||
|
||||
if (!reg)
|
||||
goto out;
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_UV) && !(tas6424->last_warn & TAS6424_WARN_VDD_UV))
|
||||
dev_warn(dev, "experienced a VDD under voltage condition\n");
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_POR) && !(tas6424->last_warn & TAS6424_WARN_VDD_POR))
|
||||
dev_warn(dev, "experienced a VDD POR condition\n");
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_OTW) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW))
|
||||
dev_warn(dev, "experienced a global overtemp warning\n");
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_OTW_CH1) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH1))
|
||||
dev_warn(dev, "experienced an overtemp warning on CH1\n");
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_OTW_CH2) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH2))
|
||||
dev_warn(dev, "experienced an overtemp warning on CH2\n");
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_OTW_CH3) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH3))
|
||||
dev_warn(dev, "experienced an overtemp warning on CH3\n");
|
||||
|
||||
if ((reg & TAS6424_WARN_VDD_OTW_CH4) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH4))
|
||||
dev_warn(dev, "experienced an overtemp warning on CH4\n");
|
||||
|
||||
/* Store current warn value so we can detect any changes next time */
|
||||
tas6424->last_warn = reg;
|
||||
|
||||
/* Clear any faults by toggling the CLEAR_FAULT control bit */
|
||||
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
|
||||
TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret);
|
||||
|
||||
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
|
||||
TAS6424_CLEAR_FAULT, 0);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret);
|
||||
|
||||
out:
|
||||
/* Schedule the next fault check at the specified interval */
|
||||
schedule_delayed_work(&tas6424->fault_check_work,
|
||||
msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL));
|
||||
}
|
||||
|
||||
static const struct reg_default tas6424_reg_defaults[] = {
|
||||
{ TAS6424_MODE_CTRL, 0x00 },
|
||||
{ TAS6424_MISC_CTRL1, 0x32 },
|
||||
{ TAS6424_MISC_CTRL2, 0x62 },
|
||||
{ TAS6424_SAP_CTRL, 0x04 },
|
||||
{ TAS6424_CH_STATE_CTRL, 0x55 },
|
||||
{ TAS6424_CH1_VOL_CTRL, 0xcf },
|
||||
{ TAS6424_CH2_VOL_CTRL, 0xcf },
|
||||
{ TAS6424_CH3_VOL_CTRL, 0xcf },
|
||||
{ TAS6424_CH4_VOL_CTRL, 0xcf },
|
||||
{ TAS6424_DC_DIAG_CTRL1, 0x00 },
|
||||
{ TAS6424_DC_DIAG_CTRL2, 0x11 },
|
||||
{ TAS6424_DC_DIAG_CTRL3, 0x11 },
|
||||
{ TAS6424_PIN_CTRL, 0xff },
|
||||
{ TAS6424_AC_DIAG_CTRL1, 0x00 },
|
||||
{ TAS6424_MISC_CTRL3, 0x00 },
|
||||
{ TAS6424_CLIP_CTRL, 0x01 },
|
||||
{ TAS6424_CLIP_WINDOW, 0x14 },
|
||||
{ TAS6424_CLIP_WARN, 0x00 },
|
||||
{ TAS6424_CBC_STAT, 0x00 },
|
||||
{ TAS6424_MISC_CTRL4, 0x40 },
|
||||
};
|
||||
|
||||
static bool tas6424_is_writable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TAS6424_MODE_CTRL:
|
||||
case TAS6424_MISC_CTRL1:
|
||||
case TAS6424_MISC_CTRL2:
|
||||
case TAS6424_SAP_CTRL:
|
||||
case TAS6424_CH_STATE_CTRL:
|
||||
case TAS6424_CH1_VOL_CTRL:
|
||||
case TAS6424_CH2_VOL_CTRL:
|
||||
case TAS6424_CH3_VOL_CTRL:
|
||||
case TAS6424_CH4_VOL_CTRL:
|
||||
case TAS6424_DC_DIAG_CTRL1:
|
||||
case TAS6424_DC_DIAG_CTRL2:
|
||||
case TAS6424_DC_DIAG_CTRL3:
|
||||
case TAS6424_PIN_CTRL:
|
||||
case TAS6424_AC_DIAG_CTRL1:
|
||||
case TAS6424_MISC_CTRL3:
|
||||
case TAS6424_CLIP_CTRL:
|
||||
case TAS6424_CLIP_WINDOW:
|
||||
case TAS6424_CLIP_WARN:
|
||||
case TAS6424_CBC_STAT:
|
||||
case TAS6424_MISC_CTRL4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool tas6424_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TAS6424_DC_LOAD_DIAG_REP12:
|
||||
case TAS6424_DC_LOAD_DIAG_REP34:
|
||||
case TAS6424_DC_LOAD_DIAG_REPLO:
|
||||
case TAS6424_CHANNEL_STATE:
|
||||
case TAS6424_CHANNEL_FAULT:
|
||||
case TAS6424_GLOB_FAULT1:
|
||||
case TAS6424_GLOB_FAULT2:
|
||||
case TAS6424_WARN:
|
||||
case TAS6424_AC_LOAD_DIAG_REP1:
|
||||
case TAS6424_AC_LOAD_DIAG_REP2:
|
||||
case TAS6424_AC_LOAD_DIAG_REP3:
|
||||
case TAS6424_AC_LOAD_DIAG_REP4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config tas6424_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.writeable_reg = tas6424_is_writable_reg,
|
||||
.volatile_reg = tas6424_is_volatile_reg,
|
||||
|
||||
.max_register = TAS6424_MAX,
|
||||
.reg_defaults = tas6424_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tas6424_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id tas6424_of_ids[] = {
|
||||
{ .compatible = "ti,tas6424", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tas6424_of_ids);
|
||||
#endif
|
||||
|
||||
static int tas6424_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct tas6424_data *tas6424;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
tas6424 = devm_kzalloc(dev, sizeof(*tas6424), GFP_KERNEL);
|
||||
if (!tas6424)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(dev, tas6424);
|
||||
|
||||
tas6424->dev = dev;
|
||||
|
||||
tas6424->regmap = devm_regmap_init_i2c(client, &tas6424_regmap_config);
|
||||
if (IS_ERR(tas6424->regmap)) {
|
||||
ret = PTR_ERR(tas6424->regmap);
|
||||
dev_err(dev, "unable to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tas6424->supplies); i++)
|
||||
tas6424->supplies[i].supply = tas6424_supply_names[i];
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(tas6424->supplies),
|
||||
tas6424->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
|
||||
tas6424->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset device to establish well-defined startup state */
|
||||
ret = regmap_update_bits(tas6424->regmap, TAS6424_MODE_CTRL,
|
||||
TAS6424_RESET, TAS6424_RESET);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to reset device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work);
|
||||
|
||||
ret = snd_soc_register_codec(dev, &soc_codec_dev_tas6424,
|
||||
tas6424_dai, ARRAY_SIZE(tas6424_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to register codec: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas6424_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct tas6424_data *tas6424 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
snd_soc_unregister_codec(dev);
|
||||
|
||||
cancel_delayed_work_sync(&tas6424->fault_check_work);
|
||||
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
|
||||
tas6424->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to disable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tas6424_i2c_ids[] = {
|
||||
{ "tas6424", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tas6424_i2c_ids);
|
||||
|
||||
static struct i2c_driver tas6424_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tas6424",
|
||||
.of_match_table = of_match_ptr(tas6424_of_ids),
|
||||
},
|
||||
.probe = tas6424_i2c_probe,
|
||||
.remove = tas6424_i2c_remove,
|
||||
.id_table = tas6424_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(tas6424_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Andreas Dannenberg <[email protected]>");
|
||||
MODULE_AUTHOR("Andrew F. Davis <[email protected]>");
|
||||
MODULE_DESCRIPTION("TAS6424 Audio amplifier driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
144
sound/soc/codecs/tas6424.h
Normal file
144
sound/soc/codecs/tas6424.h
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier
|
||||
*
|
||||
* Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Author: Andreas Dannenberg <dannenberg@ti.com>
|
||||
* Andrew F. Davis <afd@ti.com>
|
||||
*/
|
||||
|
||||
#ifndef __TAS6424_H__
|
||||
#define __TAS6424_H__
|
||||
|
||||
#define TAS6424_RATES (SNDRV_PCM_RATE_44100 | \
|
||||
SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define TAS6424_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
/* Register Address Map */
|
||||
#define TAS6424_MODE_CTRL 0x00
|
||||
#define TAS6424_MISC_CTRL1 0x01
|
||||
#define TAS6424_MISC_CTRL2 0x02
|
||||
#define TAS6424_SAP_CTRL 0x03
|
||||
#define TAS6424_CH_STATE_CTRL 0x04
|
||||
#define TAS6424_CH1_VOL_CTRL 0x05
|
||||
#define TAS6424_CH2_VOL_CTRL 0x06
|
||||
#define TAS6424_CH3_VOL_CTRL 0x07
|
||||
#define TAS6424_CH4_VOL_CTRL 0x08
|
||||
#define TAS6424_DC_DIAG_CTRL1 0x09
|
||||
#define TAS6424_DC_DIAG_CTRL2 0x0a
|
||||
#define TAS6424_DC_DIAG_CTRL3 0x0b
|
||||
#define TAS6424_DC_LOAD_DIAG_REP12 0x0c
|
||||
#define TAS6424_DC_LOAD_DIAG_REP34 0x0d
|
||||
#define TAS6424_DC_LOAD_DIAG_REPLO 0x0e
|
||||
#define TAS6424_CHANNEL_STATE 0x0f
|
||||
#define TAS6424_CHANNEL_FAULT 0x10
|
||||
#define TAS6424_GLOB_FAULT1 0x11
|
||||
#define TAS6424_GLOB_FAULT2 0x12
|
||||
#define TAS6424_WARN 0x13
|
||||
#define TAS6424_PIN_CTRL 0x14
|
||||
#define TAS6424_AC_DIAG_CTRL1 0x15
|
||||
#define TAS6424_AC_DIAG_CTRL2 0x16
|
||||
#define TAS6424_AC_LOAD_DIAG_REP1 0x17
|
||||
#define TAS6424_AC_LOAD_DIAG_REP2 0x18
|
||||
#define TAS6424_AC_LOAD_DIAG_REP3 0x19
|
||||
#define TAS6424_AC_LOAD_DIAG_REP4 0x1a
|
||||
#define TAS6424_MISC_CTRL3 0x21
|
||||
#define TAS6424_CLIP_CTRL 0x22
|
||||
#define TAS6424_CLIP_WINDOW 0x23
|
||||
#define TAS6424_CLIP_WARN 0x24
|
||||
#define TAS6424_CBC_STAT 0x25
|
||||
#define TAS6424_MISC_CTRL4 0x26
|
||||
#define TAS6424_MAX TAS6424_MISC_CTRL4
|
||||
|
||||
/* TAS6424_MODE_CTRL_REG */
|
||||
#define TAS6424_RESET BIT(7)
|
||||
|
||||
/* TAS6424_SAP_CTRL_REG */
|
||||
#define TAS6424_SAP_RATE_MASK GENMASK(7, 6)
|
||||
#define TAS6424_SAP_RATE_44100 (0x00 << 6)
|
||||
#define TAS6424_SAP_RATE_48000 (0x01 << 6)
|
||||
#define TAS6424_SAP_RATE_96000 (0x02 << 6)
|
||||
#define TAS6424_SAP_TDM_SLOT_LAST BIT(5)
|
||||
#define TAS6424_SAP_TDM_SLOT_SZ_16 BIT(4)
|
||||
#define TAS6424_SAP_TDM_SLOT_SWAP BIT(3)
|
||||
#define TAS6424_SAP_FMT_MASK GENMASK(2, 0)
|
||||
#define TAS6424_SAP_RIGHTJ_24 (0x00 << 0)
|
||||
#define TAS6424_SAP_RIGHTJ_20 (0x01 << 0)
|
||||
#define TAS6424_SAP_RIGHTJ_18 (0x02 << 0)
|
||||
#define TAS6424_SAP_RIGHTJ_16 (0x03 << 0)
|
||||
#define TAS6424_SAP_I2S (0x04 << 0)
|
||||
#define TAS6424_SAP_LEFTJ (0x05 << 0)
|
||||
#define TAS6424_SAP_DSP (0x06 << 0)
|
||||
|
||||
/* TAS6424_CH_STATE_CTRL_REG */
|
||||
#define TAS6424_CH1_STATE_MASK GENMASK(7, 6)
|
||||
#define TAS6424_CH1_STATE_PLAY (0x00 << 6)
|
||||
#define TAS6424_CH1_STATE_HIZ (0x01 << 6)
|
||||
#define TAS6424_CH1_STATE_MUTE (0x02 << 6)
|
||||
#define TAS6424_CH1_STATE_DIAG (0x03 << 6)
|
||||
#define TAS6424_CH2_STATE_MASK GENMASK(5, 4)
|
||||
#define TAS6424_CH2_STATE_PLAY (0x00 << 4)
|
||||
#define TAS6424_CH2_STATE_HIZ (0x01 << 4)
|
||||
#define TAS6424_CH2_STATE_MUTE (0x02 << 4)
|
||||
#define TAS6424_CH2_STATE_DIAG (0x03 << 4)
|
||||
#define TAS6424_CH3_STATE_MASK GENMASK(3, 2)
|
||||
#define TAS6424_CH3_STATE_PLAY (0x00 << 2)
|
||||
#define TAS6424_CH3_STATE_HIZ (0x01 << 2)
|
||||
#define TAS6424_CH3_STATE_MUTE (0x02 << 2)
|
||||
#define TAS6424_CH3_STATE_DIAG (0x03 << 2)
|
||||
#define TAS6424_CH4_STATE_MASK GENMASK(1, 0)
|
||||
#define TAS6424_CH4_STATE_PLAY (0x00 << 0)
|
||||
#define TAS6424_CH4_STATE_HIZ (0x01 << 0)
|
||||
#define TAS6424_CH4_STATE_MUTE (0x02 << 0)
|
||||
#define TAS6424_CH4_STATE_DIAG (0x03 << 0)
|
||||
#define TAS6424_ALL_STATE_PLAY (TAS6424_CH1_STATE_PLAY | \
|
||||
TAS6424_CH2_STATE_PLAY | \
|
||||
TAS6424_CH3_STATE_PLAY | \
|
||||
TAS6424_CH4_STATE_PLAY)
|
||||
#define TAS6424_ALL_STATE_HIZ (TAS6424_CH1_STATE_HIZ | \
|
||||
TAS6424_CH2_STATE_HIZ | \
|
||||
TAS6424_CH3_STATE_HIZ | \
|
||||
TAS6424_CH4_STATE_HIZ)
|
||||
#define TAS6424_ALL_STATE_MUTE (TAS6424_CH1_STATE_MUTE | \
|
||||
TAS6424_CH2_STATE_MUTE | \
|
||||
TAS6424_CH3_STATE_MUTE | \
|
||||
TAS6424_CH4_STATE_MUTE)
|
||||
#define TAS6424_ALL_STATE_DIAG (TAS6424_CH1_STATE_DIAG | \
|
||||
TAS6424_CH2_STATE_DIAG | \
|
||||
TAS6424_CH3_STATE_DIAG | \
|
||||
TAS6424_CH4_STATE_DIAG)
|
||||
|
||||
/* TAS6424_GLOB_FAULT1_REG */
|
||||
#define TAS6424_FAULT_CLOCK BIT(4)
|
||||
#define TAS6424_FAULT_PVDD_OV BIT(3)
|
||||
#define TAS6424_FAULT_VBAT_OV BIT(2)
|
||||
#define TAS6424_FAULT_PVDD_UV BIT(1)
|
||||
#define TAS6424_FAULT_VBAT_UV BIT(0)
|
||||
|
||||
/* TAS6424_GLOB_FAULT2_REG */
|
||||
#define TAS6424_FAULT_OTSD BIT(4)
|
||||
#define TAS6424_FAULT_OTSD_CH1 BIT(3)
|
||||
#define TAS6424_FAULT_OTSD_CH2 BIT(2)
|
||||
#define TAS6424_FAULT_OTSD_CH3 BIT(1)
|
||||
#define TAS6424_FAULT_OTSD_CH4 BIT(0)
|
||||
|
||||
/* TAS6424_WARN_REG */
|
||||
#define TAS6424_WARN_VDD_UV BIT(6)
|
||||
#define TAS6424_WARN_VDD_POR BIT(5)
|
||||
#define TAS6424_WARN_VDD_OTW BIT(4)
|
||||
#define TAS6424_WARN_VDD_OTW_CH1 BIT(3)
|
||||
#define TAS6424_WARN_VDD_OTW_CH2 BIT(2)
|
||||
#define TAS6424_WARN_VDD_OTW_CH3 BIT(1)
|
||||
#define TAS6424_WARN_VDD_OTW_CH4 BIT(0)
|
||||
|
||||
/* TAS6424_MISC_CTRL3_REG */
|
||||
#define TAS6424_CLEAR_FAULT BIT(7)
|
||||
#define TAS6424_PBTL_CH_SEL BIT(6)
|
||||
#define TAS6424_MASK_CBC_WARN BIT(5)
|
||||
#define TAS6424_MASK_VDD_UV BIT(4)
|
||||
#define TAS6424_OTSD_AUTO_RECOVERY BIT(3)
|
||||
|
||||
#endif /* __TAS6424_H__ */
|
||||
|
|
@ -316,6 +316,7 @@ static const struct of_device_id tfa9879_of_match[] = {
|
|||
{ .compatible = "nxp,tfa9879", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tfa9879_of_match);
|
||||
|
||||
static struct i2c_driver tfa9879_i2c_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ALSA SoC TLV320AIC31XX codec driver
|
||||
* ALSA SoC TLV320AIC31xx CODEC Driver
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments, Inc.
|
||||
*
|
||||
* Author: Jyri Sarha <jsarha@ti.com>
|
||||
* Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Jyri Sarha <jsarha@ti.com>
|
||||
*
|
||||
* Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* The TLV320AIC31xx series of audio codec is a low-power, highly integrated
|
||||
* high performance codec which provides a stereo DAC, a mono ADC,
|
||||
* The TLV320AIC31xx series of audio codecs are low-power, highly integrated
|
||||
* high performance codecs which provides a stereo DAC, a mono ADC,
|
||||
* and mono/stereo Class-D speaker driver.
|
||||
*/
|
||||
|
||||
|
|
@ -26,7 +18,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -144,8 +136,7 @@ static const struct regmap_config aic31xx_i2c_regmap = {
|
|||
.max_register = 12 * 128,
|
||||
};
|
||||
|
||||
#define AIC31XX_NUM_SUPPLIES 6
|
||||
static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
|
||||
static const char * const aic31xx_supply_names[] = {
|
||||
"HPVDD",
|
||||
"SPRVDD",
|
||||
"SPLVDD",
|
||||
|
|
@ -154,6 +145,8 @@ static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
|
|||
"DVDD",
|
||||
};
|
||||
|
||||
#define AIC31XX_NUM_SUPPLIES ARRAY_SIZE(aic31xx_supply_names)
|
||||
|
||||
struct aic31xx_disable_nb {
|
||||
struct notifier_block nb;
|
||||
struct aic31xx_priv *aic31xx;
|
||||
|
|
@ -164,6 +157,9 @@ struct aic31xx_priv {
|
|||
u8 i2c_regs_status;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
enum aic31xx_type codec_type;
|
||||
struct gpio_desc *gpio_reset;
|
||||
int micbias_vg;
|
||||
struct aic31xx_pdata pdata;
|
||||
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
|
||||
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
|
||||
|
|
@ -185,7 +181,7 @@ struct aic31xx_rate_divs {
|
|||
u8 madc;
|
||||
};
|
||||
|
||||
/* ADC dividers can be disabled by cofiguring them to 0 */
|
||||
/* ADC dividers can be disabled by configuring them to 0 */
|
||||
static const struct aic31xx_rate_divs aic31xx_divs[] = {
|
||||
/* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */
|
||||
/* 8k rate */
|
||||
|
|
@ -456,7 +452,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
|
|||
/* change mic bias voltage to user defined */
|
||||
snd_soc_update_bits(codec, AIC31XX_MICBIAS,
|
||||
AIC31XX_MICBIAS_MASK,
|
||||
aic31xx->pdata.micbias_vg <<
|
||||
aic31xx->micbias_vg <<
|
||||
AIC31XX_MICBIAS_SHIFT);
|
||||
dev_dbg(codec->dev, "%s: turned on\n", __func__);
|
||||
break;
|
||||
|
|
@ -679,14 +675,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
|
|||
int ret = 0;
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!(aic31xx->pdata.codec_type & DAC31XX_BIT))
|
||||
if (!(aic31xx->codec_type & DAC31XX_BIT))
|
||||
ret = snd_soc_add_codec_controls(
|
||||
codec, aic31xx_snd_controls,
|
||||
ARRAY_SIZE(aic31xx_snd_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
|
||||
if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT)
|
||||
ret = snd_soc_add_codec_controls(
|
||||
codec, aic311x_snd_controls,
|
||||
ARRAY_SIZE(aic311x_snd_controls));
|
||||
|
|
@ -704,7 +700,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
|
|||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
if (aic31xx->pdata.codec_type & DAC31XX_BIT) {
|
||||
if (aic31xx->codec_type & DAC31XX_BIT) {
|
||||
ret = snd_soc_dapm_new_controls(
|
||||
dapm, dac31xx_dapm_widgets,
|
||||
ARRAY_SIZE(dac31xx_dapm_widgets));
|
||||
|
|
@ -728,7 +724,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
|
||||
if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
|
||||
ret = snd_soc_dapm_new_controls(
|
||||
dapm, aic311x_dapm_widgets,
|
||||
ARRAY_SIZE(aic311x_dapm_widgets));
|
||||
|
|
@ -760,11 +756,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
|
|||
{
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
int bclk_score = snd_soc_params_to_frame_size(params);
|
||||
int mclk_p = aic31xx->sysclk / aic31xx->p_div;
|
||||
int mclk_p;
|
||||
int bclk_n = 0;
|
||||
int match = -1;
|
||||
int i;
|
||||
|
||||
if (!aic31xx->sysclk || !aic31xx->p_div) {
|
||||
dev_err(codec->dev, "Master clock not supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mclk_p = aic31xx->sysclk / aic31xx->p_div;
|
||||
|
||||
/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
|
||||
snd_soc_update_bits(codec, AIC31XX_CLKMUX,
|
||||
AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
|
||||
|
|
@ -840,11 +842,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
|
|||
|
||||
dev_dbg(codec->dev,
|
||||
"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
|
||||
aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
|
||||
aic31xx->p_div, aic31xx_divs[i].dosr,
|
||||
aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
|
||||
aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
|
||||
aic31xx_divs[i].madc, bclk_n);
|
||||
aic31xx_divs[i].pll_j,
|
||||
aic31xx_divs[i].pll_d,
|
||||
aic31xx->p_div,
|
||||
aic31xx_divs[i].dosr,
|
||||
aic31xx_divs[i].ndac,
|
||||
aic31xx_divs[i].mdac,
|
||||
aic31xx_divs[i].aosr,
|
||||
aic31xx_divs[i].nadc,
|
||||
aic31xx_divs[i].madc,
|
||||
bclk_n
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -919,8 +927,28 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
iface_reg1 |= AIC31XX_WCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
iface_reg1 |= AIC31XX_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
|
||||
dev_err(codec->dev, "Invalid DAI master/slave interface\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* signal polarity */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
iface_reg2 |= AIC31XX_BCLKINV_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -931,16 +959,12 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
case SND_SOC_DAIFMT_DSP_A:
|
||||
dsp_a_val = 0x1; /* fall through */
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
iface_reg2 |= AIC31XX_BCLKINV_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* NOTE: This CODEC samples on the falling edge of BCLK in
|
||||
* DSP mode, this is inverted compared to what most DAIs
|
||||
* expect, so we invert for this mode
|
||||
*/
|
||||
iface_reg2 ^= AIC31XX_BCLKINV_MASK;
|
||||
iface_reg1 |= (AIC31XX_DSP_MODE <<
|
||||
AIC31XX_IFACE1_DATATYPE_SHIFT);
|
||||
break;
|
||||
|
|
@ -981,8 +1005,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
|
||||
__func__, clk_id, freq, dir);
|
||||
|
||||
for (i = 1; freq/i > 20000000 && i < 8; i++)
|
||||
;
|
||||
for (i = 1; i < 8; i++)
|
||||
if (freq / i <= 20000000)
|
||||
break;
|
||||
if (freq/i > 20000000) {
|
||||
dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
|
||||
__func__, freq);
|
||||
|
|
@ -990,9 +1015,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
}
|
||||
aic31xx->p_div = i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic31xx_divs) &&
|
||||
aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++)
|
||||
;
|
||||
for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++)
|
||||
if (aic31xx_divs[i].mclk_p == freq / aic31xx->p_div)
|
||||
break;
|
||||
if (i == ARRAY_SIZE(aic31xx_divs)) {
|
||||
dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
|
||||
__func__, freq);
|
||||
|
|
@ -1004,6 +1029,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
clk_id << AIC31XX_PLL_CLKIN_SHIFT);
|
||||
|
||||
aic31xx->sysclk = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1019,8 +1045,8 @@ static int aic31xx_regulator_event(struct notifier_block *nb,
|
|||
* Put codec to reset and as at least one of the
|
||||
* supplies was disabled.
|
||||
*/
|
||||
if (gpio_is_valid(aic31xx->pdata.gpio_reset))
|
||||
gpio_set_value(aic31xx->pdata.gpio_reset, 0);
|
||||
if (aic31xx->gpio_reset)
|
||||
gpiod_set_value(aic31xx->gpio_reset, 1);
|
||||
|
||||
regcache_mark_dirty(aic31xx->regmap);
|
||||
dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
|
||||
|
|
@ -1029,6 +1055,22 @@ static int aic31xx_regulator_event(struct notifier_block *nb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int aic31xx_reset(struct aic31xx_priv *aic31xx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (aic31xx->gpio_reset) {
|
||||
gpiod_set_value(aic31xx->gpio_reset, 1);
|
||||
ndelay(10); /* At least 10ns */
|
||||
gpiod_set_value(aic31xx->gpio_reset, 0);
|
||||
} else {
|
||||
ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1);
|
||||
}
|
||||
mdelay(1); /* At least 1ms */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aic31xx_clk_on(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
|
|
@ -1065,20 +1107,22 @@ static void aic31xx_clk_off(struct snd_soc_codec *codec)
|
|||
static int aic31xx_power_on(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
|
||||
aic31xx->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
|
||||
gpio_set_value(aic31xx->pdata.gpio_reset, 1);
|
||||
udelay(100);
|
||||
}
|
||||
regcache_cache_only(aic31xx->regmap, false);
|
||||
|
||||
/* Reset device registers for a consistent power-on like state */
|
||||
ret = aic31xx_reset(aic31xx);
|
||||
if (ret < 0)
|
||||
dev_err(aic31xx->dev, "Could not reset device: %d\n", ret);
|
||||
|
||||
ret = regcache_sync(aic31xx->regmap);
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to restore cache: %d\n", ret);
|
||||
regcache_cache_only(aic31xx->regmap, true);
|
||||
|
|
@ -1086,19 +1130,17 @@ static int aic31xx_power_on(struct snd_soc_codec *codec)
|
|||
aic31xx->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aic31xx_power_off(struct snd_soc_codec *codec)
|
||||
static void aic31xx_power_off(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
regcache_cache_only(aic31xx->regmap, true);
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
|
||||
aic31xx->supplies);
|
||||
|
||||
return ret;
|
||||
regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
|
||||
aic31xx->supplies);
|
||||
}
|
||||
|
||||
static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
|
||||
|
|
@ -1137,14 +1179,11 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
|
|||
|
||||
static int aic31xx_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret = 0;
|
||||
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
dev_dbg(aic31xx->dev, "## %s\n", __func__);
|
||||
|
||||
aic31xx = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
aic31xx->codec = codec;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
|
||||
|
|
@ -1169,8 +1208,10 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
|
||||
ret = aic31xx_add_widgets(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aic31xx_codec_remove(struct snd_soc_codec *codec)
|
||||
|
|
@ -1258,89 +1299,31 @@ static const struct of_device_id tlv320aic31xx_of_match[] = {
|
|||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
|
||||
|
||||
static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
|
||||
{
|
||||
struct device_node *np = aic31xx->dev->of_node;
|
||||
unsigned int value = MICBIAS_2_0V;
|
||||
int ret;
|
||||
|
||||
of_property_read_u32(np, "ai31xx-micbias-vg", &value);
|
||||
switch (value) {
|
||||
case MICBIAS_2_0V:
|
||||
case MICBIAS_2_5V:
|
||||
case MICBIAS_AVDDV:
|
||||
aic31xx->pdata.micbias_vg = value;
|
||||
break;
|
||||
default:
|
||||
dev_err(aic31xx->dev,
|
||||
"Bad ai31xx-micbias-vg value %d DT\n",
|
||||
value);
|
||||
aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
|
||||
}
|
||||
|
||||
ret = of_get_named_gpio(np, "gpio-reset", 0);
|
||||
if (ret > 0)
|
||||
aic31xx->pdata.gpio_reset = ret;
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int aic31xx_device_init(struct aic31xx_priv *aic31xx)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
dev_set_drvdata(aic31xx->dev, aic31xx);
|
||||
|
||||
if (dev_get_platdata(aic31xx->dev))
|
||||
memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
|
||||
sizeof(aic31xx->pdata));
|
||||
else if (aic31xx->dev->of_node)
|
||||
aic31xx_pdata_from_of(aic31xx);
|
||||
|
||||
if (aic31xx->pdata.gpio_reset) {
|
||||
ret = devm_gpio_request_one(aic31xx->dev,
|
||||
aic31xx->pdata.gpio_reset,
|
||||
GPIOF_OUT_INIT_HIGH,
|
||||
"aic31xx-reset-pin");
|
||||
if (ret < 0) {
|
||||
dev_err(aic31xx->dev, "not able to acquire gpio\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
|
||||
aic31xx->supplies[i].supply = aic31xx_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(aic31xx->dev,
|
||||
ARRAY_SIZE(aic31xx->supplies),
|
||||
aic31xx->supplies);
|
||||
if (ret != 0)
|
||||
dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id aic31xx_acpi_match[] = {
|
||||
{ "10TI3100", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
|
||||
#endif
|
||||
|
||||
static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx;
|
||||
int ret;
|
||||
const struct regmap_config *regmap_config;
|
||||
unsigned int micbias_value = MICBIAS_2_0V;
|
||||
int i, ret;
|
||||
|
||||
dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
|
||||
id->name, (int) id->driver_data);
|
||||
|
||||
regmap_config = &aic31xx_i2c_regmap;
|
||||
id->name, (int)id->driver_data);
|
||||
|
||||
aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
|
||||
if (aic31xx == NULL)
|
||||
if (!aic31xx)
|
||||
return -ENOMEM;
|
||||
|
||||
aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
|
||||
aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap);
|
||||
if (IS_ERR(aic31xx->regmap)) {
|
||||
ret = PTR_ERR(aic31xx->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
|
|
@ -1349,13 +1332,49 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
|||
}
|
||||
aic31xx->dev = &i2c->dev;
|
||||
|
||||
aic31xx->pdata.codec_type = id->driver_data;
|
||||
aic31xx->codec_type = id->driver_data;
|
||||
|
||||
ret = aic31xx_device_init(aic31xx);
|
||||
if (ret)
|
||||
dev_set_drvdata(aic31xx->dev, aic31xx);
|
||||
|
||||
fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg",
|
||||
&micbias_value);
|
||||
switch (micbias_value) {
|
||||
case MICBIAS_2_0V:
|
||||
case MICBIAS_2_5V:
|
||||
case MICBIAS_AVDDV:
|
||||
aic31xx->micbias_vg = micbias_value;
|
||||
break;
|
||||
default:
|
||||
dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d\n",
|
||||
micbias_value);
|
||||
aic31xx->micbias_vg = MICBIAS_2_0V;
|
||||
}
|
||||
|
||||
if (dev_get_platdata(aic31xx->dev)) {
|
||||
memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata));
|
||||
aic31xx->codec_type = aic31xx->pdata.codec_type;
|
||||
aic31xx->micbias_vg = aic31xx->pdata.micbias_vg;
|
||||
}
|
||||
|
||||
aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(aic31xx->gpio_reset)) {
|
||||
dev_err(aic31xx->dev, "not able to acquire gpio\n");
|
||||
return PTR_ERR(aic31xx->gpio_reset);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
|
||||
aic31xx->supplies[i].supply = aic31xx_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(aic31xx->dev,
|
||||
ARRAY_SIZE(aic31xx->supplies),
|
||||
aic31xx->supplies);
|
||||
if (ret) {
|
||||
dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (aic31xx->pdata.codec_type & DAC31XX_BIT)
|
||||
if (aic31xx->codec_type & DAC31XX_BIT)
|
||||
return snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_driver_aic31xx,
|
||||
dac31xx_dai_driver,
|
||||
|
|
@ -1386,14 +1405,6 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id aic31xx_acpi_match[] = {
|
||||
{ "10TI3100", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver aic31xx_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320aic31xx-codec",
|
||||
|
|
@ -1404,9 +1415,8 @@ static struct i2c_driver aic31xx_i2c_driver = {
|
|||
.remove = aic31xx_i2c_remove,
|
||||
.id_table = aic31xx_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(aic31xx_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver");
|
||||
MODULE_AUTHOR("Jyri Sarha");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jyri Sarha <[email protected]>");
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC31xx CODEC Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -1,36 +1,30 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ALSA SoC TLV320AIC31XX codec driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments, Inc.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* ALSA SoC TLV320AIC31xx CODEC Driver Definitions
|
||||
*
|
||||
* Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*/
|
||||
|
||||
#ifndef _TLV320AIC31XX_H
|
||||
#define _TLV320AIC31XX_H
|
||||
|
||||
#define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000
|
||||
|
||||
#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
|
||||
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \
|
||||
| SNDRV_PCM_FMTBIT_S32_LE)
|
||||
#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
|
||||
#define AIC31XX_STEREO_CLASS_D_BIT 0x1
|
||||
#define AIC31XX_MINIDSP_BIT 0x2
|
||||
#define DAC31XX_BIT 0x4
|
||||
#define AIC31XX_STEREO_CLASS_D_BIT BIT(1)
|
||||
#define AIC31XX_MINIDSP_BIT BIT(2)
|
||||
#define DAC31XX_BIT BIT(3)
|
||||
|
||||
enum aic31xx_type {
|
||||
AIC3100 = 0,
|
||||
AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
|
||||
AIC3120 = AIC31XX_MINIDSP_BIT,
|
||||
AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
|
||||
AIC3111 = AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT,
|
||||
DAC3100 = DAC31XX_BIT,
|
||||
DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,
|
||||
};
|
||||
|
|
@ -43,222 +37,167 @@ struct aic31xx_pdata {
|
|||
|
||||
#define AIC31XX_REG(page, reg) ((page * 128) + reg)
|
||||
|
||||
/* Page Control Register */
|
||||
#define AIC31XX_PAGECTL AIC31XX_REG(0, 0)
|
||||
#define AIC31XX_PAGECTL AIC31XX_REG(0, 0) /* Page Control Register */
|
||||
|
||||
/* Page 0 Registers */
|
||||
/* Software reset register */
|
||||
#define AIC31XX_RESET AIC31XX_REG(0, 1)
|
||||
/* OT FLAG register */
|
||||
#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3)
|
||||
/* Clock clock Gen muxing, Multiplexers*/
|
||||
#define AIC31XX_CLKMUX AIC31XX_REG(0, 4)
|
||||
/* PLL P and R-VAL register */
|
||||
#define AIC31XX_PLLPR AIC31XX_REG(0, 5)
|
||||
/* PLL J-VAL register */
|
||||
#define AIC31XX_PLLJ AIC31XX_REG(0, 6)
|
||||
/* PLL D-VAL MSB register */
|
||||
#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7)
|
||||
/* PLL D-VAL LSB register */
|
||||
#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8)
|
||||
/* DAC NDAC_VAL register*/
|
||||
#define AIC31XX_NDAC AIC31XX_REG(0, 11)
|
||||
/* DAC MDAC_VAL register */
|
||||
#define AIC31XX_MDAC AIC31XX_REG(0, 12)
|
||||
/* DAC OSR setting register 1, MSB value */
|
||||
#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13)
|
||||
/* DAC OSR setting register 2, LSB value */
|
||||
#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14)
|
||||
#define AIC31XX_RESET AIC31XX_REG(0, 1) /* Software reset register */
|
||||
#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) /* OT FLAG register */
|
||||
#define AIC31XX_CLKMUX AIC31XX_REG(0, 4) /* Clock clock Gen muxing, Multiplexers*/
|
||||
#define AIC31XX_PLLPR AIC31XX_REG(0, 5) /* PLL P and R-VAL register */
|
||||
#define AIC31XX_PLLJ AIC31XX_REG(0, 6) /* PLL J-VAL register */
|
||||
#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7) /* PLL D-VAL MSB register */
|
||||
#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8) /* PLL D-VAL LSB register */
|
||||
#define AIC31XX_NDAC AIC31XX_REG(0, 11) /* DAC NDAC_VAL register*/
|
||||
#define AIC31XX_MDAC AIC31XX_REG(0, 12) /* DAC MDAC_VAL register */
|
||||
#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13) /* DAC OSR setting register 1, MSB value */
|
||||
#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14) /* DAC OSR setting register 2, LSB value */
|
||||
#define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16)
|
||||
/* Clock setting register 8, PLL */
|
||||
#define AIC31XX_NADC AIC31XX_REG(0, 18)
|
||||
/* Clock setting register 9, PLL */
|
||||
#define AIC31XX_MADC AIC31XX_REG(0, 19)
|
||||
/* ADC Oversampling (AOSR) Register */
|
||||
#define AIC31XX_AOSR AIC31XX_REG(0, 20)
|
||||
/* Clock setting register 9, Multiplexers */
|
||||
#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25)
|
||||
/* Clock setting register 10, CLOCKOUT M divider value */
|
||||
#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26)
|
||||
/* Audio Interface Setting Register 1 */
|
||||
#define AIC31XX_IFACE1 AIC31XX_REG(0, 27)
|
||||
/* Audio Data Slot Offset Programming */
|
||||
#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28)
|
||||
/* Audio Interface Setting Register 2 */
|
||||
#define AIC31XX_IFACE2 AIC31XX_REG(0, 29)
|
||||
/* Clock setting register 11, BCLK N Divider */
|
||||
#define AIC31XX_BCLKN AIC31XX_REG(0, 30)
|
||||
/* Audio Interface Setting Register 3, Secondary Audio Interface */
|
||||
#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31)
|
||||
/* Audio Interface Setting Register 4 */
|
||||
#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32)
|
||||
/* Audio Interface Setting Register 5 */
|
||||
#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33)
|
||||
/* I2C Bus Condition */
|
||||
#define AIC31XX_I2C AIC31XX_REG(0, 34)
|
||||
/* ADC FLAG */
|
||||
#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36)
|
||||
/* DAC Flag Registers */
|
||||
#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37)
|
||||
#define AIC31XX_NADC AIC31XX_REG(0, 18) /* Clock setting register 8, PLL */
|
||||
#define AIC31XX_MADC AIC31XX_REG(0, 19) /* Clock setting register 9, PLL */
|
||||
#define AIC31XX_AOSR AIC31XX_REG(0, 20) /* ADC Oversampling (AOSR) Register */
|
||||
#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) /* Clock setting register 9, Multiplexers */
|
||||
#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) /* Clock setting register 10, CLOCKOUT M divider value */
|
||||
#define AIC31XX_IFACE1 AIC31XX_REG(0, 27) /* Audio Interface Setting Register 1 */
|
||||
#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) /* Audio Data Slot Offset Programming */
|
||||
#define AIC31XX_IFACE2 AIC31XX_REG(0, 29) /* Audio Interface Setting Register 2 */
|
||||
#define AIC31XX_BCLKN AIC31XX_REG(0, 30) /* Clock setting register 11, BCLK N Divider */
|
||||
#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31) /* Audio Interface Setting Register 3, Secondary Audio Interface */
|
||||
#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32) /* Audio Interface Setting Register 4 */
|
||||
#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33) /* Audio Interface Setting Register 5 */
|
||||
#define AIC31XX_I2C AIC31XX_REG(0, 34) /* I2C Bus Condition */
|
||||
#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36) /* ADC FLAG */
|
||||
#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37) /* DAC Flag Registers */
|
||||
#define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38)
|
||||
/* Sticky Interrupt flag (overflow) */
|
||||
#define AIC31XX_OFFLAG AIC31XX_REG(0, 39)
|
||||
/* Sticy DAC Interrupt flags */
|
||||
#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44)
|
||||
/* Sticy ADC Interrupt flags */
|
||||
#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45)
|
||||
/* DAC Interrupt flags 2 */
|
||||
#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46)
|
||||
/* ADC Interrupt flags 2 */
|
||||
#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47)
|
||||
/* INT1 interrupt control */
|
||||
#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48)
|
||||
/* INT2 interrupt control */
|
||||
#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49)
|
||||
/* GPIO1 control */
|
||||
#define AIC31XX_GPIO1 AIC31XX_REG(0, 50)
|
||||
|
||||
#define AIC31XX_OFFLAG AIC31XX_REG(0, 39) /* Sticky Interrupt flag (overflow) */
|
||||
#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) /* Sticy DAC Interrupt flags */
|
||||
#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) /* Sticy ADC Interrupt flags */
|
||||
#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) /* DAC Interrupt flags 2 */
|
||||
#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47) /* ADC Interrupt flags 2 */
|
||||
#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48) /* INT1 interrupt control */
|
||||
#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) /* INT2 interrupt control */
|
||||
#define AIC31XX_GPIO1 AIC31XX_REG(0, 51) /* GPIO1 control */
|
||||
#define AIC31XX_DACPRB AIC31XX_REG(0, 60)
|
||||
/* ADC Instruction Set Register */
|
||||
#define AIC31XX_ADCPRB AIC31XX_REG(0, 61)
|
||||
/* DAC channel setup register */
|
||||
#define AIC31XX_DACSETUP AIC31XX_REG(0, 63)
|
||||
/* DAC Mute and volume control register */
|
||||
#define AIC31XX_DACMUTE AIC31XX_REG(0, 64)
|
||||
/* Left DAC channel digital volume control */
|
||||
#define AIC31XX_LDACVOL AIC31XX_REG(0, 65)
|
||||
/* Right DAC channel digital volume control */
|
||||
#define AIC31XX_RDACVOL AIC31XX_REG(0, 66)
|
||||
/* Headset detection */
|
||||
#define AIC31XX_HSDETECT AIC31XX_REG(0, 67)
|
||||
/* ADC Digital Mic */
|
||||
#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81)
|
||||
/* ADC Digital Volume Control Fine Adjust */
|
||||
#define AIC31XX_ADCFGA AIC31XX_REG(0, 82)
|
||||
/* ADC Digital Volume Control Coarse Adjust */
|
||||
#define AIC31XX_ADCVOL AIC31XX_REG(0, 83)
|
||||
|
||||
#define AIC31XX_ADCPRB AIC31XX_REG(0, 61) /* ADC Instruction Set Register */
|
||||
#define AIC31XX_DACSETUP AIC31XX_REG(0, 63) /* DAC channel setup register */
|
||||
#define AIC31XX_DACMUTE AIC31XX_REG(0, 64) /* DAC Mute and volume control register */
|
||||
#define AIC31XX_LDACVOL AIC31XX_REG(0, 65) /* Left DAC channel digital volume control */
|
||||
#define AIC31XX_RDACVOL AIC31XX_REG(0, 66) /* Right DAC channel digital volume control */
|
||||
#define AIC31XX_HSDETECT AIC31XX_REG(0, 67) /* Headset detection */
|
||||
#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81) /* ADC Digital Mic */
|
||||
#define AIC31XX_ADCFGA AIC31XX_REG(0, 82) /* ADC Digital Volume Control Fine Adjust */
|
||||
#define AIC31XX_ADCVOL AIC31XX_REG(0, 83) /* ADC Digital Volume Control Coarse Adjust */
|
||||
|
||||
/* Page 1 Registers */
|
||||
/* Headphone drivers */
|
||||
#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31)
|
||||
/* Class-D Speakear Amplifier */
|
||||
#define AIC31XX_SPKAMP AIC31XX_REG(1, 32)
|
||||
/* HP Output Drivers POP Removal Settings */
|
||||
#define AIC31XX_HPPOP AIC31XX_REG(1, 33)
|
||||
/* Output Driver PGA Ramp-Down Period Control */
|
||||
#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34)
|
||||
/* DAC_L and DAC_R Output Mixer Routing */
|
||||
#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35)
|
||||
/* Left Analog Vol to HPL */
|
||||
#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36)
|
||||
/* Right Analog Vol to HPR */
|
||||
#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37)
|
||||
/* Left Analog Vol to SPL */
|
||||
#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38)
|
||||
/* Right Analog Vol to SPR */
|
||||
#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39)
|
||||
/* HPL Driver */
|
||||
#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40)
|
||||
/* HPR Driver */
|
||||
#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41)
|
||||
/* SPL Driver */
|
||||
#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42)
|
||||
/* SPR Driver */
|
||||
#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43)
|
||||
/* HP Driver Control */
|
||||
#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44)
|
||||
/* MIC Bias Control */
|
||||
#define AIC31XX_MICBIAS AIC31XX_REG(1, 46)
|
||||
/* MIC PGA*/
|
||||
#define AIC31XX_MICPGA AIC31XX_REG(1, 47)
|
||||
/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
|
||||
#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48)
|
||||
/* ADC Input Selection for M-Terminal */
|
||||
#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49)
|
||||
/* Input CM Settings */
|
||||
#define AIC31XX_MICPGACM AIC31XX_REG(1, 50)
|
||||
#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) /* Headphone drivers */
|
||||
#define AIC31XX_SPKAMP AIC31XX_REG(1, 32) /* Class-D Speakear Amplifier */
|
||||
#define AIC31XX_HPPOP AIC31XX_REG(1, 33) /* HP Output Drivers POP Removal Settings */
|
||||
#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) /* Output Driver PGA Ramp-Down Period Control */
|
||||
#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) /* DAC_L and DAC_R Output Mixer Routing */
|
||||
#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) /* Left Analog Vol to HPL */
|
||||
#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) /* Right Analog Vol to HPR */
|
||||
#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) /* Left Analog Vol to SPL */
|
||||
#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) /* Right Analog Vol to SPR */
|
||||
#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40) /* HPL Driver */
|
||||
#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41) /* HPR Driver */
|
||||
#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42) /* SPL Driver */
|
||||
#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43) /* SPR Driver */
|
||||
#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44) /* HP Driver Control */
|
||||
#define AIC31XX_MICBIAS AIC31XX_REG(1, 46) /* MIC Bias Control */
|
||||
#define AIC31XX_MICPGA AIC31XX_REG(1, 47) /* MIC PGA*/
|
||||
#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48) /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
|
||||
#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49) /* ADC Input Selection for M-Terminal */
|
||||
#define AIC31XX_MICPGACM AIC31XX_REG(1, 50) /* Input CM Settings */
|
||||
|
||||
/* Bits, masks and shifts */
|
||||
/* Bits, masks, and shifts */
|
||||
|
||||
/* AIC31XX_CLKMUX */
|
||||
#define AIC31XX_PLL_CLKIN_MASK 0x0c
|
||||
#define AIC31XX_PLL_CLKIN_SHIFT 2
|
||||
#define AIC31XX_PLL_CLKIN_MCLK 0
|
||||
#define AIC31XX_CODEC_CLKIN_MASK 0x03
|
||||
#define AIC31XX_CODEC_CLKIN_SHIFT 0
|
||||
#define AIC31XX_CODEC_CLKIN_PLL 3
|
||||
#define AIC31XX_CODEC_CLKIN_BCLK 1
|
||||
#define AIC31XX_PLL_CLKIN_MASK GENMASK(3, 2)
|
||||
#define AIC31XX_PLL_CLKIN_SHIFT (2)
|
||||
#define AIC31XX_PLL_CLKIN_MCLK 0x00
|
||||
#define AIC31XX_PLL_CLKIN_BCKL 0x01
|
||||
#define AIC31XX_PLL_CLKIN_GPIO1 0x02
|
||||
#define AIC31XX_PLL_CLKIN_DIN 0x03
|
||||
#define AIC31XX_CODEC_CLKIN_MASK GENMASK(1, 0)
|
||||
#define AIC31XX_CODEC_CLKIN_SHIFT (0)
|
||||
#define AIC31XX_CODEC_CLKIN_MCLK 0x00
|
||||
#define AIC31XX_CODEC_CLKIN_BCLK 0x01
|
||||
#define AIC31XX_CODEC_CLKIN_GPIO1 0x02
|
||||
#define AIC31XX_CODEC_CLKIN_PLL 0x03
|
||||
|
||||
/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC,
|
||||
AIC31XX_BCLKN */
|
||||
#define AIC31XX_PLL_MASK 0x7f
|
||||
#define AIC31XX_PM_MASK 0x80
|
||||
/* AIC31XX_PLLPR */
|
||||
/* AIC31XX_NDAC */
|
||||
/* AIC31XX_MDAC */
|
||||
/* AIC31XX_NADC */
|
||||
/* AIC31XX_MADC */
|
||||
/* AIC31XX_BCLKN */
|
||||
#define AIC31XX_PLL_MASK GENMASK(6, 0)
|
||||
#define AIC31XX_PM_MASK BIT(7)
|
||||
|
||||
/* AIC31XX_IFACE1 */
|
||||
#define AIC31XX_WORD_LEN_16BITS 0x00
|
||||
#define AIC31XX_WORD_LEN_20BITS 0x01
|
||||
#define AIC31XX_WORD_LEN_24BITS 0x02
|
||||
#define AIC31XX_WORD_LEN_32BITS 0x03
|
||||
#define AIC31XX_IFACE1_DATALEN_MASK 0x30
|
||||
#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
|
||||
#define AIC31XX_IFACE1_DATATYPE_MASK 0xC0
|
||||
#define AIC31XX_IFACE1_DATATYPE_MASK GENMASK(7, 6)
|
||||
#define AIC31XX_IFACE1_DATATYPE_SHIFT (6)
|
||||
#define AIC31XX_I2S_MODE 0x00
|
||||
#define AIC31XX_DSP_MODE 0x01
|
||||
#define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02
|
||||
#define AIC31XX_LEFT_JUSTIFIED_MODE 0x03
|
||||
#define AIC31XX_IFACE1_MASTER_MASK 0x0C
|
||||
#define AIC31XX_BCLK_MASTER 0x08
|
||||
#define AIC31XX_WCLK_MASTER 0x04
|
||||
#define AIC31XX_IFACE1_DATALEN_MASK GENMASK(5, 4)
|
||||
#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
|
||||
#define AIC31XX_WORD_LEN_16BITS 0x00
|
||||
#define AIC31XX_WORD_LEN_20BITS 0x01
|
||||
#define AIC31XX_WORD_LEN_24BITS 0x02
|
||||
#define AIC31XX_WORD_LEN_32BITS 0x03
|
||||
#define AIC31XX_IFACE1_MASTER_MASK GENMASK(3, 2)
|
||||
#define AIC31XX_BCLK_MASTER BIT(2)
|
||||
#define AIC31XX_WCLK_MASTER BIT(3)
|
||||
|
||||
/* AIC31XX_DATA_OFFSET */
|
||||
#define AIC31XX_DATA_OFFSET_MASK 0xFF
|
||||
#define AIC31XX_DATA_OFFSET_MASK GENMASK(7, 0)
|
||||
|
||||
/* AIC31XX_IFACE2 */
|
||||
#define AIC31XX_BCLKINV_MASK 0x08
|
||||
#define AIC31XX_BDIVCLK_MASK 0x03
|
||||
#define AIC31XX_BCLKINV_MASK BIT(3)
|
||||
#define AIC31XX_BDIVCLK_MASK GENMASK(1, 0)
|
||||
#define AIC31XX_DAC2BCLK 0x00
|
||||
#define AIC31XX_DACMOD2BCLK 0x01
|
||||
#define AIC31XX_ADC2BCLK 0x02
|
||||
#define AIC31XX_ADCMOD2BCLK 0x03
|
||||
|
||||
/* AIC31XX_ADCFLAG */
|
||||
#define AIC31XX_ADCPWRSTATUS_MASK 0x40
|
||||
#define AIC31XX_ADCPWRSTATUS_MASK BIT(6)
|
||||
|
||||
/* AIC31XX_DACFLAG1 */
|
||||
#define AIC31XX_LDACPWRSTATUS_MASK 0x80
|
||||
#define AIC31XX_RDACPWRSTATUS_MASK 0x08
|
||||
#define AIC31XX_HPLDRVPWRSTATUS_MASK 0x20
|
||||
#define AIC31XX_HPRDRVPWRSTATUS_MASK 0x02
|
||||
#define AIC31XX_SPLDRVPWRSTATUS_MASK 0x10
|
||||
#define AIC31XX_SPRDRVPWRSTATUS_MASK 0x01
|
||||
#define AIC31XX_LDACPWRSTATUS_MASK BIT(7)
|
||||
#define AIC31XX_HPLDRVPWRSTATUS_MASK BIT(5)
|
||||
#define AIC31XX_SPLDRVPWRSTATUS_MASK BIT(4)
|
||||
#define AIC31XX_RDACPWRSTATUS_MASK BIT(3)
|
||||
#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
|
||||
#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
|
||||
|
||||
/* AIC31XX_INTRDACFLAG */
|
||||
#define AIC31XX_HPSCDETECT_MASK 0x80
|
||||
#define AIC31XX_BUTTONPRESS_MASK 0x20
|
||||
#define AIC31XX_HSPLUG_MASK 0x10
|
||||
#define AIC31XX_LDRCTHRES_MASK 0x08
|
||||
#define AIC31XX_RDRCTHRES_MASK 0x04
|
||||
#define AIC31XX_DACSINT_MASK 0x02
|
||||
#define AIC31XX_DACAINT_MASK 0x01
|
||||
#define AIC31XX_HPLSCDETECT BIT(7)
|
||||
#define AIC31XX_HPRSCDETECT BIT(6)
|
||||
#define AIC31XX_BUTTONPRESS BIT(5)
|
||||
#define AIC31XX_HSPLUG BIT(4)
|
||||
#define AIC31XX_LDRCTHRES BIT(3)
|
||||
#define AIC31XX_RDRCTHRES BIT(2)
|
||||
#define AIC31XX_DACSINT BIT(1)
|
||||
#define AIC31XX_DACAINT BIT(0)
|
||||
|
||||
/* AIC31XX_INT1CTRL */
|
||||
#define AIC31XX_HSPLUGDET_MASK 0x80
|
||||
#define AIC31XX_BUTTONPRESSDET_MASK 0x40
|
||||
#define AIC31XX_DRCTHRES_MASK 0x20
|
||||
#define AIC31XX_AGCNOISE_MASK 0x10
|
||||
#define AIC31XX_OC_MASK 0x08
|
||||
#define AIC31XX_ENGINE_MASK 0x04
|
||||
#define AIC31XX_HSPLUGDET BIT(7)
|
||||
#define AIC31XX_BUTTONPRESSDET BIT(6)
|
||||
#define AIC31XX_DRCTHRES BIT(5)
|
||||
#define AIC31XX_AGCNOISE BIT(4)
|
||||
#define AIC31XX_SC BIT(3)
|
||||
#define AIC31XX_ENGINE BIT(2)
|
||||
|
||||
/* AIC31XX_DACSETUP */
|
||||
#define AIC31XX_SOFTSTEP_MASK 0x03
|
||||
#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
|
||||
|
||||
/* AIC31XX_DACMUTE */
|
||||
#define AIC31XX_DACMUTE_MASK 0x0C
|
||||
#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
|
||||
|
||||
/* AIC31XX_MICBIAS */
|
||||
#define AIC31XX_MICBIAS_MASK 0x03
|
||||
#define AIC31XX_MICBIAS_SHIFT 0
|
||||
#define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
|
||||
#define AIC31XX_MICBIAS_SHIFT 0
|
||||
|
||||
#endif /* _TLV320AIC31XX_H */
|
||||
|
|
|
|||
|
|
@ -281,34 +281,34 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
|
|||
|
||||
static const struct aic32x4_rate_divs aic32x4_divs[] = {
|
||||
/* 8k rate */
|
||||
{AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
|
||||
{AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
|
||||
{AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
|
||||
{12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
|
||||
{24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
|
||||
{25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
|
||||
/* 11.025k rate */
|
||||
{AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
|
||||
{AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
|
||||
{12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
|
||||
{24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
|
||||
/* 16k rate */
|
||||
{AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
|
||||
{AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
|
||||
{AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
|
||||
{12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
|
||||
{24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
|
||||
{25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
|
||||
/* 22.05k rate */
|
||||
{AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
|
||||
{AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
|
||||
{AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
|
||||
{12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
|
||||
{24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
|
||||
{25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
|
||||
/* 32k rate */
|
||||
{AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
|
||||
{AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
|
||||
{12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
|
||||
{24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
|
||||
/* 44.1k rate */
|
||||
{AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
|
||||
{AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
|
||||
{AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
|
||||
{12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
|
||||
{24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
|
||||
{25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
|
||||
/* 48k rate */
|
||||
{AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
|
||||
{AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
|
||||
{AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
|
||||
{12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
|
||||
{24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
|
||||
{25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
|
||||
|
||||
/* 96k rate */
|
||||
{AIC32X4_FREQ_25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
|
||||
{25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
|
||||
|
|
@ -601,9 +601,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case AIC32X4_FREQ_12000000:
|
||||
case AIC32X4_FREQ_24000000:
|
||||
case AIC32X4_FREQ_25000000:
|
||||
case 12000000:
|
||||
case 24000000:
|
||||
case 25000000:
|
||||
aic32x4->sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -614,16 +614,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
u8 iface_reg_1;
|
||||
u8 iface_reg_2;
|
||||
u8 iface_reg_3;
|
||||
|
||||
iface_reg_1 = snd_soc_read(codec, AIC32X4_IFACE1);
|
||||
iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2);
|
||||
iface_reg_2 = snd_soc_read(codec, AIC32X4_IFACE2);
|
||||
iface_reg_2 = 0;
|
||||
iface_reg_3 = snd_soc_read(codec, AIC32X4_IFACE3);
|
||||
iface_reg_3 = iface_reg_3 & ~(1 << 3);
|
||||
u8 iface_reg_1 = 0;
|
||||
u8 iface_reg_2 = 0;
|
||||
u8 iface_reg_3 = 0;
|
||||
|
||||
/* set master/slave audio interface */
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
|
|
@ -641,30 +634,37 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|||
case SND_SOC_DAIFMT_I2S:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT);
|
||||
iface_reg_3 |= (1 << 3); /* invert bit clock */
|
||||
iface_reg_1 |= (AIC32X4_DSP_MODE <<
|
||||
AIC32X4_IFACE1_DATATYPE_SHIFT);
|
||||
iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
|
||||
iface_reg_2 = 0x01; /* add offset 1 */
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT);
|
||||
iface_reg_3 |= (1 << 3); /* invert bit clock */
|
||||
iface_reg_1 |= (AIC32X4_DSP_MODE <<
|
||||
AIC32X4_IFACE1_DATATYPE_SHIFT);
|
||||
iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
iface_reg_1 |=
|
||||
(AIC32X4_RIGHT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT);
|
||||
iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE <<
|
||||
AIC32X4_IFACE1_DATATYPE_SHIFT);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
iface_reg_1 |=
|
||||
(AIC32X4_LEFT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT);
|
||||
iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE <<
|
||||
AIC32X4_IFACE1_DATATYPE_SHIFT);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AIC32X4_IFACE1, iface_reg_1);
|
||||
snd_soc_write(codec, AIC32X4_IFACE2, iface_reg_2);
|
||||
snd_soc_write(codec, AIC32X4_IFACE3, iface_reg_3);
|
||||
snd_soc_update_bits(codec, AIC32X4_IFACE1,
|
||||
AIC32X4_IFACE1_DATATYPE_MASK |
|
||||
AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
|
||||
snd_soc_update_bits(codec, AIC32X4_IFACE2,
|
||||
AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
|
||||
snd_soc_update_bits(codec, AIC32X4_IFACE3,
|
||||
AIC32X4_BCLKINV_MASK, iface_reg_3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -674,7 +674,8 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 data;
|
||||
u8 iface1_reg = 0;
|
||||
u8 dacsetup_reg = 0;
|
||||
int i;
|
||||
|
||||
i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
|
||||
|
|
@ -683,82 +684,88 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
|
|||
return i;
|
||||
}
|
||||
|
||||
/* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */
|
||||
snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_PLLCLKIN);
|
||||
snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK);
|
||||
/* MCLK as PLL_CLKIN */
|
||||
snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
|
||||
AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
|
||||
/* PLL as CODEC_CLKIN */
|
||||
snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
|
||||
AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
|
||||
/* DAC_MOD_CLK as BDIV_CLKIN */
|
||||
snd_soc_update_bits(codec, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
|
||||
AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
|
||||
|
||||
/* We will fix R value to 1 and will make P & J=K.D as varialble */
|
||||
data = snd_soc_read(codec, AIC32X4_PLLPR);
|
||||
data &= ~(7 << 4);
|
||||
snd_soc_write(codec, AIC32X4_PLLPR,
|
||||
(data | (aic32x4_divs[i].p_val << 4) | 0x01));
|
||||
/* We will fix R value to 1 and will make P & J=K.D as variable */
|
||||
snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
|
||||
|
||||
/* PLL P value */
|
||||
snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
|
||||
aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
|
||||
|
||||
/* PLL J value */
|
||||
snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
|
||||
|
||||
/* PLL D value */
|
||||
snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
|
||||
snd_soc_write(codec, AIC32X4_PLLDLSB,
|
||||
(aic32x4_divs[i].pll_d & 0xff));
|
||||
snd_soc_write(codec, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
|
||||
|
||||
/* NDAC divider value */
|
||||
data = snd_soc_read(codec, AIC32X4_NDAC);
|
||||
data &= ~(0x7f);
|
||||
snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac);
|
||||
snd_soc_update_bits(codec, AIC32X4_NDAC,
|
||||
AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
|
||||
|
||||
/* MDAC divider value */
|
||||
data = snd_soc_read(codec, AIC32X4_MDAC);
|
||||
data &= ~(0x7f);
|
||||
snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac);
|
||||
snd_soc_update_bits(codec, AIC32X4_MDAC,
|
||||
AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
|
||||
|
||||
/* DOSR MSB & LSB values */
|
||||
snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
|
||||
snd_soc_write(codec, AIC32X4_DOSRLSB,
|
||||
(aic32x4_divs[i].dosr & 0xff));
|
||||
snd_soc_write(codec, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
|
||||
|
||||
/* NADC divider value */
|
||||
data = snd_soc_read(codec, AIC32X4_NADC);
|
||||
data &= ~(0x7f);
|
||||
snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc);
|
||||
snd_soc_update_bits(codec, AIC32X4_NADC,
|
||||
AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
|
||||
|
||||
/* MADC divider value */
|
||||
data = snd_soc_read(codec, AIC32X4_MADC);
|
||||
data &= ~(0x7f);
|
||||
snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc);
|
||||
snd_soc_update_bits(codec, AIC32X4_MADC,
|
||||
AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
|
||||
|
||||
/* AOSR value */
|
||||
snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr);
|
||||
|
||||
/* BCLK N divider */
|
||||
data = snd_soc_read(codec, AIC32X4_BCLKN);
|
||||
data &= ~(0x7f);
|
||||
snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N);
|
||||
snd_soc_update_bits(codec, AIC32X4_BCLKN,
|
||||
AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
|
||||
|
||||
data = snd_soc_read(codec, AIC32X4_IFACE1);
|
||||
data = data & ~(3 << 4);
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
|
||||
AIC32X4_IFACE1_DATALEN_SHIFT);
|
||||
break;
|
||||
case 20:
|
||||
data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT);
|
||||
iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
|
||||
AIC32X4_IFACE1_DATALEN_SHIFT);
|
||||
break;
|
||||
case 24:
|
||||
data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT);
|
||||
iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
|
||||
AIC32X4_IFACE1_DATALEN_SHIFT);
|
||||
break;
|
||||
case 32:
|
||||
data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT);
|
||||
iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
|
||||
AIC32X4_IFACE1_DATALEN_SHIFT);
|
||||
break;
|
||||
}
|
||||
snd_soc_write(codec, AIC32X4_IFACE1, data);
|
||||
snd_soc_update_bits(codec, AIC32X4_IFACE1,
|
||||
AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
|
||||
|
||||
if (params_channels(params) == 1) {
|
||||
data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
|
||||
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
|
||||
} else {
|
||||
if (aic32x4->swapdacs)
|
||||
data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
|
||||
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
|
||||
else
|
||||
data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
|
||||
dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
|
||||
}
|
||||
snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK,
|
||||
data);
|
||||
snd_soc_update_bits(codec, AIC32X4_DACSETUP,
|
||||
AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -766,13 +773,10 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
|
|||
static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 dac_reg;
|
||||
|
||||
dac_reg = snd_soc_read(codec, AIC32X4_DACMUTE) & ~AIC32X4_MUTEON;
|
||||
if (mute)
|
||||
snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg | AIC32X4_MUTEON);
|
||||
else
|
||||
snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg);
|
||||
snd_soc_update_bits(codec, AIC32X4_DACMUTE,
|
||||
AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,141 +19,189 @@ int aic32x4_remove(struct device *dev);
|
|||
|
||||
/* tlv320aic32x4 register space (in decimal to match datasheet) */
|
||||
|
||||
#define AIC32X4_PAGE1 128
|
||||
#define AIC32X4_REG(page, reg) ((page * 128) + reg)
|
||||
|
||||
#define AIC32X4_PSEL 0
|
||||
#define AIC32X4_RESET 1
|
||||
#define AIC32X4_CLKMUX 4
|
||||
#define AIC32X4_PLLPR 5
|
||||
#define AIC32X4_PLLJ 6
|
||||
#define AIC32X4_PLLDMSB 7
|
||||
#define AIC32X4_PLLDLSB 8
|
||||
#define AIC32X4_NDAC 11
|
||||
#define AIC32X4_MDAC 12
|
||||
#define AIC32X4_DOSRMSB 13
|
||||
#define AIC32X4_DOSRLSB 14
|
||||
#define AIC32X4_NADC 18
|
||||
#define AIC32X4_MADC 19
|
||||
#define AIC32X4_AOSR 20
|
||||
#define AIC32X4_CLKMUX2 25
|
||||
#define AIC32X4_CLKOUTM 26
|
||||
#define AIC32X4_IFACE1 27
|
||||
#define AIC32X4_IFACE2 28
|
||||
#define AIC32X4_IFACE3 29
|
||||
#define AIC32X4_BCLKN 30
|
||||
#define AIC32X4_IFACE4 31
|
||||
#define AIC32X4_IFACE5 32
|
||||
#define AIC32X4_IFACE6 33
|
||||
#define AIC32X4_GPIOCTL 52
|
||||
#define AIC32X4_DOUTCTL 53
|
||||
#define AIC32X4_DINCTL 54
|
||||
#define AIC32X4_MISOCTL 55
|
||||
#define AIC32X4_SCLKCTL 56
|
||||
#define AIC32X4_DACSPB 60
|
||||
#define AIC32X4_ADCSPB 61
|
||||
#define AIC32X4_DACSETUP 63
|
||||
#define AIC32X4_DACMUTE 64
|
||||
#define AIC32X4_LDACVOL 65
|
||||
#define AIC32X4_RDACVOL 66
|
||||
#define AIC32X4_ADCSETUP 81
|
||||
#define AIC32X4_ADCFGA 82
|
||||
#define AIC32X4_LADCVOL 83
|
||||
#define AIC32X4_RADCVOL 84
|
||||
#define AIC32X4_LAGC1 86
|
||||
#define AIC32X4_LAGC2 87
|
||||
#define AIC32X4_LAGC3 88
|
||||
#define AIC32X4_LAGC4 89
|
||||
#define AIC32X4_LAGC5 90
|
||||
#define AIC32X4_LAGC6 91
|
||||
#define AIC32X4_LAGC7 92
|
||||
#define AIC32X4_RAGC1 94
|
||||
#define AIC32X4_RAGC2 95
|
||||
#define AIC32X4_RAGC3 96
|
||||
#define AIC32X4_RAGC4 97
|
||||
#define AIC32X4_RAGC5 98
|
||||
#define AIC32X4_RAGC6 99
|
||||
#define AIC32X4_RAGC7 100
|
||||
#define AIC32X4_PWRCFG (AIC32X4_PAGE1 + 1)
|
||||
#define AIC32X4_LDOCTL (AIC32X4_PAGE1 + 2)
|
||||
#define AIC32X4_OUTPWRCTL (AIC32X4_PAGE1 + 9)
|
||||
#define AIC32X4_CMMODE (AIC32X4_PAGE1 + 10)
|
||||
#define AIC32X4_HPLROUTE (AIC32X4_PAGE1 + 12)
|
||||
#define AIC32X4_HPRROUTE (AIC32X4_PAGE1 + 13)
|
||||
#define AIC32X4_LOLROUTE (AIC32X4_PAGE1 + 14)
|
||||
#define AIC32X4_LORROUTE (AIC32X4_PAGE1 + 15)
|
||||
#define AIC32X4_HPLGAIN (AIC32X4_PAGE1 + 16)
|
||||
#define AIC32X4_HPRGAIN (AIC32X4_PAGE1 + 17)
|
||||
#define AIC32X4_LOLGAIN (AIC32X4_PAGE1 + 18)
|
||||
#define AIC32X4_LORGAIN (AIC32X4_PAGE1 + 19)
|
||||
#define AIC32X4_HEADSTART (AIC32X4_PAGE1 + 20)
|
||||
#define AIC32X4_MICBIAS (AIC32X4_PAGE1 + 51)
|
||||
#define AIC32X4_LMICPGAPIN (AIC32X4_PAGE1 + 52)
|
||||
#define AIC32X4_LMICPGANIN (AIC32X4_PAGE1 + 54)
|
||||
#define AIC32X4_RMICPGAPIN (AIC32X4_PAGE1 + 55)
|
||||
#define AIC32X4_RMICPGANIN (AIC32X4_PAGE1 + 57)
|
||||
#define AIC32X4_FLOATINGINPUT (AIC32X4_PAGE1 + 58)
|
||||
#define AIC32X4_LMICPGAVOL (AIC32X4_PAGE1 + 59)
|
||||
#define AIC32X4_RMICPGAVOL (AIC32X4_PAGE1 + 60)
|
||||
#define AIC32X4_PSEL AIC32X4_REG(0, 0)
|
||||
|
||||
#define AIC32X4_FREQ_12000000 12000000
|
||||
#define AIC32X4_FREQ_24000000 24000000
|
||||
#define AIC32X4_FREQ_25000000 25000000
|
||||
#define AIC32X4_RESET AIC32X4_REG(0, 1)
|
||||
#define AIC32X4_CLKMUX AIC32X4_REG(0, 4)
|
||||
#define AIC32X4_PLLPR AIC32X4_REG(0, 5)
|
||||
#define AIC32X4_PLLJ AIC32X4_REG(0, 6)
|
||||
#define AIC32X4_PLLDMSB AIC32X4_REG(0, 7)
|
||||
#define AIC32X4_PLLDLSB AIC32X4_REG(0, 8)
|
||||
#define AIC32X4_NDAC AIC32X4_REG(0, 11)
|
||||
#define AIC32X4_MDAC AIC32X4_REG(0, 12)
|
||||
#define AIC32X4_DOSRMSB AIC32X4_REG(0, 13)
|
||||
#define AIC32X4_DOSRLSB AIC32X4_REG(0, 14)
|
||||
#define AIC32X4_NADC AIC32X4_REG(0, 18)
|
||||
#define AIC32X4_MADC AIC32X4_REG(0, 19)
|
||||
#define AIC32X4_AOSR AIC32X4_REG(0, 20)
|
||||
#define AIC32X4_CLKMUX2 AIC32X4_REG(0, 25)
|
||||
#define AIC32X4_CLKOUTM AIC32X4_REG(0, 26)
|
||||
#define AIC32X4_IFACE1 AIC32X4_REG(0, 27)
|
||||
#define AIC32X4_IFACE2 AIC32X4_REG(0, 28)
|
||||
#define AIC32X4_IFACE3 AIC32X4_REG(0, 29)
|
||||
#define AIC32X4_BCLKN AIC32X4_REG(0, 30)
|
||||
#define AIC32X4_IFACE4 AIC32X4_REG(0, 31)
|
||||
#define AIC32X4_IFACE5 AIC32X4_REG(0, 32)
|
||||
#define AIC32X4_IFACE6 AIC32X4_REG(0, 33)
|
||||
#define AIC32X4_GPIOCTL AIC32X4_REG(0, 52)
|
||||
#define AIC32X4_DOUTCTL AIC32X4_REG(0, 53)
|
||||
#define AIC32X4_DINCTL AIC32X4_REG(0, 54)
|
||||
#define AIC32X4_MISOCTL AIC32X4_REG(0, 55)
|
||||
#define AIC32X4_SCLKCTL AIC32X4_REG(0, 56)
|
||||
#define AIC32X4_DACSPB AIC32X4_REG(0, 60)
|
||||
#define AIC32X4_ADCSPB AIC32X4_REG(0, 61)
|
||||
#define AIC32X4_DACSETUP AIC32X4_REG(0, 63)
|
||||
#define AIC32X4_DACMUTE AIC32X4_REG(0, 64)
|
||||
#define AIC32X4_LDACVOL AIC32X4_REG(0, 65)
|
||||
#define AIC32X4_RDACVOL AIC32X4_REG(0, 66)
|
||||
#define AIC32X4_ADCSETUP AIC32X4_REG(0, 81)
|
||||
#define AIC32X4_ADCFGA AIC32X4_REG(0, 82)
|
||||
#define AIC32X4_LADCVOL AIC32X4_REG(0, 83)
|
||||
#define AIC32X4_RADCVOL AIC32X4_REG(0, 84)
|
||||
#define AIC32X4_LAGC1 AIC32X4_REG(0, 86)
|
||||
#define AIC32X4_LAGC2 AIC32X4_REG(0, 87)
|
||||
#define AIC32X4_LAGC3 AIC32X4_REG(0, 88)
|
||||
#define AIC32X4_LAGC4 AIC32X4_REG(0, 89)
|
||||
#define AIC32X4_LAGC5 AIC32X4_REG(0, 90)
|
||||
#define AIC32X4_LAGC6 AIC32X4_REG(0, 91)
|
||||
#define AIC32X4_LAGC7 AIC32X4_REG(0, 92)
|
||||
#define AIC32X4_RAGC1 AIC32X4_REG(0, 94)
|
||||
#define AIC32X4_RAGC2 AIC32X4_REG(0, 95)
|
||||
#define AIC32X4_RAGC3 AIC32X4_REG(0, 96)
|
||||
#define AIC32X4_RAGC4 AIC32X4_REG(0, 97)
|
||||
#define AIC32X4_RAGC5 AIC32X4_REG(0, 98)
|
||||
#define AIC32X4_RAGC6 AIC32X4_REG(0, 99)
|
||||
#define AIC32X4_RAGC7 AIC32X4_REG(0, 100)
|
||||
|
||||
#define AIC32X4_WORD_LEN_16BITS 0x00
|
||||
#define AIC32X4_WORD_LEN_20BITS 0x01
|
||||
#define AIC32X4_WORD_LEN_24BITS 0x02
|
||||
#define AIC32X4_WORD_LEN_32BITS 0x03
|
||||
#define AIC32X4_PWRCFG AIC32X4_REG(1, 1)
|
||||
#define AIC32X4_LDOCTL AIC32X4_REG(1, 2)
|
||||
#define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9)
|
||||
#define AIC32X4_CMMODE AIC32X4_REG(1, 10)
|
||||
#define AIC32X4_HPLROUTE AIC32X4_REG(1, 12)
|
||||
#define AIC32X4_HPRROUTE AIC32X4_REG(1, 13)
|
||||
#define AIC32X4_LOLROUTE AIC32X4_REG(1, 14)
|
||||
#define AIC32X4_LORROUTE AIC32X4_REG(1, 15)
|
||||
#define AIC32X4_HPLGAIN AIC32X4_REG(1, 16)
|
||||
#define AIC32X4_HPRGAIN AIC32X4_REG(1, 17)
|
||||
#define AIC32X4_LOLGAIN AIC32X4_REG(1, 18)
|
||||
#define AIC32X4_LORGAIN AIC32X4_REG(1, 19)
|
||||
#define AIC32X4_HEADSTART AIC32X4_REG(1, 20)
|
||||
#define AIC32X4_MICBIAS AIC32X4_REG(1, 51)
|
||||
#define AIC32X4_LMICPGAPIN AIC32X4_REG(1, 52)
|
||||
#define AIC32X4_LMICPGANIN AIC32X4_REG(1, 54)
|
||||
#define AIC32X4_RMICPGAPIN AIC32X4_REG(1, 55)
|
||||
#define AIC32X4_RMICPGANIN AIC32X4_REG(1, 57)
|
||||
#define AIC32X4_FLOATINGINPUT AIC32X4_REG(1, 58)
|
||||
#define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59)
|
||||
#define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60)
|
||||
|
||||
#define AIC32X4_LADC_EN (1 << 7)
|
||||
#define AIC32X4_RADC_EN (1 << 6)
|
||||
/* Bits, masks, and shifts */
|
||||
|
||||
#define AIC32X4_I2S_MODE 0x00
|
||||
#define AIC32X4_DSP_MODE 0x01
|
||||
#define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02
|
||||
#define AIC32X4_LEFT_JUSTIFIED_MODE 0x03
|
||||
/* AIC32X4_CLKMUX */
|
||||
#define AIC32X4_PLL_CLKIN_MASK GENMASK(3, 2)
|
||||
#define AIC32X4_PLL_CLKIN_SHIFT (2)
|
||||
#define AIC32X4_PLL_CLKIN_MCLK (0x00)
|
||||
#define AIC32X4_PLL_CLKIN_BCKL (0x01)
|
||||
#define AIC32X4_PLL_CLKIN_GPIO1 (0x02)
|
||||
#define AIC32X4_PLL_CLKIN_DIN (0x03)
|
||||
#define AIC32X4_CODEC_CLKIN_MASK GENMASK(1, 0)
|
||||
#define AIC32X4_CODEC_CLKIN_SHIFT (0)
|
||||
#define AIC32X4_CODEC_CLKIN_MCLK (0x00)
|
||||
#define AIC32X4_CODEC_CLKIN_BCLK (0x01)
|
||||
#define AIC32X4_CODEC_CLKIN_GPIO1 (0x02)
|
||||
#define AIC32X4_CODEC_CLKIN_PLL (0x03)
|
||||
|
||||
#define AIC32X4_AVDDWEAKDISABLE 0x08
|
||||
#define AIC32X4_LDOCTLEN 0x01
|
||||
/* AIC32X4_PLLPR */
|
||||
#define AIC32X4_PLLEN BIT(7)
|
||||
#define AIC32X4_PLL_P_MASK GENMASK(6, 4)
|
||||
#define AIC32X4_PLL_P_SHIFT (4)
|
||||
#define AIC32X4_PLL_R_MASK GENMASK(3, 0)
|
||||
|
||||
#define AIC32X4_LDOIN_18_36 0x01
|
||||
#define AIC32X4_LDOIN2HP 0x02
|
||||
/* AIC32X4_NDAC */
|
||||
#define AIC32X4_NDACEN BIT(7)
|
||||
#define AIC32X4_NDAC_MASK GENMASK(6, 0)
|
||||
|
||||
#define AIC32X4_DACSPBLOCK_MASK 0x1f
|
||||
#define AIC32X4_ADCSPBLOCK_MASK 0x1f
|
||||
/* AIC32X4_MDAC */
|
||||
#define AIC32X4_MDACEN BIT(7)
|
||||
#define AIC32X4_MDAC_MASK GENMASK(6, 0)
|
||||
|
||||
#define AIC32X4_PLLJ_SHIFT 6
|
||||
#define AIC32X4_DOSRMSB_SHIFT 4
|
||||
/* AIC32X4_NADC */
|
||||
#define AIC32X4_NADCEN BIT(7)
|
||||
#define AIC32X4_NADC_MASK GENMASK(6, 0)
|
||||
|
||||
#define AIC32X4_PLLCLKIN 0x03
|
||||
/* AIC32X4_MADC */
|
||||
#define AIC32X4_MADCEN BIT(7)
|
||||
#define AIC32X4_MADC_MASK GENMASK(6, 0)
|
||||
|
||||
#define AIC32X4_MICBIAS_LDOIN 0x08
|
||||
/* AIC32X4_BCLKN */
|
||||
#define AIC32X4_BCLKEN BIT(7)
|
||||
#define AIC32X4_BCLK_MASK GENMASK(6, 0)
|
||||
|
||||
/* AIC32X4_IFACE1 */
|
||||
#define AIC32X4_IFACE1_DATATYPE_MASK GENMASK(7, 6)
|
||||
#define AIC32X4_IFACE1_DATATYPE_SHIFT (6)
|
||||
#define AIC32X4_I2S_MODE (0x00)
|
||||
#define AIC32X4_DSP_MODE (0x01)
|
||||
#define AIC32X4_RIGHT_JUSTIFIED_MODE (0x02)
|
||||
#define AIC32X4_LEFT_JUSTIFIED_MODE (0x03)
|
||||
#define AIC32X4_IFACE1_DATALEN_MASK GENMASK(5, 4)
|
||||
#define AIC32X4_IFACE1_DATALEN_SHIFT (4)
|
||||
#define AIC32X4_WORD_LEN_16BITS (0x00)
|
||||
#define AIC32X4_WORD_LEN_20BITS (0x01)
|
||||
#define AIC32X4_WORD_LEN_24BITS (0x02)
|
||||
#define AIC32X4_WORD_LEN_32BITS (0x03)
|
||||
#define AIC32X4_IFACE1_MASTER_MASK GENMASK(3, 2)
|
||||
#define AIC32X4_BCLKMASTER BIT(2)
|
||||
#define AIC32X4_WCLKMASTER BIT(3)
|
||||
|
||||
/* AIC32X4_IFACE2 */
|
||||
#define AIC32X4_DATA_OFFSET_MASK GENMASK(7, 0)
|
||||
|
||||
/* AIC32X4_IFACE3 */
|
||||
#define AIC32X4_BCLKINV_MASK BIT(3)
|
||||
#define AIC32X4_BDIVCLK_MASK GENMASK(1, 0)
|
||||
#define AIC32X4_BDIVCLK_SHIFT (0)
|
||||
#define AIC32X4_DAC2BCLK (0x00)
|
||||
#define AIC32X4_DACMOD2BCLK (0x01)
|
||||
#define AIC32X4_ADC2BCLK (0x02)
|
||||
#define AIC32X4_ADCMOD2BCLK (0x03)
|
||||
|
||||
/* AIC32X4_DACSETUP */
|
||||
#define AIC32X4_DAC_CHAN_MASK GENMASK(5, 2)
|
||||
#define AIC32X4_LDAC2RCHN BIT(5)
|
||||
#define AIC32X4_LDAC2LCHN BIT(4)
|
||||
#define AIC32X4_RDAC2LCHN BIT(3)
|
||||
#define AIC32X4_RDAC2RCHN BIT(2)
|
||||
|
||||
/* AIC32X4_DACMUTE */
|
||||
#define AIC32X4_MUTEON 0x0C
|
||||
|
||||
/* AIC32X4_ADCSETUP */
|
||||
#define AIC32X4_LADC_EN BIT(7)
|
||||
#define AIC32X4_RADC_EN BIT(6)
|
||||
|
||||
/* AIC32X4_PWRCFG */
|
||||
#define AIC32X4_AVDDWEAKDISABLE BIT(3)
|
||||
|
||||
/* AIC32X4_LDOCTL */
|
||||
#define AIC32X4_LDOCTLEN BIT(0)
|
||||
|
||||
/* AIC32X4_CMMODE */
|
||||
#define AIC32X4_LDOIN_18_36 BIT(0)
|
||||
#define AIC32X4_LDOIN2HP BIT(1)
|
||||
|
||||
/* AIC32X4_MICBIAS */
|
||||
#define AIC32X4_MICBIAS_LDOIN BIT(3)
|
||||
#define AIC32X4_MICBIAS_2075V 0x60
|
||||
|
||||
/* AIC32X4_LMICPGANIN */
|
||||
#define AIC32X4_LMICPGANIN_IN2R_10K 0x10
|
||||
#define AIC32X4_LMICPGANIN_CM1L_10K 0x40
|
||||
|
||||
/* AIC32X4_RMICPGANIN */
|
||||
#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
|
||||
#define AIC32X4_RMICPGANIN_CM1R_10K 0x40
|
||||
|
||||
#define AIC32X4_LMICPGAVOL_NOGAIN 0x80
|
||||
#define AIC32X4_RMICPGAVOL_NOGAIN 0x80
|
||||
|
||||
#define AIC32X4_BCLKMASTER 0x08
|
||||
#define AIC32X4_WCLKMASTER 0x04
|
||||
#define AIC32X4_PLLEN (0x01 << 7)
|
||||
#define AIC32X4_NDACEN (0x01 << 7)
|
||||
#define AIC32X4_MDACEN (0x01 << 7)
|
||||
#define AIC32X4_NADCEN (0x01 << 7)
|
||||
#define AIC32X4_MADCEN (0x01 << 7)
|
||||
#define AIC32X4_BCLKEN (0x01 << 7)
|
||||
#define AIC32X4_DACEN (0x03 << 6)
|
||||
#define AIC32X4_RDAC2LCHN (0x02 << 2)
|
||||
#define AIC32X4_LDAC2RCHN (0x02 << 4)
|
||||
#define AIC32X4_LDAC2LCHN (0x01 << 4)
|
||||
#define AIC32X4_RDAC2RCHN (0x01 << 2)
|
||||
#define AIC32X4_DAC_CHAN_MASK 0x3c
|
||||
|
||||
#define AIC32X4_SSTEP2WCLK 0x01
|
||||
#define AIC32X4_MUTEON 0x0C
|
||||
#define AIC32X4_DACMOD2BCLK 0x01
|
||||
|
||||
#endif /* _TLV320AIC32X4_H */
|
||||
|
|
|
|||
|
|
@ -1804,11 +1804,18 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
|||
if (!ai3x_setup)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_get_named_gpio(np, "gpio-reset", 0);
|
||||
if (ret >= 0)
|
||||
ret = of_get_named_gpio(np, "reset-gpios", 0);
|
||||
if (ret >= 0) {
|
||||
aic3x->gpio_reset = ret;
|
||||
else
|
||||
aic3x->gpio_reset = -1;
|
||||
} else {
|
||||
ret = of_get_named_gpio(np, "gpio-reset", 0);
|
||||
if (ret > 0) {
|
||||
dev_warn(&i2c->dev, "Using deprecated property \"gpio-reset\", please update your DT");
|
||||
aic3x->gpio_reset = ret;
|
||||
} else {
|
||||
aic3x->gpio_reset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(np, "ai3x-gpio-func",
|
||||
ai3x_setup->gpio_func, 2) >= 0) {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ struct tlv320dac33_priv {
|
|||
int mode1_latency; /* latency caused by the i2c writes in
|
||||
* us */
|
||||
u8 burst_bclkdiv; /* BCLK divider value in burst mode */
|
||||
u8 *reg_cache;
|
||||
unsigned int burst_rate; /* Interface speed in Burst modes */
|
||||
|
||||
int keep_bclk; /* Keep the BCLK continuously running
|
||||
|
|
@ -121,7 +122,7 @@ struct tlv320dac33_priv {
|
|||
unsigned int uthr;
|
||||
|
||||
enum dac33_state state;
|
||||
void *control_data;
|
||||
struct i2c_client *i2c;
|
||||
};
|
||||
|
||||
static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
|
||||
|
|
@ -173,7 +174,8 @@ static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
|
|||
static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec,
|
||||
unsigned reg)
|
||||
{
|
||||
u8 *cache = codec->reg_cache;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 *cache = dac33->reg_cache;
|
||||
if (reg >= DAC33_CACHEREGNUM)
|
||||
return 0;
|
||||
|
||||
|
|
@ -183,7 +185,8 @@ static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec,
|
|||
static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
|
||||
u8 reg, u8 value)
|
||||
{
|
||||
u8 *cache = codec->reg_cache;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 *cache = dac33->reg_cache;
|
||||
if (reg >= DAC33_CACHEREGNUM)
|
||||
return;
|
||||
|
||||
|
|
@ -200,7 +203,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
|
|||
|
||||
/* If powered off, return the cached value */
|
||||
if (dac33->chip_power) {
|
||||
val = i2c_smbus_read_byte_data(codec->control_data, value[0]);
|
||||
val = i2c_smbus_read_byte_data(dac33->i2c, value[0]);
|
||||
if (val < 0) {
|
||||
dev_err(codec->dev, "Read failed (%d)\n", val);
|
||||
value[0] = dac33_read_reg_cache(codec, reg);
|
||||
|
|
@ -233,7 +236,7 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
|
||||
dac33_write_reg_cache(codec, data[0], data[1]);
|
||||
if (dac33->chip_power) {
|
||||
ret = codec->hw_write(codec->control_data, data, 2);
|
||||
ret = i2c_master_send(dac33->i2c, data, 2);
|
||||
if (ret != 2)
|
||||
dev_err(codec->dev, "Write failed (%d)\n", ret);
|
||||
else
|
||||
|
|
@ -243,19 +246,6 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dac33->mutex);
|
||||
ret = dac33_write(codec, reg, value);
|
||||
mutex_unlock(&dac33->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DAC33_I2C_ADDR_AUTOINC 0x80
|
||||
static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
|
|
@ -280,7 +270,7 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
|
|||
if (dac33->chip_power) {
|
||||
/* We need to set autoincrement mode for 16 bit writes */
|
||||
data[0] |= DAC33_I2C_ADDR_AUTOINC;
|
||||
ret = codec->hw_write(codec->control_data, data, 3);
|
||||
ret = i2c_master_send(dac33->i2c, data, 3);
|
||||
if (ret != 3)
|
||||
dev_err(codec->dev, "Write failed (%d)\n", ret);
|
||||
else
|
||||
|
|
@ -1379,8 +1369,6 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
|
|||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
codec->control_data = dac33->control_data;
|
||||
codec->hw_write = (hw_write_t) i2c_master_send;
|
||||
dac33->codec = codec;
|
||||
|
||||
/* Read the tlv320dac33 ID registers */
|
||||
|
|
@ -1434,13 +1422,9 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
|
|||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
|
||||
.read = dac33_read_reg_cache,
|
||||
.write = dac33_write_locked,
|
||||
.set_bias_level = dac33_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
.reg_cache_size = ARRAY_SIZE(dac33_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = dac33_reg,
|
||||
|
||||
.probe = dac33_soc_probe,
|
||||
.remove = dac33_soc_remove,
|
||||
|
||||
|
|
@ -1499,7 +1483,14 @@ static int dac33_i2c_probe(struct i2c_client *client,
|
|||
if (dac33 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dac33->control_data = client;
|
||||
dac33->reg_cache = devm_kmemdup(&client->dev,
|
||||
dac33_reg,
|
||||
ARRAY_SIZE(dac33_reg) * sizeof(u8),
|
||||
GFP_KERNEL);
|
||||
if (!dac33->reg_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
dac33->i2c = client;
|
||||
mutex_init(&dac33->mutex);
|
||||
spin_lock_init(&dac33->lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
|
|||
{
|
||||
struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component);
|
||||
|
||||
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);
|
||||
|
|
|
|||
1456
sound/soc/codecs/tscs42xx.c
Normal file
1456
sound/soc/codecs/tscs42xx.c
Normal file
File diff suppressed because it is too large
Load diff
2693
sound/soc/codecs/tscs42xx.h
Normal file
2693
sound/soc/codecs/tscs42xx.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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) {
|
||||
|
|
@ -240,10 +240,11 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
|
|||
sizeof(struct twl4030_codec_data),
|
||||
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;
|
||||
|
|
@ -849,14 +850,14 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
|
|||
int mask = (1 << fls(max)) - 1;
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
(snd_soc_read(codec, reg) >> shift) & mask;
|
||||
(twl4030_read(codec, reg) >> shift) & mask;
|
||||
if (ucontrol->value.integer.value[0])
|
||||
ucontrol->value.integer.value[0] =
|
||||
max + 1 - ucontrol->value.integer.value[0];
|
||||
|
||||
if (shift != rshift) {
|
||||
ucontrol->value.integer.value[1] =
|
||||
(snd_soc_read(codec, reg) >> rshift) & mask;
|
||||
(twl4030_read(codec, reg) >> rshift) & mask;
|
||||
if (ucontrol->value.integer.value[1])
|
||||
ucontrol->value.integer.value[1] =
|
||||
max + 1 - ucontrol->value.integer.value[1];
|
||||
|
|
@ -907,9 +908,9 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
|
|||
int mask = (1<<fls(max))-1;
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
(snd_soc_read(codec, reg) >> shift) & mask;
|
||||
(twl4030_read(codec, reg) >> shift) & mask;
|
||||
ucontrol->value.integer.value[1] =
|
||||
(snd_soc_read(codec, reg2) >> shift) & mask;
|
||||
(twl4030_read(codec, reg2) >> shift) & mask;
|
||||
|
||||
if (ucontrol->value.integer.value[0])
|
||||
ucontrol->value.integer.value[0] =
|
||||
|
|
@ -2194,8 +2195,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
|
|||
static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
|
||||
.probe = twl4030_soc_probe,
|
||||
.remove = twl4030_soc_remove,
|
||||
.read = twl4030_read,
|
||||
.write = twl4030_write,
|
||||
.set_bias_level = twl4030_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -106,10 +106,12 @@ static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
|
|||
{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
|
||||
};
|
||||
|
||||
#define to_twl6040(codec) dev_get_drvdata((codec)->dev->parent)
|
||||
|
||||
static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
u8 value;
|
||||
|
||||
if (reg >= TWL6040_CACHEREGNUM)
|
||||
|
|
@ -171,7 +173,7 @@ static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
|
|||
static int twl6040_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
|
||||
if (reg >= TWL6040_CACHEREGNUM)
|
||||
return -EIO;
|
||||
|
|
@ -541,7 +543,7 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
|
|||
if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
|
||||
snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
|
||||
|
||||
u8 val = snd_soc_read(codec, TWL6040_REG_HSLCTL);
|
||||
u8 val = twl6040_read(codec, TWL6040_REG_HSLCTL);
|
||||
if (val & TWL6040_HSDACMODE)
|
||||
/* HSDACL in LP mode */
|
||||
return -8; /* -8dB */
|
||||
|
|
@ -572,7 +574,7 @@ EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
|
|||
|
||||
int twl6040_get_hs_step_size(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
|
||||
if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
|
||||
/* For ES under ES_1.3 HS step is 2 mV */
|
||||
|
|
@ -830,7 +832,7 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
static int twl6040_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -922,7 +924,7 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
|
|
@ -964,7 +966,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
|
||||
int mute)
|
||||
{
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int hslctl, hsrctl, earctl;
|
||||
int hflctl, hfrctl;
|
||||
|
|
@ -1108,7 +1110,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
|
|||
static int twl6040_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl6040_data *priv;
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
|
||||
struct platform_device *pdev = to_platform_device(codec->dev);
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -1119,7 +1120,6 @@ static int twl6040_probe(struct snd_soc_codec *codec)
|
|||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
|
||||
priv->codec = codec;
|
||||
codec->control_data = twl6040;
|
||||
|
||||
priv->plug_irq = platform_get_irq(pdev, 0);
|
||||
if (priv->plug_irq < 0) {
|
||||
|
|
@ -1158,8 +1158,6 @@ static int twl6040_remove(struct snd_soc_codec *codec)
|
|||
static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
|
||||
.probe = twl6040_probe,
|
||||
.remove = twl6040_remove,
|
||||
.read = twl6040_read,
|
||||
.write = twl6040_write,
|
||||
.set_bias_level = twl6040_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
.ignore_pmdown_time = true,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ struct uda1380_priv {
|
|||
struct snd_soc_codec *codec;
|
||||
unsigned int dac_clk;
|
||||
struct work_struct work;
|
||||
void *control_data;
|
||||
struct i2c_client *i2c;
|
||||
u16 *reg_cache;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -63,7 +64,9 @@ static unsigned long uda1380_cache_dirty;
|
|||
static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 *cache = uda1380->reg_cache;
|
||||
|
||||
if (reg == UDA1380_RESET)
|
||||
return 0;
|
||||
if (reg >= UDA1380_CACHEREGNUM)
|
||||
|
|
@ -77,7 +80,8 @@ static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
|
|||
static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
|
||||
u16 reg, unsigned int value)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 *cache = uda1380->reg_cache;
|
||||
|
||||
if (reg >= UDA1380_CACHEREGNUM)
|
||||
return;
|
||||
|
|
@ -92,6 +96,7 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
|
|||
static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 data[3];
|
||||
|
||||
/* data is
|
||||
|
|
@ -111,10 +116,10 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
|
||||
return 0;
|
||||
pr_debug("uda1380: hw write %x val %x\n", reg, value);
|
||||
if (codec->hw_write(codec->control_data, data, 3) == 3) {
|
||||
if (i2c_master_send(uda1380->i2c, data, 3) == 3) {
|
||||
unsigned int val;
|
||||
i2c_master_send(codec->control_data, data, 1);
|
||||
i2c_master_recv(codec->control_data, data, 2);
|
||||
i2c_master_send(uda1380->i2c, data, 1);
|
||||
i2c_master_recv(uda1380->i2c, data, 2);
|
||||
val = (data[0]<<8) | data[1];
|
||||
if (val != value) {
|
||||
pr_debug("uda1380: READ BACK VAL %x\n",
|
||||
|
|
@ -130,16 +135,17 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
|
||||
static void uda1380_sync_cache(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg;
|
||||
u8 data[3];
|
||||
u16 *cache = codec->reg_cache;
|
||||
u16 *cache = uda1380->reg_cache;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (reg = 0; reg < UDA1380_MVOL; reg++) {
|
||||
data[0] = reg;
|
||||
data[1] = (cache[reg] & 0xff00) >> 8;
|
||||
data[2] = cache[reg] & 0x00ff;
|
||||
if (codec->hw_write(codec->control_data, data, 3) != 3)
|
||||
if (i2c_master_send(uda1380->i2c, data, 3) != 3)
|
||||
dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
|
||||
__func__, reg);
|
||||
}
|
||||
|
|
@ -148,6 +154,7 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec)
|
|||
static int uda1380_reset(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_reset)) {
|
||||
gpio_set_value(pdata->gpio_reset, 1);
|
||||
|
|
@ -160,7 +167,7 @@ static int uda1380_reset(struct snd_soc_codec *codec)
|
|||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
|
||||
if (codec->hw_write(codec->control_data, data, 3) != 3) {
|
||||
if (i2c_master_send(uda1380->i2c, data, 3) != 3) {
|
||||
dev_err(codec->dev, "%s: failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -695,9 +702,6 @@ static int uda1380_probe(struct snd_soc_codec *codec)
|
|||
|
||||
uda1380->codec = codec;
|
||||
|
||||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
codec->control_data = uda1380->control_data;
|
||||
|
||||
if (!gpio_is_valid(pdata->gpio_power)) {
|
||||
ret = uda1380_reset(codec);
|
||||
if (ret)
|
||||
|
|
@ -722,16 +726,9 @@ static int uda1380_probe(struct snd_soc_codec *codec)
|
|||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
|
||||
.probe = uda1380_probe,
|
||||
.read = uda1380_read_reg_cache,
|
||||
.write = uda1380_write,
|
||||
.set_bias_level = uda1380_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.reg_cache_size = ARRAY_SIZE(uda1380_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = uda1380_reg,
|
||||
.reg_cache_step = 1,
|
||||
|
||||
.component_driver = {
|
||||
.controls = uda1380_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(uda1380_snd_controls),
|
||||
|
|
@ -771,8 +768,15 @@ static int uda1380_i2c_probe(struct i2c_client *i2c,
|
|||
return ret;
|
||||
}
|
||||
|
||||
uda1380->reg_cache = devm_kmemdup(&i2c->dev,
|
||||
uda1380_reg,
|
||||
ARRAY_SIZE(uda1380_reg) * sizeof(u16),
|
||||
GFP_KERNEL);
|
||||
if (!uda1380->reg_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, uda1380);
|
||||
uda1380->control_data = i2c;
|
||||
uda1380->i2c = i2c;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
|
||||
|
|
|
|||
|
|
@ -655,11 +655,8 @@ static int wm0010_boot(struct snd_soc_codec *codec)
|
|||
ret = -ENOMEM;
|
||||
len = pll_rec.length + 8;
|
||||
out = kzalloc(len, GFP_KERNEL | GFP_DMA);
|
||||
if (!out) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to allocate RX buffer\n");
|
||||
if (!out)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA);
|
||||
if (!img_swap)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* 'wm2000_anc.bin' by default (overridable via platform data) at
|
||||
* runtime and is expected to be in flat binary format. This is
|
||||
* generated by Wolfson configuration tools and includes
|
||||
* system-specific callibration information. If supplied as a
|
||||
* system-specific calibration information. If supplied as a
|
||||
* sequence of ASCII-encoded hexidecimal bytes this can be converted
|
||||
* into a flat binary with a command such as this on the command line:
|
||||
*
|
||||
|
|
@ -826,8 +826,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
|||
int reg;
|
||||
u16 id;
|
||||
|
||||
wm2000 = devm_kzalloc(&i2c->dev, sizeof(struct wm2000_priv),
|
||||
GFP_KERNEL);
|
||||
wm2000 = devm_kzalloc(&i2c->dev, sizeof(*wm2000), GFP_KERNEL);
|
||||
if (!wm2000)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -902,7 +901,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
|||
wm2000->anc_download_size,
|
||||
GFP_KERNEL);
|
||||
if (wm2000->anc_download == NULL) {
|
||||
dev_err(&i2c->dev, "Out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_supplies;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1935,8 +1935,11 @@ static int wm5102_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 wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int ret;
|
||||
|
||||
snd_soc_codec_init_regmap(codec, arizona->regmap);
|
||||
|
||||
ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1989,17 +1992,9 @@ static unsigned int wm5102_digital_vu[] = {
|
|||
ARIZONA_DAC_DIGITAL_VOLUME_5R,
|
||||
};
|
||||
|
||||
static struct regmap *wm5102_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm5102_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return priv->core.arizona->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
|
||||
.probe = wm5102_codec_probe,
|
||||
.remove = wm5102_codec_remove,
|
||||
.get_regmap = wm5102_get_regmap,
|
||||
|
||||
.idle_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -2280,9 +2280,11 @@ static int wm5110_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 wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int i, 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)
|
||||
|
|
@ -2344,17 +2346,9 @@ static unsigned int wm5110_digital_vu[] = {
|
|||
ARIZONA_DAC_DIGITAL_VOLUME_6R,
|
||||
};
|
||||
|
||||
static struct regmap *wm5110_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm5110_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return priv->core.arizona->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
|
||||
.probe = wm5110_codec_probe,
|
||||
.remove = wm5110_codec_remove,
|
||||
.get_regmap = wm5110_get_regmap,
|
||||
|
||||
.idle_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -1472,6 +1472,8 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
|
|||
GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_soc_codec_init_regmap(codec, wm8350->regmap);
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
|
||||
priv->wm8350 = wm8350;
|
||||
|
|
@ -1580,17 +1582,9 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap *wm8350_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm8350 *wm8350 = dev_get_platdata(dev);
|
||||
|
||||
return wm8350->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
|
||||
.probe = wm8350_codec_probe,
|
||||
.remove = wm8350_codec_remove,
|
||||
.get_regmap = wm8350_get_regmap,
|
||||
.set_bias_level = wm8350_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -1285,6 +1285,7 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
|
|||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_soc_codec_init_regmap(codec, wm8400->regmap);
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
priv->wm8400 = wm8400;
|
||||
|
||||
|
|
@ -1325,17 +1326,9 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap *wm8400_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm8400 *wm8400 = dev_get_platdata(dev);
|
||||
|
||||
return wm8400->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
|
||||
.probe = wm8400_codec_probe,
|
||||
.remove = wm8400_codec_remove,
|
||||
.get_regmap = wm8400_get_regmap,
|
||||
.set_bias_level = wm8400_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -1995,8 +1995,7 @@ static int wm8903_i2c_probe(struct i2c_client *i2c,
|
|||
unsigned int val, irq_pol;
|
||||
int ret, i;
|
||||
|
||||
wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv),
|
||||
GFP_KERNEL);
|
||||
wm8903 = devm_kzalloc(&i2c->dev, sizeof(*wm8903), GFP_KERNEL);
|
||||
if (wm8903 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -2017,13 +2016,10 @@ static int wm8903_i2c_probe(struct i2c_client *i2c,
|
|||
if (pdata) {
|
||||
wm8903->pdata = pdata;
|
||||
} else {
|
||||
wm8903->pdata = devm_kzalloc(&i2c->dev,
|
||||
sizeof(struct wm8903_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (wm8903->pdata == NULL) {
|
||||
dev_err(&i2c->dev, "Failed to allocate pdata\n");
|
||||
wm8903->pdata = devm_kzalloc(&i2c->dev, sizeof(*wm8903->pdata),
|
||||
GFP_KERNEL);
|
||||
if (!wm8903->pdata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = wm8903_set_pdata_irq_trigger(i2c, wm8903->pdata);
|
||||
|
|
|
|||
|
|
@ -3993,6 +3993,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
|||
unsigned int reg;
|
||||
int ret, i;
|
||||
|
||||
snd_soc_codec_init_regmap(codec, control->regmap);
|
||||
|
||||
wm8994->hubs.codec = codec;
|
||||
|
||||
mutex_init(&wm8994->accdet_lock);
|
||||
|
|
@ -4434,19 +4436,11 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap *wm8994_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm8994 *control = dev_get_drvdata(dev->parent);
|
||||
|
||||
return control->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
|
||||
.probe = wm8994_codec_probe,
|
||||
.remove = wm8994_codec_remove,
|
||||
.suspend = wm8994_codec_suspend,
|
||||
.resume = wm8994_codec_resume,
|
||||
.get_regmap = wm8994_get_regmap,
|
||||
.set_bias_level = wm8994_set_bias_level,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1062,8 +1062,11 @@ static int wm8997_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 wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->core.arizona;
|
||||
int ret;
|
||||
|
||||
snd_soc_codec_init_regmap(codec, arizona->regmap);
|
||||
|
||||
ret = arizona_init_spk(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -1095,17 +1098,9 @@ static unsigned int wm8997_digital_vu[] = {
|
|||
ARIZONA_DAC_DIGITAL_VOLUME_5R,
|
||||
};
|
||||
|
||||
static struct regmap *wm8997_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm8997_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return priv->core.arizona->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
|
||||
.probe = wm8997_codec_probe,
|
||||
.remove = wm8997_codec_remove,
|
||||
.get_regmap = wm8997_get_regmap,
|
||||
|
||||
.idle_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -1275,9 +1275,11 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)
|
|||
struct wm8998_priv *priv = snd_soc_codec_get_drvdata(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 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)
|
||||
|
|
@ -1313,17 +1315,9 @@ static unsigned int wm8998_digital_vu[] = {
|
|||
ARIZONA_DAC_DIGITAL_VOLUME_5R,
|
||||
};
|
||||
|
||||
static struct regmap *wm8998_get_regmap(struct device *dev)
|
||||
{
|
||||
struct wm8998_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return priv->core.arizona->regmap;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
|
||||
.probe = wm8998_codec_probe,
|
||||
.remove = wm8998_codec_remove,
|
||||
.get_regmap = wm8998_get_regmap,
|
||||
|
||||
.idle_bias_off = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "../codecs/tlv320aic23.h"
|
||||
#include "imx-ssi.h"
|
||||
#include "fsl_ssi.h"
|
||||
#include "imx-audmux.h"
|
||||
|
||||
#define CODEC_CLOCK 12000000
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
#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 Register Field Maps -- */
|
||||
|
||||
#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 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_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 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
|
||||
|
||||
/* 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 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
|
||||
|
||||
/* 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 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_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)
|
||||
|
||||
#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 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 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_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 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_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 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
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,71 +1,123 @@
|
|||
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
|
||||
select SND_SOC_INTEL_COMMON
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue