mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
ASoC: Tas2560: Add audio codecs
Add audio codecs Tas2560 driver. Change-Id: I0806dc5427b7c8bdd3447e06ebd1e92d9a8ec22c Signed-off-by: Wen Xie <xiewen3@motorola.com> Reviewed-on: https://gerrit.mot.com/1196381 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Zhengming Yao <yaozm1@lenovo.com> Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
de28d59ec4
commit
87709cb9cd
10 changed files with 3016 additions and 0 deletions
|
|
@ -65,3 +65,9 @@ LOCAL_MODULE := snd_soc_tfa9874.ko
|
|||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := tas2560.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ EXTRA_CFLAGS += -I$(TOP)/kernel/techpack/audio/include/uapi
|
|||
endif
|
||||
|
||||
EXTRA_CFLAGS += -DCONFIG_SND_SOC_AOV_TRIGGER -DCONFIG_SND_SOC_OPALUM
|
||||
EXTRA_CFLAGS += -DCONFIG_TAS2560_REGMAP -DCONFIG_TAS2560_CODEC -DCONFIG_TAS2560_MISC
|
||||
|
||||
ifeq ($(KDIR),)
|
||||
PLMA_HOSTSW_DIR=$(realpath -f $(srctree)/$(src))
|
||||
|
|
@ -67,3 +68,6 @@ EXTRA_CFLAGS += -DTFA_DEBUG -DDEBUG
|
|||
snd_soc_tfa9874-objs += tfa_debug.o
|
||||
endif
|
||||
obj-m += snd_soc_tfa9874.o
|
||||
|
||||
tas2560-objs = tas2560-core.o tas2560-misc.o tas2560-codec.o tas2560-regmap.o
|
||||
obj-m += tas2560.o
|
||||
|
|
|
|||
510
sound/soc/codecs/tas2560-codec.c
Normal file
510
sound/soc/codecs/tas2560-codec.c
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
** =============================================================================
|
||||
** Copyright (c) 2016 Texas Instruments Inc.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** File:
|
||||
** tas2560-codec.c
|
||||
**
|
||||
** Description:
|
||||
** ALSA SoC driver for Texas Instruments TAS2560 High Performance 4W Smart Amplifier
|
||||
**
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_TAS2560_CODEC
|
||||
|
||||
#define DEBUG
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "tas2560.h"
|
||||
#include "tas2560-core.h"
|
||||
|
||||
#define TAS2560_MDELAY 0xFFFFFFFE
|
||||
#define KCONTROL_CODEC
|
||||
|
||||
static unsigned int tas2560_codec_read(struct snd_soc_codec *codec, unsigned int reg)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int value = 0;
|
||||
int ret;
|
||||
|
||||
ret = pTAS2560->read(pTAS2560, reg, &value);
|
||||
if (ret >= 0)
|
||||
return value;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2560_codec_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
return pTAS2560->write(pTAS2560, reg, value);
|
||||
}
|
||||
|
||||
static int tas2560_codec_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
pTAS2560->runtime_suspend(pTAS2560);
|
||||
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2560_codec_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
pTAS2560->runtime_resume(pTAS2560);
|
||||
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2560_AIF_post_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
/* struct snd_soc_codec *codec = w->codec; */
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
dev_dbg(pTAS2560->dev, "SND_SOC_DAPM_POST_PMU");
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
dev_dbg(pTAS2560->dev, "SND_SOC_DAPM_POST_PMD");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget tas2560_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_AIF_IN_E("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0,
|
||||
tas2560_AIF_post_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_OUT_DRV("ClassD", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_OUTPUT("OUT")
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route tas2560_audio_map[] = {
|
||||
{"DAC", NULL, "ASI1"},
|
||||
{"ClassD", NULL, "DAC"},
|
||||
{"OUT", NULL, "ClassD"},
|
||||
{"DAC", NULL, "PLL"},
|
||||
};
|
||||
|
||||
static int tas2560_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tas2560_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static int tas2560_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
dev_dbg(pTAS2560->dev, "%s, %d\n", __func__, mute);
|
||||
tas2560_enable(pTAS2560, !mute);
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2560_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 tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s, format=0x%x\n", __func__, fmt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops tas2560_dai_ops = {
|
||||
.startup = tas2560_startup,
|
||||
.shutdown = tas2560_shutdown,
|
||||
.digital_mute = tas2560_mute,
|
||||
.hw_params = tas2560_hw_params,
|
||||
.prepare = tas2560_prepare,
|
||||
.set_sysclk = tas2560_set_dai_sysclk,
|
||||
.set_fmt = tas2560_set_dai_fmt,
|
||||
};
|
||||
|
||||
#define TAS2560_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
static struct snd_soc_dai_driver tas2560_dai_driver[] = {
|
||||
{
|
||||
.name = "tas2560 ASI1",
|
||||
.id = 0,
|
||||
.playback = {
|
||||
.stream_name = "ASI1 Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = TAS2560_FORMATS,
|
||||
},
|
||||
.ops = &tas2560_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int tas2560_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_get_load(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pUcontrol)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(pCodec);
|
||||
|
||||
pUcontrol->value.integer.value[0] = pTAS2560->mnLoad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_set_load(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pUcontrol)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(pCodec);
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
pTAS2560->mnLoad = pUcontrol->value.integer.value[0];
|
||||
dev_dbg(pCodec->dev, "%s:load = 0x%x\n", __func__,
|
||||
pTAS2560->mnLoad);
|
||||
tas2560_setLoad(pTAS2560, pTAS2560->mnLoad);
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_get_Sampling_Rate(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pUcontrol)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(pCodec);
|
||||
|
||||
pUcontrol->value.integer.value[0] = pTAS2560->mnSamplingRate;
|
||||
dev_dbg(pCodec->dev, "%s: %d\n", __func__,
|
||||
pTAS2560->mnSamplingRate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_set_Sampling_Rate(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pUcontrol)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(pCodec);
|
||||
int sampleRate = pUcontrol->value.integer.value[0];
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
dev_dbg(pCodec->dev, "%s: %d\n", __func__, sampleRate);
|
||||
tas2560_set_SampleRate(pTAS2560, sampleRate);
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_power_ctrl_get(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pValue)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
pValue->value.integer.value[0] = pTAS2560->mbPowerUp;
|
||||
dev_dbg(codec->dev, "tas2560_power_ctrl_get = 0x%x\n",
|
||||
pTAS2560->mbPowerUp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_power_ctrl_put(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pValue)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
int bPowerUp = pValue->value.integer.value[0];
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
tas2560_enable(pTAS2560, bPowerUp);
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_ear_switch_get(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *pCodec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *pCodec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(pCodec);
|
||||
|
||||
ucontrol->value.integer.value[0] = pTAS2560->enablePmicEarPath;
|
||||
dev_dbg(pCodec->dev, "%s: ear_switch_get = %d\n", __func__, (int)(pTAS2560->enablePmicEarPath));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_ear_switch_set(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]);
|
||||
|
||||
pTAS2560->enablePmicEarPath = (ucontrol->value.integer.value[0] ? true : false);
|
||||
|
||||
if (!gpio_is_valid(pTAS2560->mnSwitchGPIO)) {
|
||||
dev_dbg(codec->dev, "%s: Invalid gpio: %d\n", __func__, pTAS2560->mnSwitchGPIO);
|
||||
return false;
|
||||
}
|
||||
|
||||
gpio_set_value_cansleep(pTAS2560->mnSwitchGPIO, pTAS2560->enablePmicEarPath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tas2560_ppg_ctrl_get(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pValue)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
pValue->value.integer.value[0] = tas2560_get_PPG(pTAS2560);
|
||||
dev_dbg(codec->dev, "tas2560_ppg_ctrl_get = 0x%x\n",
|
||||
pTAS2560->mnPPG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_ppg_ctrl_put(struct snd_kcontrol *pKcontrol,
|
||||
struct snd_ctl_elem_value *pValue)
|
||||
{
|
||||
#ifdef KCONTROL_CODEC
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
|
||||
#else
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
|
||||
#endif
|
||||
struct tas2560_priv *pTAS2560 = snd_soc_codec_get_drvdata(codec);
|
||||
int mnPPG = pValue->value.integer.value[0];
|
||||
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
tas2560_set_PPG(pTAS2560, mnPPG);
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *load_text[] = {"8_Ohm", "6_Ohm", "4_Ohm"};
|
||||
|
||||
static const struct soc_enum load_enum[] = {
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(load_text), load_text),
|
||||
};
|
||||
|
||||
static const char *Sampling_Rate_text[] = {"48_khz", "44.1_khz", "16_khz", "8_khz"};
|
||||
|
||||
static const struct soc_enum Sampling_Rate_enum[] = {
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(Sampling_Rate_text), Sampling_Rate_text),
|
||||
};
|
||||
|
||||
static const char * const tas2560_ear_switch_ctrl_text[] = {"DISABLE", "ENABLE"};
|
||||
static const struct soc_enum tas2560_ear_switch_ctl_enum[] = {
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tas2560_ear_switch_ctrl_text), tas2560_ear_switch_ctrl_text),
|
||||
};
|
||||
|
||||
/*
|
||||
* DAC digital volumes. From 0 to 15 dB in 1 dB steps
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(dac_tlv, 0, 100, 0);
|
||||
|
||||
static const struct snd_kcontrol_new tas2560_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("DAC Playback Volume", TAS2560_SPK_CTRL_REG, 0, 0x0f, 0,
|
||||
dac_tlv),
|
||||
SOC_ENUM_EXT("TAS2560 Boost load", load_enum[0],
|
||||
tas2560_get_load, tas2560_set_load),
|
||||
SOC_ENUM_EXT("TAS2560 Sampling Rate", Sampling_Rate_enum[0],
|
||||
tas2560_get_Sampling_Rate, tas2560_set_Sampling_Rate),
|
||||
SOC_SINGLE_EXT("TAS2560 PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0,
|
||||
tas2560_power_ctrl_get, tas2560_power_ctrl_put),
|
||||
SOC_ENUM_EXT("TAS2560 EAR Switch", tas2560_ear_switch_ctl_enum[0], tas2560_ear_switch_get, tas2560_ear_switch_set),
|
||||
SOC_SINGLE_EXT("TAS2560 PPG", SND_SOC_NOPM, 0, 0x006E, 0,
|
||||
tas2560_ppg_ctrl_get, tas2560_ppg_ctrl_put),
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_driver_tas2560 = {
|
||||
.probe = tas2560_codec_probe,
|
||||
.remove = tas2560_codec_remove,
|
||||
.read = tas2560_codec_read,
|
||||
.write = tas2560_codec_write,
|
||||
.suspend = tas2560_codec_suspend,
|
||||
.resume = tas2560_codec_resume,
|
||||
.component_driver = {
|
||||
.controls = tas2560_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(tas2560_snd_controls),
|
||||
.dapm_widgets = tas2560_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tas2560_dapm_widgets),
|
||||
.dapm_routes = tas2560_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(tas2560_audio_map),
|
||||
},
|
||||
};
|
||||
|
||||
int tas2560_register_codec(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
dev_info(pTAS2560->dev, "%s, enter\n", __func__);
|
||||
nResult = snd_soc_register_codec(pTAS2560->dev,
|
||||
&soc_codec_driver_tas2560,
|
||||
tas2560_dai_driver, ARRAY_SIZE(tas2560_dai_driver));
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
int tas2560_deregister_codec(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
snd_soc_unregister_codec(pTAS2560->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments Inc.");
|
||||
MODULE_DESCRIPTION("TAS2560 ALSA SOC Smart Amplifier driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
#endif /* CONFIG_TAS2560_CODEC */
|
||||
30
sound/soc/codecs/tas2560-codec.h
Normal file
30
sound/soc/codecs/tas2560-codec.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
** =============================================================================
|
||||
** Copyright (c) 2016 Texas Instruments Inc.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** File:
|
||||
** tas2560-codec.h
|
||||
**
|
||||
** Description:
|
||||
** header file for tas2560-codec.c
|
||||
**
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef _TAS2560_CODEC_H
|
||||
#define _TAS2560_CODEC_H
|
||||
|
||||
#include "tas2560.h"
|
||||
|
||||
int tas2560_register_codec(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_deregister_codec(struct tas2560_priv *pTAS2560);
|
||||
|
||||
#endif /* _TAS2560_CODEC_H */
|
||||
1053
sound/soc/codecs/tas2560-core.c
Normal file
1053
sound/soc/codecs/tas2560-core.c
Normal file
File diff suppressed because it is too large
Load diff
45
sound/soc/codecs/tas2560-core.h
Normal file
45
sound/soc/codecs/tas2560-core.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
** =============================================================================
|
||||
** Copyright (c) 2016 Texas Instruments Inc.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** File:
|
||||
** tas2560-core.h
|
||||
**
|
||||
** Description:
|
||||
** header file for tas2560-core.c
|
||||
**
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef _TAS2560_CORE_H
|
||||
#define _TAS2560_CORE_H
|
||||
|
||||
#include "tas2560.h"
|
||||
|
||||
int tas2560_set_bit_rate(struct tas2560_priv *pTAS2560, unsigned int nBitRate);
|
||||
int tas2560_get_bit_rate(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_set_ASI_fmt(struct tas2560_priv *pTAS2560, unsigned int fmt);
|
||||
int tas2560_setLoad(struct tas2560_priv *pTAS2560, int load);
|
||||
int tas2560_getLoad(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_get_volume(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_set_volume(struct tas2560_priv *pTAS2560, int volume);
|
||||
int tas2560_set_SampleRate(struct tas2560_priv *pTAS2560, unsigned int nSamplingRate);
|
||||
int tas2560_setupPLL(struct tas2560_priv *pTAS2560, int pll_clkin);
|
||||
int tas2560_set_pll_clkin(struct tas2560_priv *pTAS2560, int clk_id, unsigned int freq);
|
||||
int tas2560_parse_dt(struct device *dev, struct tas2560_priv *pTAS2560);
|
||||
void tas2560_sw_shutdown(struct tas2560_priv *pTAS2560, int sw_shutdown);
|
||||
void tas2560_enable(struct tas2560_priv *pTAS2560, bool bEnable);
|
||||
int tas2560_load_default(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_load_platdata(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_LoadConfig(struct tas2560_priv *pTAS2560, bool bPowerOn);
|
||||
int tas2560_get_PPG(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_set_PPG(struct tas2560_priv *pTAS2560, int ppgvolume);
|
||||
#endif /* _TAS2560_CORE_H */
|
||||
438
sound/soc/codecs/tas2560-misc.c
Normal file
438
sound/soc/codecs/tas2560-misc.c
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
** =============================================================================
|
||||
** Copyright (c) 2016 Texas Instruments Inc.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
** File:
|
||||
** tas2560-misc.c
|
||||
**
|
||||
** Description:
|
||||
** misc driver for Texas Instruments TAS2560 High Performance 4W Smart Amplifier
|
||||
**
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_TAS2560_MISC
|
||||
|
||||
#define DEBUG
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "tas2560.h"
|
||||
#include "tas2560-core.h"
|
||||
#include "tas2560-misc.h"
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
|
||||
static int g_logEnable = 1;
|
||||
static struct tas2560_priv *g_tas2560;
|
||||
|
||||
static int tas2560_file_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = g_tas2560;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -ENODEV;
|
||||
|
||||
file->private_data = (void *)pTAS2560;
|
||||
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev, "%s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_file_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = (struct tas2560_priv *)file->private_data;
|
||||
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
file->private_data = (void *)NULL;
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t tas2560_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = (struct tas2560_priv *)file->private_data;
|
||||
int ret = 0;
|
||||
unsigned int nValue = 0;
|
||||
unsigned char value = 0;
|
||||
unsigned char *p_kBuf = NULL;
|
||||
|
||||
mutex_lock(&pTAS2560->file_lock);
|
||||
|
||||
switch (pTAS2560->mnDBGCmd) {
|
||||
case TIAUDIO_CMD_REG_READ:
|
||||
{
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_REG_READ: current_reg = 0x%x, count=%d\n",
|
||||
pTAS2560->mnCurrentReg, (int)count);
|
||||
if (count == 1) {
|
||||
ret = pTAS2560->read(pTAS2560, pTAS2560->mnCurrentReg, &nValue);
|
||||
if (ret < 0) {
|
||||
dev_err(pTAS2560->dev, "dev read fail %d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
value = (u8)nValue;
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev, "TIAUDIO_CMD_REG_READ: nValue=0x%x, value=0x%x\n",
|
||||
nValue, value);
|
||||
ret = copy_to_user(buf, &value, 1);
|
||||
if (ret != 0) {
|
||||
/* Failed to copy all the data, exit */
|
||||
dev_err(pTAS2560->dev, "copy to user fail %d\n", ret);
|
||||
}
|
||||
} else if (count > 1) {
|
||||
p_kBuf = kzalloc(count, GFP_KERNEL);
|
||||
if (p_kBuf != NULL) {
|
||||
ret = pTAS2560->bulk_read(pTAS2560, pTAS2560->mnCurrentReg, p_kBuf, count);
|
||||
if (ret < 0) {
|
||||
dev_err(pTAS2560->dev, "dev bulk read fail %d\n", ret);
|
||||
} else {
|
||||
ret = copy_to_user(buf, p_kBuf, count);
|
||||
if (ret != 0) {
|
||||
/* Failed to copy all the data, exit */
|
||||
dev_err(pTAS2560->dev, "copy to user fail %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(p_kBuf);
|
||||
} else {
|
||||
dev_err(pTAS2560->dev, "read no mem\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_SAMPLERATE:
|
||||
{
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_SAMPLERATE: count = %d\n",
|
||||
(int)count);
|
||||
if (count == 4) {
|
||||
p_kBuf = kzalloc(count, GFP_KERNEL);
|
||||
if (p_kBuf != NULL) {
|
||||
p_kBuf[0] = (pTAS2560->mnSamplingRate&0x000000ff);
|
||||
p_kBuf[1] = ((pTAS2560->mnSamplingRate&0x0000ff00)>>8);
|
||||
p_kBuf[2] = ((pTAS2560->mnSamplingRate&0x00ff0000)>>16);
|
||||
p_kBuf[3] = ((pTAS2560->mnSamplingRate&0xff000000)>>24);
|
||||
|
||||
ret = copy_to_user(buf, p_kBuf, count);
|
||||
if (ret != 0) {
|
||||
/* Failed to copy all the data, exit */
|
||||
dev_err(pTAS2560->dev, "copy to user fail %d\n", ret);
|
||||
}
|
||||
|
||||
kfree(p_kBuf);
|
||||
} else {
|
||||
dev_err(pTAS2560->dev, "read no mem\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_BITRATE:
|
||||
{
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_BITRATE: count = %d\n",
|
||||
(int)count);
|
||||
|
||||
if (count == 1) {
|
||||
int bitRate = tas2560_get_bit_rate(pTAS2560);
|
||||
|
||||
if (bitRate >= 0) {
|
||||
ret = copy_to_user(buf, &bitRate, 1);
|
||||
if (ret != 0) {
|
||||
/* Failed to copy all the data, exit */
|
||||
dev_err(pTAS2560->dev, "copy to user fail %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_DACVOLUME:
|
||||
{
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_DACVOLUME: count = %d\n",
|
||||
(int)count);
|
||||
|
||||
if (count == 1) {
|
||||
int volume = tas2560_get_volume(pTAS2560);
|
||||
|
||||
if (volume >= 0) {
|
||||
ret = copy_to_user(buf, &volume, 1);
|
||||
if (ret != 0) {
|
||||
/* Failed to copy all the data, exit */
|
||||
dev_err(pTAS2560->dev, "copy to user fail %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
pTAS2560->mnDBGCmd = 0;
|
||||
|
||||
mutex_unlock(&pTAS2560->file_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t tas2560_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = (struct tas2560_priv *)file->private_data;
|
||||
int ret = 0;
|
||||
unsigned char *p_kBuf = NULL;
|
||||
unsigned int reg = 0;
|
||||
unsigned int len = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->file_lock);
|
||||
|
||||
p_kBuf = kzalloc(count, GFP_KERNEL);
|
||||
if (p_kBuf == NULL) {
|
||||
dev_err(pTAS2560->dev, "write no mem\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = copy_from_user(p_kBuf, buf, count);
|
||||
if (ret != 0) {
|
||||
dev_err(pTAS2560->dev, "copy_from_user failed.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pTAS2560->mnDBGCmd = p_kBuf[0];
|
||||
switch (pTAS2560->mnDBGCmd) {
|
||||
case TIAUDIO_CMD_REG_WITE:
|
||||
if (count > 5) {
|
||||
reg = ((unsigned int)p_kBuf[1] << 24) +
|
||||
((unsigned int)p_kBuf[2] << 16) +
|
||||
((unsigned int)p_kBuf[3] << 8) +
|
||||
(unsigned int)p_kBuf[4];
|
||||
len = count - 5;
|
||||
if (len == 1) {
|
||||
ret = pTAS2560->write(pTAS2560, reg, p_kBuf[5]);
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_REG_WITE, Reg=0x%x, Val=0x%x\n",
|
||||
reg, p_kBuf[5]);
|
||||
} else {
|
||||
ret = pTAS2560->bulk_write(pTAS2560, reg, &p_kBuf[5], len);
|
||||
}
|
||||
} else {
|
||||
dev_err(pTAS2560->dev, "%s, write len fail, count=%d.\n",
|
||||
__func__, (int)count);
|
||||
}
|
||||
pTAS2560->mnDBGCmd = 0;
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_REG_READ:
|
||||
if (count == 5) {
|
||||
pTAS2560->mnCurrentReg = ((unsigned int)p_kBuf[1] << 24) +
|
||||
((unsigned int)p_kBuf[2] << 16) +
|
||||
((unsigned int)p_kBuf[3] << 8) +
|
||||
(unsigned int)p_kBuf[4];
|
||||
if (g_logEnable) {
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_REG_READ, whole=0x%x\n",
|
||||
pTAS2560->mnCurrentReg);
|
||||
}
|
||||
} else {
|
||||
dev_err(pTAS2560->dev, "read len fail.\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_DEBUG_ON:
|
||||
{
|
||||
if (count == 2) {
|
||||
g_logEnable = p_kBuf[1];
|
||||
}
|
||||
pTAS2560->mnDBGCmd = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_SAMPLERATE:
|
||||
{
|
||||
if (count == 5) {
|
||||
unsigned int nSampleRate = ((unsigned int)p_kBuf[1] << 24) +
|
||||
((unsigned int)p_kBuf[2] << 16) +
|
||||
((unsigned int)p_kBuf[3] << 8) +
|
||||
(unsigned int)p_kBuf[4];
|
||||
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_SAMPLERATE, set to %d\n",
|
||||
nSampleRate);
|
||||
|
||||
tas2560_set_SampleRate(pTAS2560, nSampleRate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_BITRATE:
|
||||
{
|
||||
if (count == 2) {
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_BITRATE, set to %d\n",
|
||||
p_kBuf[1]);
|
||||
|
||||
tas2560_set_bit_rate(pTAS2560, p_kBuf[1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_DACVOLUME:
|
||||
{
|
||||
if (count == 2) {
|
||||
unsigned char volume = (p_kBuf[1] & 0x0f);
|
||||
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_DACVOLUME, set to %d\n",
|
||||
volume);
|
||||
|
||||
tas2560_set_volume(pTAS2560, volume);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIAUDIO_CMD_SPEAKER:
|
||||
{
|
||||
if (count == 2) {
|
||||
if (g_logEnable)
|
||||
dev_info(pTAS2560->dev,
|
||||
"TIAUDIO_CMD_SPEAKER, set to %d\n",
|
||||
p_kBuf[1]);
|
||||
tas2560_enable(pTAS2560, (p_kBuf[1] > 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pTAS2560->mnDBGCmd = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
err:
|
||||
if (p_kBuf != NULL)
|
||||
kfree(p_kBuf);
|
||||
|
||||
mutex_unlock(&pTAS2560->file_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static long tas2560_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = file->private_data;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->file_lock);
|
||||
|
||||
switch (cmd) {
|
||||
case SMARTPA_SPK_DAC_VOLUME:
|
||||
{
|
||||
u8 volume = (arg & 0x0f);
|
||||
|
||||
tas2560_set_volume(pTAS2560, volume);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMARTPA_SPK_POWER_ON:
|
||||
{
|
||||
tas2560_enable(pTAS2560, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMARTPA_SPK_POWER_OFF:
|
||||
{
|
||||
tas2560_enable(pTAS2560, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMARTPA_SPK_SET_SAMPLERATE:
|
||||
{
|
||||
tas2560_set_SampleRate(pTAS2560, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMARTPA_SPK_SET_BITRATE:
|
||||
{
|
||||
tas2560_set_bit_rate(pTAS2560, arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&pTAS2560->file_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = tas2560_file_read,
|
||||
.write = tas2560_file_write,
|
||||
.unlocked_ioctl = tas2560_file_unlocked_ioctl,
|
||||
.open = tas2560_file_open,
|
||||
.release = tas2560_file_release,
|
||||
};
|
||||
|
||||
#define MODULE_NAME "tas2560"
|
||||
static struct miscdevice tas2560_misc = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = MODULE_NAME,
|
||||
.fops = &fops,
|
||||
};
|
||||
|
||||
int tas2560_register_misc(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
g_tas2560 = pTAS2560;
|
||||
ret = misc_register(&tas2560_misc);
|
||||
if (ret) {
|
||||
dev_err(pTAS2560->dev, "TAS2560 misc fail: %d\n", ret);
|
||||
}
|
||||
|
||||
dev_info(pTAS2560->dev, "%s, leave\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tas2560_deregister_misc(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
misc_deregister(&tas2560_misc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments Inc.");
|
||||
MODULE_DESCRIPTION("TAS2560 Misc Smart Amplifier driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
#endif /* CONFIG_TAS2560_MISC */
|
||||
45
sound/soc/codecs/tas2560-misc.h
Normal file
45
sound/soc/codecs/tas2560-misc.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
** =============================================================================
|
||||
** Copyright (c) 2016 Texas Instruments Inc.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** File:
|
||||
** tas2560-misc.h
|
||||
**
|
||||
** Description:
|
||||
** header file for tas2560-misc.c
|
||||
**
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef _TAS2560_MISC_H
|
||||
#define _TAS2560_MISC_H
|
||||
|
||||
#define TIAUDIO_CMD_REG_WITE 1
|
||||
#define TIAUDIO_CMD_REG_READ 2
|
||||
#define TIAUDIO_CMD_DEBUG_ON 3
|
||||
#define TIAUDIO_CMD_CALIBRATION 7
|
||||
#define TIAUDIO_CMD_SAMPLERATE 8
|
||||
#define TIAUDIO_CMD_BITRATE 9
|
||||
#define TIAUDIO_CMD_DACVOLUME 10
|
||||
#define TIAUDIO_CMD_SPEAKER 11
|
||||
|
||||
#define TAS2560_MAGIC_NUMBER 'M' /* '2560' */
|
||||
|
||||
#define SMARTPA_SPK_DAC_VOLUME _IOWR(TAS2560_MAGIC_NUMBER, 1, unsigned long)
|
||||
#define SMARTPA_SPK_POWER_ON _IOWR(TAS2560_MAGIC_NUMBER, 2, unsigned long)
|
||||
#define SMARTPA_SPK_POWER_OFF _IOWR(TAS2560_MAGIC_NUMBER, 3, unsigned long)
|
||||
#define SMARTPA_SPK_SET_SAMPLERATE _IOWR(TAS2560_MAGIC_NUMBER, 7, unsigned long)
|
||||
#define SMARTPA_SPK_SET_BITRATE _IOWR(TAS2560_MAGIC_NUMBER, 8, unsigned long)
|
||||
|
||||
int tas2560_register_misc(struct tas2560_priv *pTAS2560);
|
||||
int tas2560_deregister_misc(struct tas2560_priv *pTAS2560);
|
||||
|
||||
#endif /* _TAS2560_MISC_H */
|
||||
662
sound/soc/codecs/tas2560-regmap.c
Normal file
662
sound/soc/codecs/tas2560-regmap.c
Normal file
|
|
@ -0,0 +1,662 @@
|
|||
/*
|
||||
* ALSA SoC Texas Instruments TAS2560 High Performance 4W Smart Amplifier
|
||||
*
|
||||
* Copyright (C) 2016 Texas Instruments, Inc.
|
||||
*
|
||||
* Author: saiprasad
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifdef CONFIG_TAS2560_REGMAP
|
||||
|
||||
#define DEBUG
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "tas2560.h"
|
||||
#include "tas2560-core.h"
|
||||
#include "tas2560-misc.h"
|
||||
#include "tas2560-codec.h"
|
||||
|
||||
static int tas2560_change_book_page(struct tas2560_priv *pTAS2560,
|
||||
int book, int page)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
if ((pTAS2560->mnCurrentBook == book)
|
||||
&& (pTAS2560->mnCurrentPage == page))
|
||||
goto end;
|
||||
|
||||
if (pTAS2560->mnCurrentBook != book) {
|
||||
nResult = regmap_write(pTAS2560->regmap, TAS2560_BOOKCTL_PAGE, 0);
|
||||
if (nResult < 0) {
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
goto end;
|
||||
}
|
||||
pTAS2560->mnCurrentPage = 0;
|
||||
nResult = regmap_write(pTAS2560->regmap, TAS2560_BOOKCTL_REG, book);
|
||||
if (nResult < 0) {
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
goto end;
|
||||
}
|
||||
pTAS2560->mnCurrentBook = book;
|
||||
}
|
||||
|
||||
if (pTAS2560->mnCurrentPage != page) {
|
||||
nResult = regmap_write(pTAS2560->regmap, TAS2560_BOOKCTL_PAGE, page);
|
||||
if (nResult < 0) {
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
goto end;
|
||||
}
|
||||
pTAS2560->mnCurrentPage = page;
|
||||
}
|
||||
|
||||
end:
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static int tas2560_dev_read(struct tas2560_priv *pTAS2560,
|
||||
unsigned int reg, unsigned int *pValue)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->dev_lock);
|
||||
|
||||
nResult = tas2560_change_book_page(pTAS2560,
|
||||
TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg));
|
||||
if (nResult < 0)
|
||||
goto end;
|
||||
|
||||
nResult = regmap_read(pTAS2560->regmap, TAS2560_PAGE_REG(reg), pValue);
|
||||
if (nResult < 0)
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
else
|
||||
dev_dbg(pTAS2560->dev, "%s: BOOK:PAGE:REG %u:%u:%u\n", __func__,
|
||||
TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg),
|
||||
TAS2560_PAGE_REG(reg));
|
||||
|
||||
end:
|
||||
mutex_unlock(&pTAS2560->dev_lock);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static int tas2560_dev_write(struct tas2560_priv *pTAS2560,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->dev_lock);
|
||||
|
||||
nResult = tas2560_change_book_page(pTAS2560,
|
||||
TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg));
|
||||
if (nResult < 0)
|
||||
goto end;
|
||||
|
||||
nResult = regmap_write(pTAS2560->regmap, TAS2560_PAGE_REG(reg),
|
||||
value);
|
||||
if (nResult < 0)
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
else
|
||||
dev_dbg(pTAS2560->dev, "%s: BOOK:PAGE:REG %u:%u:%u, VAL: 0x%02x\n",
|
||||
__func__, TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg),
|
||||
TAS2560_PAGE_REG(reg), value);
|
||||
|
||||
end:
|
||||
mutex_unlock(&pTAS2560->dev_lock);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static int tas2560_dev_bulk_write(struct tas2560_priv *pTAS2560,
|
||||
unsigned int reg, unsigned char *pData, unsigned int nLength)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->dev_lock);
|
||||
|
||||
nResult = tas2560_change_book_page(pTAS2560,
|
||||
TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg));
|
||||
if (nResult < 0)
|
||||
goto end;
|
||||
|
||||
nResult = regmap_bulk_write(pTAS2560->regmap,
|
||||
TAS2560_PAGE_REG(reg), pData, nLength);
|
||||
if (nResult < 0)
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
else
|
||||
dev_dbg(pTAS2560->dev, "%s: BOOK:PAGE:REG %u:%u:%u, len: 0x%02x\n",
|
||||
__func__, TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg),
|
||||
TAS2560_PAGE_REG(reg), nLength);
|
||||
|
||||
end:
|
||||
mutex_unlock(&pTAS2560->dev_lock);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static int tas2560_dev_bulk_read(struct tas2560_priv *pTAS2560,
|
||||
unsigned int reg, unsigned char *pData, unsigned int nLength)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->dev_lock);
|
||||
|
||||
nResult = tas2560_change_book_page(pTAS2560,
|
||||
TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg));
|
||||
if (nResult < 0)
|
||||
goto end;
|
||||
|
||||
nResult = regmap_bulk_read(pTAS2560->regmap, TAS2560_PAGE_REG(reg), pData, nLength);
|
||||
if (nResult < 0)
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
else
|
||||
dev_dbg(pTAS2560->dev, "%s: BOOK:PAGE:REG %u:%u:%u, len: 0x%02x\n",
|
||||
__func__, TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg),
|
||||
TAS2560_PAGE_REG(reg), nLength);
|
||||
end:
|
||||
mutex_unlock(&pTAS2560->dev_lock);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static int tas2560_dev_update_bits(struct tas2560_priv *pTAS2560, unsigned int reg,
|
||||
unsigned int mask, unsigned int value)
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
mutex_lock(&pTAS2560->dev_lock);
|
||||
nResult = tas2560_change_book_page(pTAS2560,
|
||||
TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg));
|
||||
if (nResult < 0)
|
||||
goto end;
|
||||
|
||||
nResult = regmap_update_bits(pTAS2560->regmap, TAS2560_PAGE_REG(reg), mask, value);
|
||||
if (nResult < 0)
|
||||
dev_err(pTAS2560->dev, "%s, ERROR, L=%d, E=%d\n",
|
||||
__func__, __LINE__, nResult);
|
||||
else
|
||||
dev_dbg(pTAS2560->dev, "%s: BOOK:PAGE:REG %u:%u:%u, mask: 0x%x, val=0x%x\n",
|
||||
__func__, TAS2560_BOOK_ID(reg), TAS2560_PAGE_ID(reg),
|
||||
TAS2560_PAGE_REG(reg), mask, value);
|
||||
end:
|
||||
mutex_unlock(&pTAS2560->dev_lock);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static bool tas2560_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tas2560_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct regmap_config tas2560_i2c_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = tas2560_writeable,
|
||||
.volatile_reg = tas2560_volatile,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.max_register = 128,
|
||||
};
|
||||
|
||||
static void tas2560_hw_reset(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
if (gpio_is_valid(pTAS2560->mnResetGPIO)) {
|
||||
gpio_direction_output(pTAS2560->mnResetGPIO, 0);
|
||||
msleep(5);
|
||||
gpio_direction_output(pTAS2560->mnResetGPIO, 1);
|
||||
msleep(2);
|
||||
}
|
||||
|
||||
pTAS2560->mnCurrentBook = -1;
|
||||
pTAS2560->mnCurrentPage = -1;
|
||||
}
|
||||
|
||||
void tas2560_clearIRQ(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
unsigned int nValue;
|
||||
int nResult = 0;
|
||||
|
||||
nResult = pTAS2560->read(pTAS2560, TAS2560_FLAGS_1, &nValue);
|
||||
if (nResult >= 0)
|
||||
pTAS2560->read(pTAS2560, TAS2560_FLAGS_2, &nValue);
|
||||
}
|
||||
|
||||
void tas2560_enableIRQ(struct tas2560_priv *pTAS2560, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
if (pTAS2560->mbIRQEnable)
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(pTAS2560->mnIRQGPIO))
|
||||
enable_irq(pTAS2560->mnIRQ);
|
||||
|
||||
schedule_delayed_work(&pTAS2560->irq_work, msecs_to_jiffies(10));
|
||||
pTAS2560->mbIRQEnable = true;
|
||||
} else {
|
||||
if (!pTAS2560->mbIRQEnable)
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(pTAS2560->mnIRQGPIO))
|
||||
disable_irq_nosync(pTAS2560->mnIRQ);
|
||||
pTAS2560->mbIRQEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void irq_work_routine(struct work_struct *work)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 =
|
||||
container_of(work, struct tas2560_priv, irq_work.work);
|
||||
unsigned int nDevInt1Status = 0, nDevInt2Status = 0;
|
||||
int nCounter = 2;
|
||||
int nResult = 0;
|
||||
|
||||
#ifdef CONFIG_TAS2560_CODEC
|
||||
mutex_lock(&pTAS2560->codec_lock);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TAS2560_MISC
|
||||
mutex_lock(&pTAS2560->file_lock);
|
||||
#endif
|
||||
if (pTAS2560->mbRuntimeSuspend) {
|
||||
dev_info(pTAS2560->dev, "%s, Runtime Suspended\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!pTAS2560->mbPowerUp) {
|
||||
dev_info(pTAS2560->dev, "%s, device not powered\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
nResult = tas2560_dev_write(pTAS2560, TAS2560_INT_GEN_REG, 0x00);
|
||||
if (nResult < 0)
|
||||
goto reload;
|
||||
|
||||
nResult = tas2560_dev_read(pTAS2560, TAS2560_FLAGS_1, &nDevInt1Status);
|
||||
if (nResult >= 0)
|
||||
nResult = tas2560_dev_read(pTAS2560, TAS2560_FLAGS_2, &nDevInt2Status);
|
||||
else
|
||||
goto reload;
|
||||
|
||||
if (((nDevInt1Status & 0xfc) != 0) || ((nDevInt2Status & 0xc0) != 0)) {
|
||||
/* in case of INT_OC, INT_UV, INT_OT, INT_BO, INT_CL, INT_CLK1, INT_CLK2 */
|
||||
dev_dbg(pTAS2560->dev, "IRQ critical Error : 0x%x, 0x%x\n",
|
||||
nDevInt1Status, nDevInt2Status);
|
||||
|
||||
if (nDevInt1Status & 0x80) {
|
||||
pTAS2560->mnErrCode |= ERROR_OVER_CURRENT;
|
||||
dev_err(pTAS2560->dev, "SPK over current!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_OVER_CURRENT;
|
||||
|
||||
if (nDevInt1Status & 0x40) {
|
||||
pTAS2560->mnErrCode |= ERROR_UNDER_VOLTAGE;
|
||||
dev_err(pTAS2560->dev, "SPK under voltage!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_UNDER_VOLTAGE;
|
||||
|
||||
if (nDevInt1Status & 0x20) {
|
||||
pTAS2560->mnErrCode |= ERROR_CLK_HALT;
|
||||
dev_err(pTAS2560->dev, "clk halted!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_CLK_HALT;
|
||||
|
||||
if (nDevInt1Status & 0x10) {
|
||||
pTAS2560->mnErrCode |= ERROR_DIE_OVERTEMP;
|
||||
dev_err(pTAS2560->dev, "die over temperature!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_DIE_OVERTEMP;
|
||||
|
||||
if (nDevInt1Status & 0x08) {
|
||||
pTAS2560->mnErrCode |= ERROR_BROWNOUT;
|
||||
dev_err(pTAS2560->dev, "brownout!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_BROWNOUT;
|
||||
|
||||
if (nDevInt1Status & 0x04) {
|
||||
pTAS2560->mnErrCode |= ERROR_CLK_LOST;
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_CLK_LOST;
|
||||
|
||||
if (nDevInt2Status & 0x80) {
|
||||
pTAS2560->mnErrCode |= ERROR_CLK_DET1;
|
||||
dev_err(pTAS2560->dev, "clk detection 1!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_CLK_DET1;
|
||||
|
||||
if (nDevInt2Status & 0x40) {
|
||||
pTAS2560->mnErrCode |= ERROR_CLK_DET2;
|
||||
dev_err(pTAS2560->dev, "clk detection 2!\n");
|
||||
} else
|
||||
pTAS2560->mnErrCode &= ~ERROR_CLK_DET2;
|
||||
|
||||
goto reload;
|
||||
} else {
|
||||
dev_dbg(pTAS2560->dev, "IRQ status : 0x%x, 0x%x\n",
|
||||
nDevInt1Status, nDevInt2Status);
|
||||
nCounter = 2;
|
||||
|
||||
while (nCounter > 0) {
|
||||
nResult = tas2560_dev_read(pTAS2560, TAS2560_POWER_UP_FLAG_REG, &nDevInt1Status);
|
||||
if (nResult < 0)
|
||||
goto reload;
|
||||
|
||||
if ((nDevInt1Status & 0xc0) == 0xc0)
|
||||
break;
|
||||
|
||||
nCounter--;
|
||||
if (nCounter > 0) {
|
||||
/* in case check pow status just after power on TAS2560 */
|
||||
dev_dbg(pTAS2560->dev, "PowSts B: 0x%x, check again after 10ms\n",
|
||||
nDevInt1Status);
|
||||
msleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
if ((nDevInt1Status & 0xc0) != 0xc0) {
|
||||
dev_err(pTAS2560->dev, "%s, Critical ERROR B[%d]_P[%d]_R[%d]= 0x%x\n",
|
||||
__func__,
|
||||
TAS2560_BOOK_ID(TAS2560_POWER_UP_FLAG_REG),
|
||||
TAS2560_PAGE_ID(TAS2560_POWER_UP_FLAG_REG),
|
||||
TAS2560_PAGE_REG(TAS2560_POWER_UP_FLAG_REG),
|
||||
nDevInt1Status);
|
||||
pTAS2560->mnErrCode |= ERROR_CLASSD_PWR;
|
||||
goto reload;
|
||||
}
|
||||
pTAS2560->mnErrCode &= ~ERROR_CLASSD_PWR;
|
||||
}
|
||||
|
||||
nResult = tas2560_dev_write(pTAS2560, TAS2560_INT_GEN_REG, 0xff);
|
||||
if (nResult < 0)
|
||||
goto reload;
|
||||
|
||||
goto end;
|
||||
|
||||
reload:
|
||||
/* hardware reset and reload */
|
||||
tas2560_LoadConfig(pTAS2560, true);
|
||||
|
||||
end:
|
||||
if (!hrtimer_active(&pTAS2560->mtimer)) {
|
||||
dev_dbg(pTAS2560->dev, "%s, start timer\n", __func__);
|
||||
hrtimer_start(&pTAS2560->mtimer,
|
||||
ns_to_ktime((u64)CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
|
||||
}
|
||||
#ifdef CONFIG_TAS2560_MISC
|
||||
mutex_unlock(&pTAS2560->file_lock);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TAS2560_CODEC
|
||||
mutex_unlock(&pTAS2560->codec_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static enum hrtimer_restart timer_func(struct hrtimer *timer)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = container_of(timer, struct tas2560_priv, mtimer);
|
||||
|
||||
if (pTAS2560->mbPowerUp) {
|
||||
if (!delayed_work_pending(&pTAS2560->irq_work))
|
||||
schedule_delayed_work(&pTAS2560->irq_work, msecs_to_jiffies(20));
|
||||
}
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static irqreturn_t tas2560_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = (struct tas2560_priv *)dev_id;
|
||||
|
||||
tas2560_enableIRQ(pTAS2560, false);
|
||||
|
||||
/* get IRQ status after 100 ms */
|
||||
if (!delayed_work_pending(&pTAS2560->irq_work))
|
||||
schedule_delayed_work(&pTAS2560->irq_work, msecs_to_jiffies(100));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tas2560_runtime_suspend(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
pTAS2560->mbRuntimeSuspend = true;
|
||||
|
||||
if (hrtimer_active(&pTAS2560->mtimer)) {
|
||||
dev_dbg(pTAS2560->dev, "cancel die temp timer\n");
|
||||
hrtimer_cancel(&pTAS2560->mtimer);
|
||||
}
|
||||
|
||||
if (delayed_work_pending(&pTAS2560->irq_work)) {
|
||||
dev_dbg(pTAS2560->dev, "cancel IRQ work\n");
|
||||
cancel_delayed_work_sync(&pTAS2560->irq_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_runtime_resume(struct tas2560_priv *pTAS2560)
|
||||
{
|
||||
dev_dbg(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
if (pTAS2560->mbPowerUp) {
|
||||
if (!hrtimer_active(&pTAS2560->mtimer)) {
|
||||
dev_dbg(pTAS2560->dev, "%s, start check timer\n", __func__);
|
||||
hrtimer_start(&pTAS2560->mtimer,
|
||||
ns_to_ktime((u64)CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
|
||||
pTAS2560->mbRuntimeSuspend = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas2560_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560;
|
||||
int nResult;
|
||||
|
||||
dev_info(&client->dev, "%s enter\n", __func__);
|
||||
|
||||
pTAS2560 = devm_kzalloc(&client->dev, sizeof(struct tas2560_priv), GFP_KERNEL);
|
||||
if (pTAS2560 == NULL) {
|
||||
dev_err(&client->dev, "%s, -ENOMEM \n", __func__);
|
||||
nResult = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pTAS2560->dev = &client->dev;
|
||||
i2c_set_clientdata(client, pTAS2560);
|
||||
dev_set_drvdata(&client->dev, pTAS2560);
|
||||
|
||||
pTAS2560->regmap = devm_regmap_init_i2c(client, &tas2560_i2c_regmap);
|
||||
if (IS_ERR(pTAS2560->regmap)) {
|
||||
nResult = PTR_ERR(pTAS2560->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
nResult);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (client->dev.of_node)
|
||||
tas2560_parse_dt(&client->dev, pTAS2560);
|
||||
|
||||
if (gpio_is_valid(pTAS2560->mnResetGPIO)) {
|
||||
nResult = gpio_request(pTAS2560->mnResetGPIO, "TAS2560_RESET");
|
||||
if (nResult) {
|
||||
dev_err(pTAS2560->dev, "%s: Failed to request gpio %d\n", __func__,
|
||||
pTAS2560->mnResetGPIO);
|
||||
nResult = -EINVAL;
|
||||
goto free_gpio;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pTAS2560->mnSwitchGPIO)) {
|
||||
nResult = gpio_request(pTAS2560->mnSwitchGPIO, "TAS2560_EAR_SWITH");
|
||||
if (nResult) {
|
||||
dev_err(pTAS2560->dev, "%s: Failed to request gpio %d\n", __func__,
|
||||
pTAS2560->mnSwitchGPIO);
|
||||
nResult = -EINVAL;
|
||||
goto free_gpio;
|
||||
}
|
||||
gpio_direction_output(pTAS2560->mnSwitchGPIO, 0);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pTAS2560->mnIRQGPIO)) {
|
||||
nResult = gpio_request(pTAS2560->mnIRQGPIO, "TAS2560-IRQ");
|
||||
if (nResult < 0) {
|
||||
dev_err(pTAS2560->dev, "%s: GPIO %d request error\n",
|
||||
__func__, pTAS2560->mnIRQGPIO);
|
||||
goto free_gpio;
|
||||
}
|
||||
gpio_direction_input(pTAS2560->mnIRQGPIO);
|
||||
pTAS2560->mnIRQ = gpio_to_irq(pTAS2560->mnIRQGPIO);
|
||||
dev_dbg(pTAS2560->dev, "irq = %d\n", pTAS2560->mnIRQ);
|
||||
nResult = request_threaded_irq(pTAS2560->mnIRQ, tas2560_irq_handler,
|
||||
NULL, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
client->name, pTAS2560);
|
||||
if (nResult < 0) {
|
||||
dev_err(pTAS2560->dev,
|
||||
"request_irq failed, %d\n", nResult);
|
||||
goto free_gpio;
|
||||
}
|
||||
disable_irq_nosync(pTAS2560->mnIRQ);
|
||||
INIT_DELAYED_WORK(&pTAS2560->irq_work, irq_work_routine);
|
||||
}
|
||||
|
||||
pTAS2560->read = tas2560_dev_read;
|
||||
pTAS2560->write = tas2560_dev_write;
|
||||
pTAS2560->bulk_read = tas2560_dev_bulk_read;
|
||||
pTAS2560->bulk_write = tas2560_dev_bulk_write;
|
||||
pTAS2560->update_bits = tas2560_dev_update_bits;
|
||||
pTAS2560->hw_reset = tas2560_hw_reset;
|
||||
pTAS2560->enableIRQ = tas2560_enableIRQ;
|
||||
pTAS2560->clearIRQ = tas2560_clearIRQ;
|
||||
pTAS2560->runtime_suspend = tas2560_runtime_suspend;
|
||||
pTAS2560->runtime_resume = tas2560_runtime_resume;
|
||||
mutex_init(&pTAS2560->dev_lock);
|
||||
|
||||
nResult = tas2560_LoadConfig(pTAS2560, false);
|
||||
if (nResult < 0)
|
||||
goto destroy_mutex;
|
||||
|
||||
#ifdef CONFIG_TAS2560_CODEC
|
||||
mutex_init(&pTAS2560->codec_lock);
|
||||
tas2560_register_codec(pTAS2560);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TAS2560_MISC
|
||||
mutex_init(&pTAS2560->file_lock);
|
||||
tas2560_register_misc(pTAS2560);
|
||||
#endif
|
||||
|
||||
hrtimer_init(&pTAS2560->mtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
pTAS2560->mtimer.function = timer_func;
|
||||
|
||||
destroy_mutex:
|
||||
if (nResult < 0)
|
||||
mutex_destroy(&pTAS2560->dev_lock);
|
||||
|
||||
free_gpio:
|
||||
if (nResult < 0) {
|
||||
if (gpio_is_valid(pTAS2560->mnResetGPIO))
|
||||
gpio_free(pTAS2560->mnResetGPIO);
|
||||
if (gpio_is_valid(pTAS2560->mnIRQGPIO))
|
||||
gpio_free(pTAS2560->mnIRQGPIO);
|
||||
if (gpio_is_valid(pTAS2560->mnSwitchGPIO))
|
||||
gpio_free(pTAS2560->mnSwitchGPIO);
|
||||
}
|
||||
|
||||
end:
|
||||
return nResult;
|
||||
}
|
||||
|
||||
static int tas2560_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tas2560_priv *pTAS2560 = i2c_get_clientdata(client);
|
||||
|
||||
dev_info(pTAS2560->dev, "%s\n", __func__);
|
||||
|
||||
#ifdef CONFIG_TAS2560_CODEC
|
||||
tas2560_deregister_codec(pTAS2560);
|
||||
mutex_destroy(&pTAS2560->codec_lock);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TAS2560_MISC
|
||||
tas2560_deregister_misc(pTAS2560);
|
||||
mutex_destroy(&pTAS2560->file_lock);
|
||||
#endif
|
||||
|
||||
if (gpio_is_valid(pTAS2560->mnResetGPIO))
|
||||
gpio_free(pTAS2560->mnResetGPIO);
|
||||
if (gpio_is_valid(pTAS2560->mnIRQGPIO))
|
||||
gpio_free(pTAS2560->mnIRQGPIO);
|
||||
if (gpio_is_valid(pTAS2560->mnSwitchGPIO))
|
||||
gpio_free(pTAS2560->mnSwitchGPIO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct i2c_device_id tas2560_i2c_id[] = {
|
||||
{ "tas2560", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tas2560_i2c_id);
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id tas2560_of_match[] = {
|
||||
{ .compatible = "ti,tas2560" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tas2560_of_match);
|
||||
#endif
|
||||
|
||||
|
||||
static struct i2c_driver tas2560_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tas2560",
|
||||
.owner = THIS_MODULE,
|
||||
#if defined(CONFIG_OF)
|
||||
.of_match_table = of_match_ptr(tas2560_of_match),
|
||||
#endif
|
||||
},
|
||||
.probe = tas2560_i2c_probe,
|
||||
.remove = tas2560_i2c_remove,
|
||||
.id_table = tas2560_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tas2560_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments Inc.");
|
||||
MODULE_DESCRIPTION("TAS2560 I2C Smart Amplifier driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
#endif
|
||||
223
sound/soc/codecs/tas2560.h
Normal file
223
sound/soc/codecs/tas2560.h
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
** =============================================================================
|
||||
** Copyright (c) 2016 Texas Instruments Inc.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** File:
|
||||
** tas2560.h
|
||||
**
|
||||
** Description:
|
||||
** definitions and data structures for TAS2560 Android Linux driver
|
||||
**
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef _TAS2560_H
|
||||
#define _TAS2560_H
|
||||
|
||||
/* Page Control Register */
|
||||
#define TAS2560_PAGECTL_REG 0
|
||||
|
||||
/* Book Control Register (available in page0 of each book) */
|
||||
#define TAS2560_BOOKCTL_PAGE 0
|
||||
#define TAS2560_BOOKCTL_REG 127
|
||||
|
||||
#define TAS2560_REG(book, page, reg) (((book * 256 * 128) + \
|
||||
(page * 128)) + reg)
|
||||
|
||||
#define TAS2560_BOOK_ID(reg) (reg / (256 * 128))
|
||||
#define TAS2560_PAGE_ID(reg) ((reg % (256 * 128)) / 128)
|
||||
#define TAS2560_BOOK_REG(reg) (reg % (256 * 128))
|
||||
#define TAS2560_PAGE_REG(reg) ((reg % (256 * 128)) % 128)
|
||||
|
||||
/* Book0, Page0 registers */
|
||||
#define TAS2560_SW_RESET_REG TAS2560_REG(0, 0, 1)
|
||||
#define TAS2560_DEV_MODE_REG TAS2560_REG(0, 0, 2)
|
||||
#define TAS2560_SPK_CTRL_REG TAS2560_REG(0, 0, 4)
|
||||
#define TAS2560_MUTE_REG TAS2560_REG(0, 0, 7)
|
||||
#define TAS2560_PWR_REG TAS2560_REG(0, 0, 7)
|
||||
#define TAS2560_PWR_BIT_MASK (0x3 << 6)
|
||||
#define TAS2560_MUTE_MASK (0x7)
|
||||
|
||||
#define TAS2560_SR_CTRL1 TAS2560_REG(0, 0, 8)
|
||||
#define TAS2560_LOAD TAS2560_REG(0, 0, 9)
|
||||
#define TAS2560_SR_CTRL2 TAS2560_REG(0, 0, 13) /* B0_P0_R0x0d*/
|
||||
#define TAS2560_SR_CTRL3 TAS2560_REG(0, 0, 14) /* B0_P0_R0x0e*/
|
||||
|
||||
#define TAS2560_CLK_SEL TAS2560_REG(0, 0, 15)
|
||||
#define TAS2560_PLL_SRC_MASK (0xc0)
|
||||
#define TAS2560_PLL_CLKIN_BCLK (0)
|
||||
#define TAS2560_PLL_CLKIN_MCLK (1)
|
||||
#define TAS2560_PLL_CLKIN_PDMCLK (2)
|
||||
#define TAS2560_PLL_P_MASK (0x3f)
|
||||
|
||||
#define TAS2560_SET_FREQ TAS2560_REG(0, 0, 16)
|
||||
#define TAS2560_PLL_J_MASK (0x7f)
|
||||
|
||||
#define TAS2560_PLL_D_MSB TAS2560_REG(0, 0, 17) /*B0_P0_R0x11*/
|
||||
#define TAS2560_PLL_D_LSB TAS2560_REG(0, 0, 18) /*B0_P0_R0x12*/
|
||||
|
||||
#define TAS2560_DAI_FMT TAS2560_REG(0, 0, 20) /*B0_P0_R0x14*/
|
||||
#define TAS2560_ASI_OFFSET_1 TAS2560_REG(0, 0, 22)
|
||||
#define TAS2560_ASI_CFG_1 TAS2560_REG(0, 0, 24) /*B0_P0_R0x18*/
|
||||
#define TAS2560_DIRINV_MASK 0x3c
|
||||
#define TAS2560_BCLKINV (1 << 2)
|
||||
#define TAS2560_WCLKINV (1 << 3)
|
||||
#define TAS2560_BCLKDIR (1 << 4)
|
||||
#define TAS2560_WCLKDIR (1 << 5)
|
||||
|
||||
#define TAS2560_CLK_ERR_CTRL TAS2560_REG(0, 0, 33) /* B0_P0_R0x21 */
|
||||
#define TAS2560_IRQ_PIN_REG TAS2560_REG(0, 0, 35) /* B0_P0_R0x23 */
|
||||
#define TAS2560_INT_MODE_REG TAS2560_REG(0, 0, 36) /* B0_P0_R0x24 */
|
||||
#define TAS2560_INT_GEN_REG TAS2560_REG(0, 0, 37) /* B0_P0_R0x25 */
|
||||
#define TAS2560_FLAGS_1 TAS2560_REG(0, 0, 38) /* B0_P0_R0x26 */
|
||||
#define TAS2560_FLAGS_2 TAS2560_REG(0, 0, 39) /* B0_P0_R0x27 */
|
||||
#define TAS2560_POWER_UP_FLAG_REG TAS2560_REG(0, 0, 42) /* B0_P0_R0x2a */
|
||||
|
||||
#define TAS2560_DR_BOOST_REG_2 TAS2560_REG(0, 0, 60) /* B0_P0_R0x3c */
|
||||
#define TAS2560_DR_BOOST_REG_1 TAS2560_REG(0, 0, 73) /* B0_P0_R0x49 */
|
||||
#define TAS2560_CLK_ERR_CTRL2 TAS2560_REG(0, 0, 80) /* B0_P0_R0x50 */
|
||||
#define TAS2560_ID_REG TAS2560_REG(0, 0, 125)
|
||||
|
||||
/* Book0, Page50 registers */
|
||||
#define TAS2560_PPG TAS2560_REG(0, 50, 12) /*B0_P0x32_R0x0c*/
|
||||
|
||||
#define TAS2560_HPF_CUTOFF_CTL1 TAS2560_REG(0, 50, 28) /* B0_P0x32_R0x1c */
|
||||
#define TAS2560_HPF_CUTOFF_CTL2 TAS2560_REG(0, 50, 32) /* B0_P0x32_R0x20 */
|
||||
#define TAS2560_HPF_CUTOFF_CTL3 TAS2560_REG(0, 50, 36) /* B0_P0x32_R0x24 */
|
||||
|
||||
#define TAS2560_ISENSE_PATH_CTL1 TAS2560_REG(0, 50, 40) /* B0_P0x32_R0x28 */
|
||||
#define TAS2560_ISENSE_PATH_CTL2 TAS2560_REG(0, 50, 44) /* B0_P0x32_R0x2c */
|
||||
#define TAS2560_ISENSE_PATH_CTL3 TAS2560_REG(0, 50, 48) /* B0_P0x32_R0x30 */
|
||||
|
||||
#define TAS2560_VLIMIT_THRESHOLD TAS2560_REG(0, 50, 60)
|
||||
#define TAS2560_IDLE_CHNL_DETECT TAS2560_REG(0, 50, 108) /* B0_P0x32_R0x6c */
|
||||
|
||||
/* Book0, Page51 registers */
|
||||
#define TAS2560_BOOST_HEAD TAS2560_REG(0, 51, 24) /* B0_P0x33_R0x18 */
|
||||
#define TAS2560_BOOST_ON TAS2560_REG(0, 51, 16) /* B0_P0x33_R0x10 */
|
||||
#define TAS2560_BOOST_OFF TAS2560_REG(0, 51, 20) /* B0_P0x33_R0x14 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL1 TAS2560_REG(0, 51, 32) /* B0_P0x33_R0x20 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL2 TAS2560_REG(0, 51, 36) /* B0_P0x33_R0x24 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL3 TAS2560_REG(0, 51, 40) /* B0_P0x33_R0x28 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL4 TAS2560_REG(0, 51, 44) /* B0_P0x33_R0x2c */
|
||||
#define TAS2560_BOOST_TABLE_CTRL5 TAS2560_REG(0, 51, 48) /* B0_P0x33_R0x30 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL6 TAS2560_REG(0, 51, 52) /* B0_P0x33_R0x34 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL7 TAS2560_REG(0, 51, 56) /* B0_P0x33_R0x38 */
|
||||
#define TAS2560_BOOST_TABLE_CTRL8 TAS2560_REG(0, 51, 60) /* B0_P0x33_R0x3c */
|
||||
#define TAS2560_THERMAL_FOLDBACK TAS2560_REG(0, 51, 100) /* B0_P0x33_R0x64 */
|
||||
|
||||
/* Book0, Page52 registers */
|
||||
#define TAS2560_VSENSE_DEL_CTL1 TAS2560_REG(0, 52, 52) /* B0_P0x34_R0x34 */
|
||||
#define TAS2560_VSENSE_DEL_CTL2 TAS2560_REG(0, 52, 56) /* B0_P0x34_R0x38 */
|
||||
#define TAS2560_VSENSE_DEL_CTL3 TAS2560_REG(0, 52, 60) /* B0_P0x34_R0x3c */
|
||||
#define TAS2560_VSENSE_DEL_CTL4 TAS2560_REG(0, 52, 64) /* B0_P0x34_R0x40 */
|
||||
#define TAS2560_VSENSE_DEL_CTL5 TAS2560_REG(0, 52, 68) /* B0_P0x34_R0x44 */
|
||||
|
||||
#define TAS2560_DATAFORMAT_SHIFT 2
|
||||
#define TAS2560_DATAFORMAT_I2S 0x0
|
||||
#define TAS2560_DATAFORMAT_DSP 0x1
|
||||
#define TAS2560_DATAFORMAT_RIGHT_J 0x2
|
||||
#define TAS2560_DATAFORMAT_LEFT_J 0x3
|
||||
|
||||
#define TAS2560_DAI_FMT_MASK (0x7 << TAS2560_DATAFORMAT_SHIFT)
|
||||
|
||||
#define LOAD_MASK 0x18
|
||||
#define LOAD_8OHM (0)
|
||||
#define LOAD_6OHM (1)
|
||||
#define LOAD_4OHM (2)
|
||||
|
||||
#define PLL_BCLK_1P536_48KSR (0)
|
||||
#define PLL_BCLK_3P072_48KSR (1)
|
||||
|
||||
#define CHECK_PERIOD 5000 /* 5 second */
|
||||
|
||||
#define ERROR_NONE 0x00000000
|
||||
#define ERROR_PLL_ABSENT 0x00000001
|
||||
#define ERROR_DEVA_I2C_COMM 0x00000002
|
||||
#define ERROR_DEVB_I2C_COMM 0x00000004
|
||||
#define ERROR_PRAM_CRCCHK 0x00000008
|
||||
#define ERROR_YRAM_CRCCHK 0x00000010
|
||||
#define ERROR_CLK_DET2 0x00000020
|
||||
#define ERROR_CLK_DET1 0x00000040
|
||||
#define ERROR_CLK_LOST 0x00000080
|
||||
#define ERROR_BROWNOUT 0x00000100
|
||||
#define ERROR_DIE_OVERTEMP 0x00000200
|
||||
#define ERROR_CLK_HALT 0x00000400
|
||||
#define ERROR_UNDER_VOLTAGE 0x00000800
|
||||
#define ERROR_OVER_CURRENT 0x00001000
|
||||
#define ERROR_CLASSD_PWR 0x00002000
|
||||
#define ERROR_FAILSAFE 0x40000000
|
||||
|
||||
struct tas2560_register {
|
||||
int book;
|
||||
int page;
|
||||
int reg;
|
||||
};
|
||||
|
||||
struct tas2560_dai_cfg {
|
||||
unsigned int dai_fmt;
|
||||
unsigned int tdm_delay;
|
||||
};
|
||||
|
||||
struct tas2560_priv {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct mutex dev_lock;
|
||||
struct delayed_work irq_work;
|
||||
struct hrtimer mtimer;
|
||||
int mnClkin;
|
||||
int mnClkid;
|
||||
bool mbPowerUp;
|
||||
int mnCurrentBook;
|
||||
int mnCurrentPage;
|
||||
int mnLoad;
|
||||
int mnASIFormat;
|
||||
int mnResetGPIO;
|
||||
int mnIRQGPIO;
|
||||
int mnSwitchGPIO;
|
||||
bool enablePmicEarPath;
|
||||
int mnIRQ;
|
||||
bool mbIRQEnable;
|
||||
int mnSamplingRate;
|
||||
int mnFrameSize;
|
||||
int mnPLL;
|
||||
int mnPPG;
|
||||
|
||||
int (*read)(struct tas2560_priv *pTAS2560, unsigned int reg,
|
||||
unsigned int *pValue);
|
||||
int (*write)(struct tas2560_priv *pTAS2560, unsigned int reg,
|
||||
unsigned int Value);
|
||||
int (*bulk_read)(struct tas2560_priv *pTAS2560, unsigned int reg,
|
||||
unsigned char *pData, unsigned int len);
|
||||
int (*bulk_write)(struct tas2560_priv *pTAS2560, unsigned int reg,
|
||||
unsigned char *pData, unsigned int len);
|
||||
int (*update_bits)(struct tas2560_priv *pTAS2560, unsigned int reg,
|
||||
unsigned int mask, unsigned int value);
|
||||
void (*hw_reset)(struct tas2560_priv *pTAS2560);
|
||||
void (*clearIRQ)(struct tas2560_priv *pTAS2560);
|
||||
void (*enableIRQ)(struct tas2560_priv *pTAS2560, bool enable);
|
||||
/* device is working, but system is suspended */
|
||||
int (*runtime_suspend)(struct tas2560_priv *pTAS2560);
|
||||
int (*runtime_resume)(struct tas2560_priv *pTAS2560);
|
||||
bool mbRuntimeSuspend;
|
||||
|
||||
unsigned int mnErrCode;
|
||||
#ifdef CONFIG_TAS2560_CODEC
|
||||
struct mutex codec_lock;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TAS2560_MISC
|
||||
int mnDBGCmd;
|
||||
int mnCurrentReg;
|
||||
struct mutex file_lock;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
Loading…
Reference in a new issue