From da1682d5e8b53a51072552844c551b1b784e52c2 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 16 Dec 2025 17:06:16 +0800 Subject: [PATCH] ASoC: rt1320: support calibration and temperature/r0 loading This patch adds the functions/controls to support the calibration. The mixer controls could trigger a calibration and load temperature/r0 value. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20251216090616.3955293-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1320-sdw.c | 1059 ++++++++++++++++++++++++++++++++- sound/soc/codecs/rt1320-sdw.h | 66 ++ 2 files changed, 1118 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index e3f9b03df3aae..d67002002bee6 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -502,12 +502,8 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case 0x2000301c: case 0x2000900f: case 0x20009018: - case 0x3fc29d80 ... 0x3fc29d83: - case 0x3fe2e000 ... 0x3fe2e003: - case 0x3fc2ab80 ... 0x3fc2abd4: - case 0x3fc2bfc0 ... 0x3fc2bfc8: - case 0x3fc2d300 ... 0x3fc2d354: - case 0x3fc2dfc0 ... 0x3fc2dfc8: + case 0x3fc000c0 ... 0x3fc2dfc8: + case 0x3fe00000 ... 0x3fe36fff: /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01): @@ -557,6 +553,8 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0xc48c ... 0xc48f: case 0xc560: case 0xc5b5 ... 0xc5b7: + case 0xc5c3: + case 0xc5c8: case 0xc5fc ... 0xc5ff: case 0xc680 ... 0xc683: case 0xc820: @@ -590,6 +588,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0xdd0c ... 0xdd13: case 0xde02: case 0xdf14 ... 0xdf1b: + case 0xe80b: case 0xe83c ... 0xe847: case 0xf01e: case 0xf717 ... 0xf719: @@ -602,7 +601,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0x2000301c: case 0x2000900f: case 0x20009018: - case 0x3fc2ab80 ... 0x3fc2abd4: + case 0x3fc2ab80 ... 0x3fc2ac4c: case 0x3fc2b780: case 0x3fc2bf80 ... 0x3fc2bf83: case 0x3fc2bfc0 ... 0x3fc2bfc8: @@ -720,6 +719,13 @@ static int rt1320_read_prop(struct sdw_slave *slave) j++; } + prop->dp0_prop = devm_kzalloc(&slave->dev, sizeof(*prop->dp0_prop), GFP_KERNEL); + if (!prop->dp0_prop) + return -ENOMEM; + + prop->dp0_prop->simple_ch_prep_sm = true; + prop->dp0_prop->ch_prep_timeout = 10; + /* set the timeout values */ prop->clk_stop_timeout = 64; @@ -754,6 +760,515 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned return 0; } +static void rt1320_data_rw(struct rt1320_sdw_priv *rt1320, unsigned int start, + unsigned char *data, unsigned int size, enum rt1320_rw_type rw) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int tmp; + int ret = -1; + int i, j; + + pm_runtime_set_autosuspend_delay(dev, 20000); + pm_runtime_mark_last_busy(dev); + + switch (rw) { + case RT1320_BRA_WRITE: + case RT1320_BRA_READ: + ret = sdw_bpt_send_sync(rt1320->sdw_slave->bus, rt1320->sdw_slave, &rt1320->bra_msg); + if (ret < 0) + dev_err(dev, "%s: Failed to send BRA message: %d\n", __func__, ret); + fallthrough; + case RT1320_PARAM_WRITE: + case RT1320_PARAM_READ: + if (ret < 0) { + /* if BRA fails, we try to access by the control word */ + if (rw == RT1320_BRA_WRITE || rw == RT1320_BRA_READ) { + for (i = 0; i < rt1320->bra_msg.sections; i++) { + pm_runtime_mark_last_busy(dev); + for (j = 0; j < rt1320->bra_msg.sec[i].len; j++) { + if (rw == RT1320_BRA_WRITE) { + regmap_write(rt1320->regmap, + rt1320->bra_msg.sec[i].addr + j, rt1320->bra_msg.sec[i].buf[j]); + } else { + regmap_read(rt1320->regmap, rt1320->bra_msg.sec[i].addr + j, &tmp); + rt1320->bra_msg.sec[i].buf[j] = tmp; + } + } + } + } else { + for (i = 0; i < size; i++) { + if (rw == RT1320_PARAM_WRITE) + regmap_write(rt1320->regmap, start + i, data[i]); + else { + regmap_read(rt1320->regmap, start + i, &tmp); + data[i] = tmp; + } + } + } + } + break; + } + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_mark_last_busy(dev); +} + +static unsigned long long rt1320_rsgain_to_rsratio(struct rt1320_sdw_priv *rt1320, unsigned int rsgain) +{ + unsigned long long base = 1000000000U; + unsigned long long step = 1960784U; + unsigned long long tmp, result; + + if (rsgain == 0 || rsgain == 0x1ff) + result = 1000000000; + else if (rsgain & 0x100) { + tmp = 0xff - (rsgain & 0xff); + tmp = tmp * step; + result = base + tmp; + } else { + tmp = (rsgain & 0xff); + tmp = tmp * step; + result = base - tmp; + } + + return result; +} + +static void rt1320_pr_read(struct rt1320_sdw_priv *rt1320, unsigned int reg, unsigned int *val) +{ + unsigned int byte3, byte2, byte1, byte0; + + regmap_write(rt1320->regmap, 0xc483, 0x80); + regmap_write(rt1320->regmap, 0xc482, 0x40); + regmap_write(rt1320->regmap, 0xc481, 0x0c); + regmap_write(rt1320->regmap, 0xc480, 0x10); + + regmap_write(rt1320->regmap, 0xc487, ((reg & 0xff000000) >> 24)); + regmap_write(rt1320->regmap, 0xc486, ((reg & 0x00ff0000) >> 16)); + regmap_write(rt1320->regmap, 0xc485, ((reg & 0x0000ff00) >> 8)); + regmap_write(rt1320->regmap, 0xc484, (reg & 0x000000ff)); + + regmap_write(rt1320->regmap, 0xc482, 0xc0); + + regmap_read(rt1320->regmap, 0xc48f, &byte3); + regmap_read(rt1320->regmap, 0xc48e, &byte2); + regmap_read(rt1320->regmap, 0xc48d, &byte1); + regmap_read(rt1320->regmap, 0xc48c, &byte0); + + *val = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0; +} + +static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int tmp, retry = 0; + unsigned int cmd_addr; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + cmd_addr = RT1320_CMD_ID; + break; + case RT1321_DEV_ID: + cmd_addr = RT1321_CMD_ID; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + pm_runtime_mark_last_busy(dev); + /* check the value of cmd_addr becomes to zero */ + while (retry < 500) { + regmap_read(rt1320->regmap, cmd_addr, &tmp); + if (tmp == 0) + break; + usleep_range(1000, 1100); + retry++; + } + if (retry == 500) { + dev_warn(dev, "%s FW is NOT ready!", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int retry = 0, tmp; + + pm_runtime_mark_last_busy(dev); + while (retry < 200) { + regmap_read(rt1320->regmap, RT1320_POWER_STATE, &tmp); + dev_dbg(dev, "%s, RT1320_POWER_STATE=0x%x\n", __func__, tmp); + if (tmp >= ps) + break; + usleep_range(1000, 1500); + retry++; + } + if (retry == 200) { + dev_warn(dev, "%s FW Power State is NOT ready!", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static int rt1320_process_fw_param(struct rt1320_sdw_priv *rt1320, unsigned char *buf, unsigned int buf_size) +{ + struct device *dev = &rt1320->sdw_slave->dev; + struct rt1320_paramcmd *paramhr = (struct rt1320_paramcmd *)buf; + unsigned char moudleid = paramhr->moudleid; + unsigned char cmdtype = paramhr->commandtype; + unsigned int fw_param_addr; + unsigned int start_addr; + int ret = 0; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_param_addr = RT1320_FW_PARAM_ADDR; + start_addr = RT1320_CMD_PARAM_ADDR; + break; + case RT1321_DEV_ID: + fw_param_addr = RT1321_FW_PARAM_ADDR; + start_addr = RT1321_CMD_PARAM_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + ret = rt1320_check_fw_ready(rt1320); + if (ret < 0) + goto _timeout_; + + /* don't set offset 0x0/0x1, it will be set later*/ + paramhr->moudleid = 0; + paramhr->commandtype = 0; + rt1320_data_rw(rt1320, fw_param_addr, buf, buf_size, RT1320_PARAM_WRITE); + + dev_dbg(dev, "%s, moudleid=%d, cmdtype=%d, paramid=%d, paramlength=%d\n", __func__, + moudleid, cmdtype, paramhr->paramid, paramhr->paramlength); + + if (cmdtype == RT1320_SET_PARAM) { + regmap_write(rt1320->regmap, fw_param_addr, moudleid); + regmap_write(rt1320->regmap, fw_param_addr + 1, 0x01); + } + if (cmdtype == RT1320_GET_PARAM) { + regmap_write(rt1320->regmap, fw_param_addr, moudleid); + regmap_write(rt1320->regmap, fw_param_addr + 1, 0x02); + ret = rt1320_check_fw_ready(rt1320); + if (ret < 0) + goto _timeout_; + + rt1320_data_rw(rt1320, start_addr, buf + 0x10, paramhr->commandlength, RT1320_PARAM_READ); + } + return 0; + +_timeout_: + dev_err(&rt1320->sdw_slave->dev, "%s: FW is NOT ready for SET/GET_PARAM\n", __func__); + return ret; +} + +static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_fw_cmdid cmdid, + unsigned int paramid, void *parambuf, unsigned int paramsize) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned char *tempbuf = NULL; + struct rt1320_paramcmd paramhr; + int ret = 0; + + tempbuf = kzalloc(sizeof(paramhr) + paramsize, GFP_KERNEL); + if (!tempbuf) + return -ENOMEM; + + paramhr.moudleid = 1; + paramhr.commandtype = cmdid; + /* 8 is "sizeof(paramid) + sizeof(paramlength)" */ + paramhr.commandlength = 8 + paramsize; + paramhr.paramid = paramid; + paramhr.paramlength = paramsize; + + memcpy(tempbuf, ¶mhr, sizeof(paramhr)); + if (cmdid == RT1320_SET_PARAM) + memcpy(tempbuf + sizeof(paramhr), parambuf, paramsize); + + ret = rt1320_process_fw_param(rt1320, tempbuf, sizeof(paramhr) + paramsize); + if (ret < 0) { + dev_err(dev, "%s: process_fw_param failed\n", __func__); + goto _finish_; + } + + if (cmdid == RT1320_GET_PARAM) + memcpy(parambuf, tempbuf + sizeof(paramhr), paramsize); + +_finish_: + kfree(tempbuf); + return ret; +} + +static void rt1320_set_advancemode(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + struct rt1320_datafixpoint r0_data[2]; + unsigned short l_advancegain, r_advancegain; + int ret; + + /* Get advance gain/r0 */ + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 6, &r0_data[0], sizeof(struct rt1320_datafixpoint)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 7, &r0_data[1], sizeof(struct rt1320_datafixpoint)); + l_advancegain = r0_data[0].advancegain; + r_advancegain = r0_data[1].advancegain; + dev_dbg(dev, "%s, LR advanceGain=0x%x 0x%x\n", __func__, l_advancegain, r_advancegain); + + /* set R0 and enable protection by SetParameter id 6, 7 */ + r0_data[0].silencedetect = 0; + r0_data[0].r0 = rt1320->r0_l_reg; + r0_data[1].silencedetect = 0; + r0_data[1].r0 = rt1320->r0_r_reg; + dev_dbg(dev, "%s, write LR r0=%d, %d\n", __func__, r0_data[0].r0, r0_data[1].r0); + + rt1320_fw_param_protocol(rt1320, RT1320_SET_PARAM, 6, &r0_data[0], sizeof(struct rt1320_datafixpoint)); + rt1320_fw_param_protocol(rt1320, RT1320_SET_PARAM, 7, &r0_data[1], sizeof(struct rt1320_datafixpoint)); + ret = rt1320_check_fw_ready(rt1320); + if (ret < 0) + dev_err(dev, "%s: Failed to set FW param 6,7!\n", __func__); + + if (l_advancegain != 0 && r_advancegain != 0) { + regmap_write(rt1320->regmap, 0xdd0b, (l_advancegain & 0xff00) >> 8); + regmap_write(rt1320->regmap, 0xdd0a, (l_advancegain & 0xff)); + regmap_write(rt1320->regmap, 0xdd09, (r_advancegain & 0xff00) >> 8); + regmap_write(rt1320->regmap, 0xdd08, (r_advancegain & 0xff)); + dev_dbg(dev, "%s, set Advance mode gain\n", __func__); + } +} + +static int rt1320_invrs_load(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned long long l_rsratio, r_rsratio; + unsigned int pr_1058, pr_1059, pr_105a; + unsigned long long l_invrs, r_invrs; + unsigned long long factor = (1 << 28); + unsigned int l_rsgain, r_rsgain; + struct rt1320_datafixpoint r0_data[2]; + int ret; + + /* read L/Rch Rs Gain - it uses for compensating the R0 value */ + rt1320_pr_read(rt1320, 0x1058, &pr_1058); + rt1320_pr_read(rt1320, 0x1059, &pr_1059); + rt1320_pr_read(rt1320, 0x105a, &pr_105a); + l_rsgain = ((pr_1059 & 0x7f) << 2) | ((pr_105a & 0xc0) >> 6); + r_rsgain = ((pr_1058 & 0xff) << 1) | ((pr_1059 & 0x80) >> 7); + dev_dbg(dev, "%s, LR rsgain=0x%x, 0x%x\n", __func__, l_rsgain, r_rsgain); + + l_rsratio = rt1320_rsgain_to_rsratio(rt1320, l_rsgain); + r_rsratio = rt1320_rsgain_to_rsratio(rt1320, r_rsgain); + dev_dbg(dev, "%s, LR rsratio=%lld, %lld\n", __func__, l_rsratio, r_rsratio); + + l_invrs = (l_rsratio * factor) / 1000000000U; + r_invrs = (r_rsratio * factor) / 1000000000U; + + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 6, &r0_data[0], sizeof(struct rt1320_datafixpoint)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 7, &r0_data[1], sizeof(struct rt1320_datafixpoint)); + + r0_data[0].invrs = l_invrs; + r0_data[1].invrs = r_invrs; + dev_dbg(dev, "%s, write DSP LR invrs=0x%x, 0x%x\n", __func__, r0_data[0].invrs, r0_data[1].invrs); + + rt1320_fw_param_protocol(rt1320, RT1320_SET_PARAM, 6, &r0_data[0], sizeof(struct rt1320_datafixpoint)); + rt1320_fw_param_protocol(rt1320, RT1320_SET_PARAM, 7, &r0_data[1], sizeof(struct rt1320_datafixpoint)); + ret = rt1320_check_fw_ready(rt1320); + if (ret < 0) + dev_err(dev, "%s: Failed to set FW param 6,7!\n", __func__); + + return ret; +} + +static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned long long l_calir0, r_calir0; + const unsigned int factor = (1 << 27); + + l_calir0 = (rt1320->r0_l_reg * 1000) / factor; + r_calir0 = (rt1320->r0_r_reg * 1000) / factor; + + dev_dbg(dev, "%s, l_calir0=%lld.%03lld ohm, r_calir0=%lld.%03lld ohm\n", __func__, + l_calir0 / 1000, l_calir0 % 1000, + r_calir0 / 1000, r_calir0 % 1000); +} + +static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + struct rt1320_datafixpoint audfixpoint[2]; + unsigned int reg_c5fb, reg_c570, reg_cd00; + unsigned int vol_reg[4], fw_ready; + unsigned long long l_meanr0, r_meanr0; + unsigned int fw_status_addr; + int l_re[5], r_re[5]; + int ret, tmp; + unsigned long long factor = (1 << 27); + unsigned short l_advancegain, r_advancegain; + unsigned int delay_s = 7; /* delay seconds for the calibration */ + + if (!rt1320->component) + return; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_status_addr = RT1320_DSPFW_STATUS_ADDR; + break; + case RT1321_DEV_ID: + fw_status_addr = RT1321_DSPFW_STATUS_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return; + } + + /* set volume 0dB */ + regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]); + regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]); + regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]); + regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]); + regmap_write(rt1320->regmap, 0xdd0b, 0x0f); + regmap_write(rt1320->regmap, 0xdd0a, 0xff); + regmap_write(rt1320->regmap, 0xdd09, 0x0f); + regmap_write(rt1320->regmap, 0xdd08, 0xff); + + regmap_read(rt1320->regmap, 0xc5fb, ®_c5fb); + regmap_read(rt1320->regmap, 0xc570, ®_c570); + regmap_read(rt1320->regmap, 0xcd00, ®_cd00); + + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); + ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); + if (ret < 0) { + dev_dbg(dev, "%s, PDE=PS0 is NOT ready\n", __func__); + goto _finish_; + } + + regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); + fw_ready &= 0x1; + if (!fw_ready) { + dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); + goto _finish_; + } + + ret = rt1320_check_power_state_ready(rt1320, RT1320_NORMAL_STATE); + if (ret < 0) { + dev_dbg(dev, "%s, DSP FW PS is NOT ready\n", __func__); + goto _finish_; + } + + if (rt1320->dev_id == RT1320_DEV_ID) + regmap_write(rt1320->regmap, 0xc5fb, 0x00); + regmap_write(rt1320->regmap, 0xc570, 0x0b); + regmap_write(rt1320->regmap, 0xcd00, 0xc5); + + /* disable silence detection */ + regmap_update_bits(rt1320->regmap, 0xc044, 0xe0, 0x00); + dev_dbg(dev, "%s, disable silence detection\n", __func__); + + ret = rt1320_check_power_state_ready(rt1320, RT1320_K_R0_STATE); + if (ret < 0) { + dev_dbg(dev, "%s, check class D status before k r0\n", __func__); + goto _finish_; + } + + for (tmp = 0; tmp < delay_s; tmp++) { + msleep(1000); + pm_runtime_mark_last_busy(dev); + + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 11, &l_re[0], sizeof(l_re)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 12, &r_re[0], sizeof(r_re)); + + dev_dbg(dev, "%s, LR re=0x%x, 0x%x\n", __func__, l_re[4], r_re[4]); + dev_dbg(dev, "%s, waiting for calibration R0...%d seconds\n", __func__, tmp + 1); + } + + /* Get Calibration data */ + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 11, &l_re[0], sizeof(l_re)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 12, &r_re[0], sizeof(r_re)); + dev_dbg(dev, "%s, LR re=0x%x, 0x%x\n", __func__, l_re[4], r_re[4]); + + /* Get advance gain/mean r0 */ + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 6, &audfixpoint[0], sizeof(struct rt1320_datafixpoint)); + l_meanr0 = audfixpoint[0].meanr0; + l_advancegain = audfixpoint[0].advancegain; + l_meanr0 = ((l_meanr0 * 1000U) / factor); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 7, &audfixpoint[1], sizeof(struct rt1320_datafixpoint)); + r_meanr0 = audfixpoint[1].meanr0; + r_advancegain = audfixpoint[1].advancegain; + r_meanr0 = ((r_meanr0 * 1000U) / factor); + dev_dbg(dev, "%s, LR meanr0=%lld, %lld\n", __func__, l_meanr0, r_meanr0); + dev_dbg(dev, "%s, LR advanceGain=0x%x, 0x%x\n", __func__, l_advancegain, r_advancegain); + dev_dbg(dev, "%s, LR invrs=0x%x, 0x%x\n", __func__, audfixpoint[0].invrs, audfixpoint[1].invrs); + + /* enable silence detection */ + regmap_update_bits(rt1320->regmap, 0xc044, 0xe0, 0xe0); + dev_dbg(dev, "%s, enable silence detection\n", __func__); + + regmap_write(rt1320->regmap, 0xc5fb, reg_c5fb); + regmap_write(rt1320->regmap, 0xc570, reg_c570); + regmap_write(rt1320->regmap, 0xcd00, reg_cd00); + + rt1320->r0_l_reg = l_re[4]; + rt1320->r0_r_reg = r_re[4]; + rt1320->cali_done = true; + rt1320_calc_r0(rt1320); + +_finish_: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); + + /* advance gain will be set when R0 load, not here */ + regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]); + regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]); + regmap_write(rt1320->regmap, 0xdd09, vol_reg[1]); + regmap_write(rt1320->regmap, 0xdd08, vol_reg[0]); +} + +static int rt1320_r0_cali_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1320->cali_done; + return 0; +} + +static int rt1320_r0_cali_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(rt1320->component); + int ret; + + if (!rt1320->hw_init) + return 0; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + rt1320->cali_done = false; + snd_soc_dapm_mutex_lock(dapm); + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF && + ucontrol->value.integer.value[0]) { + rt1320_calibrate(rt1320); + } + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + /* * The 'patch code' is written to the patch code area. * The patch code area is used for SDCA register expansion flexibility. @@ -844,6 +1359,301 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320) } } +static int rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int factor = (1 << 22), fw_ready; + int l_t0_data[38], r_t0_data[38]; + unsigned int fw_status_addr; + int ret; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_status_addr = RT1320_DSPFW_STATUS_ADDR; + break; + case RT1321_DEV_ID: + fw_status_addr = RT1321_DSPFW_STATUS_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); + + regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); + fw_ready &= 0x1; + if (!fw_ready) { + dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__); + goto _exit_; + } + + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 3, &l_t0_data[0], sizeof(l_t0_data)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 4, &r_t0_data[0], sizeof(r_t0_data)); + + l_t0_data[37] = l_t0 * factor; + r_t0_data[37] = r_t0 * factor; + + dev_dbg(dev, "%s, write LR t0=0x%x, 0x%x\n", __func__, l_t0_data[37], r_t0_data[37]); + + rt1320_fw_param_protocol(rt1320, RT1320_SET_PARAM, 3, &l_t0_data[0], sizeof(l_t0_data)); + rt1320_fw_param_protocol(rt1320, RT1320_SET_PARAM, 4, &r_t0_data[0], sizeof(r_t0_data)); + ret = rt1320_check_fw_ready(rt1320); + if (ret < 0) + dev_err(dev, "%s: Failed to set FW param 3,4!\n", __func__); + + rt1320->temp_l_calib = l_t0; + rt1320->temp_r_calib = r_t0; + + memset(&l_t0_data[0], 0x00, sizeof(l_t0_data)); + memset(&r_t0_data[0], 0x00, sizeof(r_t0_data)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 3, &l_t0_data[0], sizeof(l_t0_data)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 4, &r_t0_data[0], sizeof(r_t0_data)); + dev_dbg(dev, "%s, read after writing LR t0=0x%x, 0x%x\n", __func__, l_t0_data[37], r_t0_data[37]); + +_exit_: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); + + return ret; +} + +static void rt1320_dspfw_load_code(struct rt1320_sdw_priv *rt1320) +{ +struct rt1320_imageinfo { + unsigned int addr; + unsigned int size; +}; + +struct rt1320_dspfwheader { + unsigned int sync; + short num; + short crc; +}; + + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(rt1320->component); + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int val, i, fw_offset, fw_ready; + unsigned int fw_status_addr; + struct rt1320_dspfwheader *fwheader; + struct rt1320_imageinfo *ptr_img; + struct sdw_bpt_section sec[10]; + const struct firmware *fw = NULL; + unsigned char *fw_data; + bool dev_fw_match = false; + static const char hdr_sig[] = "AFX"; + unsigned int hdr_size = 0; + const char *dmi_vendor, *dmi_product, *dmi_sku; + char vendor[128], product[128], sku[128]; + char *ptr_vendor, *ptr_product, *ptr_sku; + char filename[128]; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_status_addr = RT1320_DSPFW_STATUS_ADDR; + break; + case RT1321_DEV_ID: + fw_status_addr = RT1321_DSPFW_STATUS_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return; + } + + dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR); + dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME); + dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU); + + if (dmi_vendor && dmi_product && dmi_sku) { + strscpy(vendor, dmi_vendor); + strscpy(product, dmi_product); + strscpy(sku, dmi_sku); + ptr_vendor = &vendor[0]; + ptr_product = &product[0]; + ptr_sku = &sku[0]; + ptr_vendor = strsep(&ptr_vendor, " "); + ptr_product = strsep(&ptr_product, " "); + ptr_sku = strsep(&ptr_sku, " "); + + dev_dbg(dev, "%s: DMI vendor=%s, product=%s, sku=%s\n", __func__, + vendor, product, sku); + + snprintf(filename, sizeof(filename), + "realtek/rt1320/rt1320_%s_%s_%s.dat", vendor, product, sku); + dev_dbg(dev, "%s: try to load FW file %s\n", __func__, filename); + } else if (rt1320->dspfw_name) { + snprintf(filename, sizeof(filename), "rt1320_%s.dat", + rt1320->dspfw_name); + dev_dbg(dev, "%s: try to load FW file %s\n", __func__, filename); + } else { + dev_warn(dev, "%s: Can't find proper FW file name\n", __func__); + return; + } + + snd_soc_dapm_mutex_lock(dapm); + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); + + regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); + fw_ready &= 0x1; + if (fw_ready) { + dev_dbg(dev, "%s, DSP FW was already\n", __func__); + rt1320->fw_load_done = true; + goto _exit_; + } + + /* change to IRAM */ + regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); + + request_firmware(&fw, filename, dev); + if (fw) { + fwheader = (struct rt1320_dspfwheader *)fw->data; + dev_dbg(dev, "%s, fw sync = 0x%x, num=%d, crc=0x%x\n", __func__, + fwheader->sync, fwheader->num, fwheader->crc); + + if (fwheader->sync != 0x0a1c5679) { + dev_err(dev, "%s: FW sync error\n", __func__); + release_firmware(fw); + goto _exit_; + } + + fw_offset = sizeof(struct rt1320_dspfwheader) + (sizeof(struct rt1320_imageinfo) * fwheader->num); + dev_dbg(dev, "%s, fw_offset = 0x%x\n", __func__, fw_offset); + + regcache_cache_bypass(rt1320->regmap, true); + + for (i = 0; i < fwheader->num; i++) { + ptr_img = (struct rt1320_imageinfo *)&fw->data[sizeof(struct rt1320_dspfwheader) + (sizeof(struct rt1320_imageinfo) * i)]; + + dev_dbg(dev, "%s, fw_offset=0x%x, load fw addr=0x%x, size=%d\n", __func__, + fw_offset, ptr_img->addr, ptr_img->size); + + fw_data = (unsigned char *)&fw->data[fw_offset]; + + /* The binary file has a header of 64 bytes */ + if (memcmp(fw_data, hdr_sig, sizeof(hdr_sig)) == 0) + hdr_size = 64; + else + hdr_size = 0; + + sec[i].addr = ptr_img->addr; + sec[i].len = ptr_img->size - hdr_size; + sec[i].buf = fw_data + hdr_size; + + dev_dbg(dev, "%s, hdr_size=%d, sec[%d].buf[0]=0x%x\n", + __func__, hdr_size, i, sec[i].buf[0]); + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + if (ptr_img->addr == 0x3fc29d80) + if (fw_data[9] == '0') + dev_fw_match = true; + break; + case RT1321_DEV_ID: + if (ptr_img->addr == 0x3fc00000) + if (fw_data[9] == '1') + dev_fw_match = true; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + goto _exit_; + } + + fw_offset += ptr_img->size; + } + + if (dev_fw_match) { + dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__); + rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num; + rt1320->bra_msg.flags = SDW_MSG_FLAG_WRITE; + rt1320->bra_msg.sections = fwheader->num; + rt1320->bra_msg.sec = &sec[0]; + rt1320_data_rw(rt1320, 0, NULL, 0, RT1320_BRA_WRITE); + dev_dbg(dev, "%s, BRA downloading FW done..\n", __func__); + } + + regcache_cache_bypass(rt1320->regmap, false); + release_firmware(fw); + + if (!dev_fw_match) { + dev_err(dev, "%s: FW file doesn't match to device\n", __func__); + goto _exit_; + } + } else { + dev_err(dev, "%s: Failed to load %s firmware\n", __func__, filename); + goto _exit_; + } + + /* run RAM code */ + regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); + val |= 0x8; + regmap_write(rt1320->regmap, 0x3fc2bfc0, val); + + /* clear frame counter */ + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00); + regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00); + regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00); + regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00); + break; + case RT1321_DEV_ID: + regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00); + regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00); + regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00); + regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00); + break; + } + + /* enable DSP FW */ + regmap_write(rt1320->regmap, 0xc081, 0xfc); + regmap_update_bits(rt1320->regmap, 0xf01e, 0x1, 0x0); + + /* RsRatio should restore into DSP FW when FW was ready */ + rt1320_invrs_load(rt1320); + + /* DSP clock switches to PLL */ + regmap_write(rt1320->regmap, 0xc081, 0xfc); + /* pass DSP settings */ + regmap_write(rt1320->regmap, 0xc5c3, 0xf3); + regmap_write(rt1320->regmap, 0xc5c8, 0x05); + + rt1320->fw_load_done = true; + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_mark_last_busy(dev); + +_exit_: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); + + snd_soc_dapm_mutex_unlock(dapm); +} + +static void rt1320_load_dspfw_work(struct work_struct *work) +{ + struct rt1320_sdw_priv *rt1320 = + container_of(work, struct rt1320_sdw_priv, load_dspfw_work); + int ret; + + ret = pm_runtime_resume(rt1320->component->dev); + if (ret < 0 && ret != -EACCES) + return; + + dev_dbg(&rt1320->sdw_slave->dev, "%s, Starting to reload DSP FW", __func__); + rt1320_dspfw_load_code(rt1320); +} + static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) { struct sdw_slave *slave = rt1320->sdw_slave; @@ -956,6 +1766,10 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), FUNCTION_NEEDS_INITIALIZATION); + + /* reload DSP FW */ + if (rt1320->fw_load_done) + schedule_work(&rt1320->load_dspfw_work); } if (!rt1320->first_hw_init && rt1320->version_id == RT1320_VA && rt1320->dev_id == RT1320_DEV_ID) { regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, @@ -1358,6 +2172,189 @@ static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum, static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = regmap_get_device(rt1320->regmap); + unsigned int fw_status_addr; + unsigned int fw_ready; + int ret = 0; + + if (!rt1320->r0_l_reg || !rt1320->r0_r_reg) + return -EINVAL; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_status_addr = RT1320_DSPFW_STATUS_ADDR; + break; + case RT1321_DEV_ID: + fw_status_addr = RT1321_DSPFW_STATUS_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); + ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); + if (ret < 0) { + dev_dbg(dev, "%s, PDE=PS0 is NOT ready\n", __func__); + goto _timeout_; + } + + regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); + fw_ready &= 0x1; + if (!fw_ready) { + dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__); + goto _timeout_; + } + + ret = rt1320_check_power_state_ready(rt1320, RT1320_NORMAL_STATE); + if (ret < 0) { + dev_dbg(dev, "%s, DSP FW PS is NOT ready\n", __func__); + goto _timeout_; + } + + rt1320_set_advancemode(rt1320); + +_timeout_: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); + + return ret; +} + +static int rt1320_r0_load_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1320->r0_l_reg; + ucontrol->value.integer.value[1] = rt1320->r0_r_reg; + + return 0; +} + +static int rt1320_r0_load_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(rt1320->component); + int ret; + + if (!rt1320->hw_init) + return 0; + + if (ucontrol->value.integer.value[0] == 0 || + ucontrol->value.integer.value[1] == 0) + return -EINVAL; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + snd_soc_dapm_mutex_lock(dapm); + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { + rt1320->r0_l_reg = ucontrol->value.integer.value[0]; + rt1320->r0_r_reg = ucontrol->value.integer.value[1]; + rt1320_calc_r0(rt1320); + rt1320_r0_load(rt1320); + } + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + +static int rt1320_t0_r0_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.max = kcontrol->private_value; + + return 0; +} + +#define RT1320_T0_R0_LOAD(xname, xmax, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = rt1320_t0_r0_load_info, \ + .get = xhandler_get, \ + .put = xhandler_put, \ + .private_value = xmax, \ +} + +static int rt1320_dspfw_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1320->fw_load_done; + return 0; +} + +static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + int ret; + + if (!rt1320->hw_init) + return 0; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF && + ucontrol->value.integer.value[0]) + rt1320_dspfw_load_code(rt1320); + + if (!ucontrol->value.integer.value[0]) + rt1320->fw_load_done = false; + + return 0; +} + +static int rt1320_r0_temperature_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1320->temp_l_calib; + ucontrol->value.integer.value[1] = rt1320->temp_r_calib; + return 0; +} + +static int rt1320_r0_temperature_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(rt1320->component); + int ret; + + if (!rt1320->hw_init) + return 0; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + snd_soc_dapm_mutex_lock(dapm); + if ((snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) && + ucontrol->value.integer.value[0] && ucontrol->value.integer.value[1]) + rt1320_t0_load(rt1320, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + static const struct snd_kcontrol_new rt1320_snd_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume", SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), @@ -1371,6 +2368,15 @@ static const struct snd_kcontrol_new rt1320_snd_controls[] = { RT_SDCA_EXT_TLV("FU Capture Volume", SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), rt1320_set_gain_get, rt1320_set_gain_put, 4, 0x3f, in_vol_tlv, rt1320_dmic_fu_info), + + SOC_SINGLE_EXT("R0 Calibration", SND_SOC_NOPM, 0, 1, 0, + rt1320_r0_cali_get, rt1320_r0_cali_put), + SOC_SINGLE_EXT("DSP FW Update", SND_SOC_NOPM, 0, 1, 0, + rt1320_dspfw_load_get, rt1320_dspfw_load_put), + RT1320_T0_R0_LOAD("R0 Load Mode", 0xffffffff, + rt1320_r0_load_mode_get, rt1320_r0_load_mode_put), + RT1320_T0_R0_LOAD("R0 Temperature", 0xff, + rt1320_r0_temperature_get, rt1320_r0_temperature_put), }; static const struct snd_kcontrol_new rt1320_spk_l_dac = @@ -1606,6 +2612,18 @@ static int rt1320_sdw_component_probe(struct snd_soc_component *component) if (ret < 0 && ret != -EACCES) return ret; + /* Apply temperature and calibration data from device property */ + if ((rt1320->temp_l_calib <= 0xff) && (rt1320->temp_l_calib > 0) && + (rt1320->temp_r_calib <= 0xff) && (rt1320->temp_r_calib > 0)) + rt1320_t0_load(rt1320, rt1320->temp_l_calib, rt1320->temp_r_calib); + + if (rt1320->r0_l_calib && rt1320->r0_r_calib) { + rt1320->r0_l_reg = rt1320->r0_l_calib; + rt1320->r0_r_reg = rt1320->r0_r_calib; + rt1320_calc_r0(rt1320); + rt1320_r0_load(rt1320); + } + return 0; } @@ -1667,6 +2685,26 @@ static struct snd_soc_dai_driver rt1320_sdw_dai[] = { }, }; +static int rt1320_parse_dp(struct rt1320_sdw_priv *rt1320, struct device *dev) +{ + device_property_read_u32(dev, "realtek,temperature_l_calib", + &rt1320->temp_l_calib); + device_property_read_u32(dev, "realtek,temperature_r_calib", + &rt1320->temp_r_calib); + device_property_read_u32(dev, "realtek,r0_l_calib", + &rt1320->r0_l_calib); + device_property_read_u32(dev, "realtek,r0_r_calib", + &rt1320->r0_r_calib); + device_property_read_string(dev, "realtek,dspfw-name", + &rt1320->dspfw_name); + + dev_dbg(dev, "%s: temp_l_calib: %d temp_r_calib: %d r0_l_calib: %d, r0_r_calib: %d", + __func__, rt1320->temp_l_calib, rt1320->temp_r_calib, rt1320->r0_l_calib, rt1320->r0_r_calib); + dev_dbg(dev, "%s: dspfw_name: %s", __func__, rt1320->dspfw_name); + + return 0; +} + static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, struct regmap *mbq_regmap, struct sdw_slave *slave) { @@ -1685,6 +2723,8 @@ static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, regcache_cache_only(rt1320->regmap, true); regcache_cache_only(rt1320->mbq_regmap, true); + rt1320_parse_dp(rt1320, dev); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1696,6 +2736,8 @@ static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] = rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true; + INIT_WORK(&rt1320->load_dspfw_work, rt1320_load_dspfw_work); + ret = devm_snd_soc_register_component(dev, &soc_component_sdw_rt1320, rt1320_sdw_dai, @@ -1742,6 +2784,9 @@ static int rt1320_sdw_probe(struct sdw_slave *slave, static int rt1320_sdw_remove(struct sdw_slave *slave) { + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev); + + cancel_work_sync(&rt1320->load_dspfw_work); pm_runtime_disable(&slave->dev); return 0; diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index a6d90e259dc9d..5a9f496dd848f 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -13,6 +13,7 @@ #include #include #include +#include "../../../drivers/soundwire/bus.h" #define RT1320_DEV_ID 0x6981 #define RT1321_DEV_ID 0x7045 @@ -22,6 +23,8 @@ #define RT1320_DEV_ID_1 0xc405 #define RT1320_DEV_ID_0 0xc406 +#define RT1320_POWER_STATE 0xc560 + #define RT1321_PATCH_MAIN_VER 0x1000cffe #define RT1321_PATCH_BETA_VER 0x1000cfff @@ -96,6 +99,57 @@ enum rt1320_version_id { #define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" #define RT1321_VA_MCU_PATCH "realtek/rt1320/rt1321-patch-code-va.bin" +#define RT1320_FW_PARAM_ADDR 0x3fc2ab80 +#define RT1320_CMD_ID 0x3fc2ab81 +#define RT1320_CMD_PARAM_ADDR 0x3fc2ab90 +#define RT1320_DSPFW_STATUS_ADDR 0x3fc2bfc4 + +#define RT1321_FW_PARAM_ADDR 0x3fc2d300 +#define RT1321_CMD_ID 0x3fc2d301 +#define RT1321_CMD_PARAM_ADDR 0x3fc2d310 +#define RT1321_DSPFW_STATUS_ADDR 0x3fc2dfc4 + +/* FW parameter id 6, 7 */ +struct rt1320_datafixpoint { + int silencedetect; + int r0; + int meanr0; + int advancegain; + int ts; + int re; + int t; + int invrs; +}; + +struct rt1320_paramcmd { + unsigned char moudleid; + unsigned char commandtype; + unsigned short reserved1; + unsigned int commandlength; + long long reserved2; + unsigned int paramid; + unsigned int paramlength; +}; + +enum rt1320_fw_cmdid { + RT1320_FW_READY, + RT1320_SET_PARAM, + RT1320_GET_PARAM, + RT1320_GET_POOLSIZE, +}; + +enum rt1320_power_state { + RT1320_NORMAL_STATE = 0x18, + RT1320_K_R0_STATE = 0x1b, +}; + +enum rt1320_rw_type { + RT1320_BRA_WRITE = 0, + RT1320_BRA_READ = 1, + RT1320_PARAM_WRITE = 2, + RT1320_PARAM_READ = 3, +}; + struct rt1320_sdw_priv { struct snd_soc_component *component; struct regmap *regmap; @@ -108,6 +162,18 @@ struct rt1320_sdw_priv { unsigned int dev_id; bool fu_dapm_mute; bool fu_mixer_mute[4]; + unsigned long long r0_l_reg; + unsigned long long r0_r_reg; + unsigned int r0_l_calib; + unsigned int r0_r_calib; + unsigned int temp_l_calib; + unsigned int temp_r_calib; + const char *dspfw_name; + bool cali_done; + bool fw_load_done; + bool rae_update_done; + struct work_struct load_dspfw_work; + struct sdw_bpt_msg bra_msg; }; #endif /* __RT1320_SDW_H__ */ -- 2.47.3