From fb5e35ab7baa34201d0aa01dcdf3a45690adece8 Mon Sep 17 00:00:00 2001 From: liaohj Date: Sat, 12 Oct 2019 12:54:59 +0800 Subject: [PATCH] audio:ti2558:add brown protection function add ti2558 brown protection function 1. currently just have limit voltage setting: a.ti,lim_th_max is the start limit voltage, when voltage less than the voltate, smart pa will decrease gain step by step. b.ti,lim_th_min is the immediately limit voltage, when voltage less than the voltage, smart pa will decrease the min gain . ti,lim_th_max & ti,lim_th_min defined at product dts. 2.how to enable. we can set TAS2562 BROWNOUT PROTECT ENABLE On to mixerpaths. 3.when HW test the voltage ,we will set in dts and enable by mixer_paths. 4.If HW need to adjust the min gain, need add more code . if there are the request ,need to achieve in the future. fix some no function. 1.fix tas2562_codec_read & tas2562_codec_write no function. 2.fix Amp Output Level no useful. Change-Id: I6e4be083063f009246d3a4a478c22fa6aee8467f Signed-off-by: liaohj Reviewed-on: https://gerrit.mot.com/1435926 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Wanlong Zhou Reviewed-by: Hujun Liao Submit-Approved: Jira Key --- sound/soc/codecs/tas2562-codec.c | 166 +++++++++++++++++++++++++++++- sound/soc/codecs/tas2562-codec.h | 1 + sound/soc/codecs/tas2562-regmap.c | 26 ++++- sound/soc/codecs/tas2562.h | 42 ++++++++ 4 files changed, 230 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/tas2562-codec.c b/sound/soc/codecs/tas2562-codec.c index 19597fd0d00d..b1144ea22308 100644 --- a/sound/soc/codecs/tas2562-codec.c +++ b/sound/soc/codecs/tas2562-codec.c @@ -56,11 +56,13 @@ /* #define TAS2558_CODEC */ static char const *iv_enable_text[] = {"Off", "On"}; +static char const *brownout_enable_text[] = {"Off", "On"}; static int tas2562iv_enable; static int mb_mute; static const struct soc_enum tas2562_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(iv_enable_text), iv_enable_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(brownout_enable_text), brownout_enable_text), }; static int tas2562_set_fmt(struct tas2562_priv *p_tas2562, unsigned int fmt); @@ -75,6 +77,8 @@ static int tas2562_mute_ctrl_get(struct snd_kcontrol *pKcontrol, static int tas2562_mute_ctrl_put(struct snd_kcontrol *pKcontrol, struct snd_ctl_elem_value *pValue); +static int tas2562_brownout_params_init(struct tas2562_priv *p_tas2562); + static unsigned int p_tas2562_classh_d_data[] = { /* reg address size values */ TAS2562_CLASSHHEADROOM, 0x4, 0x09, 0x99, 0x99, 0x9a, @@ -96,11 +100,13 @@ static unsigned int p_tas2562_classh_d_data[] = { static unsigned int tas2562_codec_read(struct snd_soc_codec *codec, unsigned int reg) { + unsigned int value = 0; struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); - dev_dbg(p_tas2562->dev, "Should not get here\n"); + p_tas2562->read (p_tas2562, channel_left, reg, &value); + dev_dbg(p_tas2562->dev, "%s, reg=%d, value=%d", __func__, reg, value); - return 0; + return value; } static int tas2562_iv_enable(struct tas2562_priv *p_tas2562, int enable) @@ -195,9 +201,87 @@ static int tas2562iv_get(struct snd_kcontrol *kcontrol, return 0; } +int tas2562_brownout_enable(struct tas2562_priv *p_tas2562, bool enable) +{ + int ret = 0; + dev_info(p_tas2562->dev, "%s, enable = %d\n", __func__, enable); + /* Brownout Protection Init */ + if (enable) { + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_LIMITERCONFIGURATIONREG0, + 0x51); + if (ret < 0) + return ret; + tas2562_brownout_params_init(p_tas2562); + p_tas2562->tas2562brownout_enable = true; + } else { + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_LIMITERCONFIGURATIONREG0, + 0x12); + if (ret < 0) + return ret; + p_tas2562->tas2562brownout_enable = false; + } + + return ret; +} + +static int tas2562_brownout_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tas2562_priv *p_tas2562 = NULL; + int brownout_enable = 0, n_result = 0; + + if (codec == NULL) { + pr_err("%s:codec is NULL\n", __func__); + return 0; + } + + p_tas2562 = snd_soc_codec_get_drvdata(codec); + if (p_tas2562 == NULL) { + pr_err("%s:p_tas2562 is NULL\n", __func__); + return 0; + } + + brownout_enable = ucontrol->value.integer.value[0]; + + n_result = tas2562_brownout_enable(p_tas2562, brownout_enable); + + pr_debug("%s: brownout_enable = %d\n", __func__, brownout_enable); + + return n_result; +} + +static int tas2562_brownout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tas2562_priv *p_tas2562 = NULL; + + if (codec == NULL) { + pr_err("%s:codec is NULL\n", __func__); + return 0; + } + + p_tas2562 = snd_soc_codec_get_drvdata(codec); + if (p_tas2562 == NULL) { + pr_err("%s:p_tas2562 is NULL\n", __func__); + return 0; + } + + ucontrol->value.integer.value[0] = p_tas2562->tas2562brownout_enable; + + dev_err(p_tas2562->dev, "brownout enable %d\n", p_tas2562->tas2562brownout_enable); + + return 0; +} + static const struct snd_kcontrol_new tas2562_controls[] = { SOC_ENUM_EXT("TAS2562 IVSENSE ENABLE", tas2562_enum[0], tas2562iv_get, tas2562iv_put), +SOC_ENUM_EXT("TAS2562 BROWNOUT PROTECT ENABLE", tas2562_enum[1], + tas2562_brownout_get, tas2562_brownout_put), }; static int tas2562_codec_write(struct snd_soc_codec *codec, unsigned int reg, @@ -205,7 +289,8 @@ static int tas2562_codec_write(struct snd_soc_codec *codec, unsigned int reg, { struct tas2562_priv *p_tas2562 = snd_soc_codec_get_drvdata(codec); - dev_dbg(p_tas2562->dev, "Should not get here\n"); + dev_dbg(p_tas2562->dev, "%s: %d, %d", __func__, reg, value); + p_tas2562->write (p_tas2562, channel_both, reg, value); return 0; } @@ -373,6 +458,8 @@ static int tas2562_set_power_state(struct tas2562_priv *p_tas2562, state); } + n_result = tas2562_brownout_enable(p_tas2562, p_tas2562->tas2562brownout_enable); + return n_result; } @@ -954,6 +1041,77 @@ static struct snd_soc_dai_driver tas2562_dai_driver[] = { }, }; +static int tas2562_brownout_params_init(struct tas2562_priv *p_tas2562) +{ + int ret = 0; + + dev_info(p_tas2562->dev, "%s, lim_th_min = %d, lim_th_max = %d!\n", + __func__, p_tas2562->lim_th_min, p_tas2562->lim_th_max); + + if (p_tas2562->lim_th_min <= 0 || + p_tas2562->lim_th_min > p_tas2562->lim_th_max) { + dev_info(p_tas2562->dev, "%s: use default config!\n", __func__); + p_tas2562->lim_th_min = 4; + } + if (p_tas2562->lim_th_max <= 0 || + p_tas2562->lim_th_min > p_tas2562->lim_th_max) { + dev_info(p_tas2562->dev, "%s: use default config!\n", __func__); + p_tas2562->lim_th_max = 9; + } + + /* LIMB_TH_MAX config*/ + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN0, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_min, 0xFF000000, 24)); + if (ret < 0) + return ret; + + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN1, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_min, 0x00FF0000, 16)); + if (ret < 0) + return ret; + + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN2, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_min, 0x0000FF00, 8)); + if (ret < 0) + return ret; + + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN3, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_min, 0x000000FF, 0)); + if (ret < 0) + return ret; + + /* LIMB TH MAX CONFIG */ + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MAX0, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_max, 0xFF000000, 24)); + if (ret < 0) + return ret; + + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN1, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_max, 0x00FF0000, 16)); + if (ret < 0) + return ret; + + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN2, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_max, 0x0000FF00, 8)); + if (ret < 0) + return ret; + + ret = p_tas2562->write(p_tas2562, channel_both, + TAS2562_BROWNOUT_LIMB_TH_MIN3, + TAS2562_BROWNOUT_VBAT_CONVERT(p_tas2562->lim_th_max, 0x000000FF, 0)); + if (ret < 0) + return ret; + + return 0; +} + static int tas2562_load_init(struct tas2562_priv *p_tas2562) { int ret; @@ -1040,7 +1198,7 @@ static const struct soc_enum spk_enum[] = { static const struct snd_kcontrol_new tas2562_snd_controls[] = { SOC_SINGLE_TLV("Amp Output Level", TAS2562_PLAYBACKCONFIGURATIONREG0, - 0, 0x16, 0, + 1, 0x16, 0, tas2562_digital_tlv), SOC_SINGLE_EXT("SmartPA System Mute", SND_SOC_NOPM, 0, 0x0001, 0, tas2562_system_mute_ctrl_get, tas2562_system_mute_ctrl_put), diff --git a/sound/soc/codecs/tas2562-codec.h b/sound/soc/codecs/tas2562-codec.h index 7b4447208b7d..186933a36216 100644 --- a/sound/soc/codecs/tas2562-codec.h +++ b/sound/soc/codecs/tas2562-codec.h @@ -27,5 +27,6 @@ int tas2562_register_codec(struct tas2562_priv *p_tas2562); int tas2562_deregister_codec(struct tas2562_priv *p_tas2562); int tas2562_load_config(struct tas2562_priv *p_tas2562); +int tas2562_brownout_enable(struct tas2562_priv *p_tas2562, bool enable); #endif /* _TAS2562_CODEC_H */ diff --git a/sound/soc/codecs/tas2562-regmap.c b/sound/soc/codecs/tas2562-regmap.c index 66e2861e65f2..8fba5d542a91 100644 --- a/sound/soc/codecs/tas2562-regmap.c +++ b/sound/soc/codecs/tas2562-regmap.c @@ -665,7 +665,7 @@ static void irq_work_routine(struct work_struct *work) TAS2562_POWERCONTROL, &nDevInt1Status); if (n_result < 0) goto reload; - if (chn && channel_right) + if (chn & channel_right) n_result = p_tas2562->read(p_tas2562, channel_right, TAS2562_POWERCONTROL, &nDevInt3Status); if (n_result < 0) @@ -759,6 +759,10 @@ static void irq_work_routine(struct work_struct *work) if (n_result < 0) goto reload; + n_result = tas2562_brownout_enable(p_tas2562, p_tas2562->tas2562brownout_enable); + if (n_result < 0) + return n_result; + goto end; reload: @@ -941,6 +945,26 @@ static int tas2562_parse_dt(struct device *dev, struct tas2562_priv *p_tas2562) } } + + + rc = of_property_read_u32(np, "ti,lim_th_min", &p_tas2562->lim_th_min); + if (rc) { + dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n", + "ti,lim_th_min", np->full_name, rc); + } else { + dev_dbg(p_tas2562->dev, "ti,lim_th_min=%d", + p_tas2562->lim_th_min); + } + + rc = of_property_read_u32(np, "ti,lim_th_max", &p_tas2562->lim_th_max); + if (rc) { + dev_err(p_tas2562->dev, "Looking up %s property in node %s failed %d\n", + "ti,lim_th_max", np->full_name, rc); + } else { + dev_dbg(p_tas2562->dev, "ti,lim_th_max=%d", + p_tas2562->lim_th_max); + } + return ret; } diff --git a/sound/soc/codecs/tas2562.h b/sound/soc/codecs/tas2562.h index 01d148fe8b86..e715897f6d21 100644 --- a/sound/soc/codecs/tas2562.h +++ b/sound/soc/codecs/tas2562.h @@ -546,6 +546,44 @@ TAS2562_INTERRUPTCONFIGURATION_PININTCONFIG10_ASSERT2MSONLATCHEDINTERRUPTS \ #define TAS2562_BOOK TAS2562_REG(0x0, 0x0, 0x7F) #define TAS2562_BOOK_BOOK70_MASK (0xff << 0) + /* Brown out Prevention */ +#define TAS2562_BROWNOUT_LIM_CFG1 TAS2562_REG(0x0, 0x0, 0x13) +#define TAS2562_BROWNOUT_LIM_MAX_ATN0 TAS2562_REG(0x0, 0x02, 0x14) +#define TAS2562_BROWNOUT_LIM_MAX_ATN1 TAS2562_REG(0x0, 0x02, 0x15) +#define TAS2562_BROWNOUT_LIM_MAX_ATN2 TAS2562_REG(0x0, 0x02, 0x16) +#define TAS2562_BROWNOUT_LIM_MAX_ATN3 TAS2562_REG(0x0, 0x02, 0x17) + +#define TAS2562_BROWNOUT_LIMB_BOP_TH0 TAS2562_REG(0x0, 0x02, 0x2B) +#define TAS2562_BROWNOUT_LIMB_BOP_TH1 TAS2562_REG(0x0, 0x02, 0x2A) +#define TAS2562_BROWNOUT_LIMB_BOP_TH2 TAS2562_REG(0x0, 0x02, 0x29) +#define TAS2562_BROWNOUT_LIMB_BOP_TH3 TAS2562_REG(0x0, 0x02, 0x28) + +#define TAS2562_BROWNOUT_LIMB_SLOPE0 TAS2562_REG(0x0, 0x02, 0x27) +#define TAS2562_BROWNOUT_LIMB_SLOPE1 TAS2562_REG(0x0, 0x02, 0x26) +#define TAS2562_BROWNOUT_LIMB_SLOPE2 TAS2562_REG(0x0, 0x02, 0x25) +#define TAS2562_BROWNOUT_LIMB_SLOPE3 TAS2562_REG(0x0, 0x02, 0x24) + +#define TAS2562_BROWNOUT_LIMB_INF_PT0 TAS2562_REG(0x0, 0x02, 0x23) +#define TAS2562_BROWNOUT_LIMB_INF_PT1 TAS2562_REG(0x0, 0x02, 0x22) +#define TAS2562_BROWNOUT_LIMB_INF_PT2 TAS2562_REG(0x0, 0x02, 0x21) +#define TAS2562_BROWNOUT_LIMB_INF_PT3 TAS2562_REG(0x0, 0x02, 0x20) + +#define TAS2562_BROWNOUT_LIMB_TH_MIN0 TAS2562_REG(0x0, 0x02, 0x1F) +#define TAS2562_BROWNOUT_LIMB_TH_MIN1 TAS2562_REG(0x0, 0x02, 0x1E) +#define TAS2562_BROWNOUT_LIMB_TH_MIN2 TAS2562_REG(0x0, 0x02, 0x1D) +#define TAS2562_BROWNOUT_LIMB_TH_MIN3 TAS2562_REG(0x0, 0x02, 0x1C) + +#define TAS2562_BROWNOUT_LIMB_TH_MAX0 TAS2562_REG(0x0, 0x02, 0x1B) +#define TAS2562_BROWNOUT_LIMB_TH_MAX1 TAS2562_REG(0x0, 0x02, 0x1A) +#define TAS2562_BROWNOUT_LIMB_TH_MAX2 TAS2562_REG(0x0, 0x02, 0x09) +#define TAS2562_BROWNOUT_LIMB_TH_MAX3 TAS2562_REG(0x0, 0x02, 0x08) + +#define TAS2562_BROWNOUT_VBAT_CONVERT(arg, mask, shift) (((arg << 27) & mask) >> shift) +#define TAS2562_BROWNOUT_LIMB_INF_PT_CONVERT(arg, mask, shift) (((arg << 28) & mask) >> shift) +#define TAS2562_BROWNOUT_LIMB_SLOPE_CONVERT(arg, mask, shift) (((arg << 28) & mask) >> shift) +#define TAS2562_BROWNOUT_LIMB_BPO_TH_CONVERT(arg, mask, shift) (((arg << 28) & mask) >> shift) + + #define TAS2562_POWER_ACTIVE 0 #define TAS2562_POWER_MUTE 1 #define TAS2562_POWER_SHUTDOWN 2 @@ -650,6 +688,10 @@ int mn_dbg_cmd; int mn_current_reg; struct mutex file_lock; #endif +int max_ant; +int lim_th_max; +int lim_th_min; +bool tas2562brownout_enable; }; #endif /* __TAS2562_ */