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:
Wen Xie 2018-06-20 14:57:03 +08:00
commit 87709cb9cd
10 changed files with 3016 additions and 0 deletions

View file

@ -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

View file

@ -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

View 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 */

View 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 */

File diff suppressed because it is too large Load diff

View 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 */

View 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 */

View 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 */

View 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
View 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