diff options
Diffstat (limited to 'sound/soc/codecs/rt1015.c')
-rw-r--r-- | sound/soc/codecs/rt1015.c | 233 |
1 files changed, 177 insertions, 56 deletions
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 25fe2ddedd54..32e6bcf763d1 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -27,10 +27,15 @@ #include <sound/soc-dapm.h> #include <sound/soc.h> #include <sound/tlv.h> +#include <sound/rt1015.h> #include "rl6231.h" #include "rt1015.h" +static const struct rt1015_platform_data i2s_default_platform_data = { + .power_up_delay_ms = 50, +}; + static const struct reg_default rt1015_reg[] = { { 0x0000, 0x0000 }, { 0x0004, 0xa000 }, @@ -492,18 +497,40 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015) snd_soc_dapm_mutex_lock(&component->dapm); regcache_cache_bypass(regmap, true); - regmap_write(regmap, RT1015_PWR1, 0xd7df); - regmap_write(regmap, RT1015_PWR4, 0x00b2); - regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2008); + regmap_write(regmap, RT1015_PWR9, 0xAA60); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0089); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008A); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008C); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008D); + regmap_write(regmap, RT1015_PWR4, 0x80B2); + regmap_write(regmap, RT1015_CLASSD_SEQ, 0x5797); + regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2100); + regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0100); + regmap_write(regmap, RT1015_PWR5, 0x2175); + regmap_write(regmap, RT1015_MIXER1, 0x005D); + regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1); + regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12F7); + regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x1205); + msleep(200); + regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2000); + regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0180); + regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1); + regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x0A05); + msleep(200); + regmap_write(regmap, RT1015_PWR4, 0x00B2); + regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028); regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140); - regmap_write(regmap, RT1015_GAT_BOOST, 0x0efe); - regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000d); - regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000e); - regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a00); - regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a01); - regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a05); - msleep(500); - regmap_write(regmap, RT1015_PWR1, 0x0); + regmap_write(regmap, RT1015_PWR5, 0x0175); + regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x1721); + regmap_write(regmap, RT1015_CLASSD_SEQ, 0x570E); + regmap_write(regmap, RT1015_MIXER1, 0x203D); + regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5A01); + regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12FF); + regmap_write(regmap, RT1015_GAT_BOOST, 0x0eFE); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008E); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0088); + regmap_write(regmap, RT1015_SYS_RST1, 0x05F5); + regmap_write(regmap, RT1015_SYS_RST2, 0x0b9a); regcache_cache_bypass(regmap, false); regcache_mark_dirty(regmap); @@ -539,7 +566,7 @@ static void rt1015_flush_work(struct work_struct *work) struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv, flush_work.work); struct snd_soc_component *component = rt1015->component; - unsigned int val, i = 0, count = 20; + unsigned int val, i = 0, count = 200; while (i < count) { usleep_range(1000, 1500); @@ -599,6 +626,8 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f7); snd_soc_component_write(component, + RT1015_SYS_RST2, 0x0b0a); + snd_soc_component_write(component, RT1015_GAT_BOOST, 0xacfe); snd_soc_component_write(component, RT1015_PWR9, 0xaa00); @@ -606,9 +635,13 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, RT1015_GAT_BOOST, 0xecfe); } else { snd_soc_component_write(component, + 0x032d, 0xaa60); + snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f7); snd_soc_component_write(component, - RT1015_PWR_STATE_CTRL, 0x026e); + RT1015_SYS_RST2, 0x0b0a); + snd_soc_component_write(component, + RT1015_PWR_STATE_CTRL, 0x008e); } break; @@ -622,11 +655,17 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, RT1015_PWR9, 0xa800); snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f5); + snd_soc_component_write(component, + RT1015_SYS_RST2, 0x0b9a); } else { snd_soc_component_write(component, - RT1015_PWR_STATE_CTRL, 0x0268); + 0x032d, 0xaa60); + snd_soc_component_write(component, + RT1015_PWR_STATE_CTRL, 0x0088); snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f5); + snd_soc_component_write(component, + RT1015_SYS_RST2, 0x0b9a); } rt1015->dac_is_used = 0; @@ -650,6 +689,7 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: if (rt1015->hw_config == RT1015_HW_28) schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10)); + msleep(rt1015->pdata.power_up_delay_ms); break; default: break; @@ -658,38 +698,12 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("INT RC CLK", RT1015_PWR1, RT1015_PWR_INTCLK_BIT, - 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ISENSE", RT1015_PWR1, RT1015_PWR_ISENSE_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("VSENSE", RT1015_PWR1, RT1015_PWR_VSENSE_BIT, 0, - NULL, 0), SND_SOC_DAPM_SUPPLY("PLL", RT1015_PWR1, RT1015_PWR_PLL_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("BG1 BG2", RT1015_PWR1, RT1015_PWR_BG_1_2_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("MBIAS BG", RT1015_PWR1, RT1015_PWR_MBIAS_BG_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("VBAT", RT1015_PWR1, RT1015_PWR_VBAT_BIT, 0, NULL, - 0), - SND_SOC_DAPM_SUPPLY("MBIAS", RT1015_PWR1, RT1015_PWR_MBIAS_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("ADCV", RT1015_PWR1, RT1015_PWR_ADCV_BIT, 0, NULL, - 0), - SND_SOC_DAPM_SUPPLY("MIXERV", RT1015_PWR1, RT1015_PWR_MIXERV_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("SUMV", RT1015_PWR1, RT1015_PWR_SUMV_BIT, 0, NULL, - 0), - SND_SOC_DAPM_SUPPLY("VREFLV", RT1015_PWR1, RT1015_PWR_VREFLV_BIT, 0, - NULL, 0), - SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC_E("DAC", NULL, RT1015_PWR1, RT1015_PWR_DAC_BIT, 0, + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_OUTPUT("SPO"), @@ -697,19 +711,7 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { static const struct snd_soc_dapm_route rt1015_dapm_routes[] = { { "DAC", NULL, "AIFRX" }, - { "DAC", NULL, "LDO2" }, { "DAC", NULL, "PLL", rt1015_is_sys_clk_from_pll}, - { "DAC", NULL, "INT RC CLK" }, - { "DAC", NULL, "ISENSE" }, - { "DAC", NULL, "VSENSE" }, - { "DAC", NULL, "BG1 BG2" }, - { "DAC", NULL, "MBIAS BG" }, - { "DAC", NULL, "VBAT" }, - { "DAC", NULL, "MBIAS" }, - { "DAC", NULL, "ADCV" }, - { "DAC", NULL, "MIXERV" }, - { "DAC", NULL, "SUMV" }, - { "DAC", NULL, "VREFLV" }, { "Amp Drv", NULL, "DAC" }, { "SPO", NULL, "Amp Drv" }, }; @@ -944,6 +946,106 @@ static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) return 0; } +static int rt1015_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + unsigned int val = 0, rx_slotnum, tx_slotnum; + int ret = 0, first_bit; + + switch (slots) { + case 2: + val |= RT1015_I2S_TX_2CH; + break; + case 4: + val |= RT1015_I2S_TX_4CH; + break; + case 6: + val |= RT1015_I2S_TX_6CH; + break; + case 8: + val |= RT1015_I2S_TX_8CH; + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + switch (slot_width) { + case 16: + val |= RT1015_I2S_CH_TX_LEN_16B; + break; + case 20: + val |= RT1015_I2S_CH_TX_LEN_20B; + break; + case 24: + val |= RT1015_I2S_CH_TX_LEN_24B; + break; + case 32: + val |= RT1015_I2S_CH_TX_LEN_32B; + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + if (rx_slotnum != 1) { + ret = -EINVAL; + dev_err(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + + /* This is an assumption that the system sends stereo audio to the amplifier typically. + * And the stereo audio is placed in slot 0/2/4/6 as the starting slot. + * The users could select the channel from L/R/L+R by "Mono LR Select" control. + */ + first_bit = __ffs(rx_mask); + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + snd_soc_component_update_bits(component, + RT1015_TDM1_4, + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + snd_soc_component_update_bits(component, + RT1015_TDM1_4, + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Tx slot configuration */ + tx_slotnum = hweight_long(tx_mask); + if (tx_slotnum) { + ret = -EINVAL; + dev_err(component->dev, "doesn't need to support tx slots\n"); + goto _set_tdm_err_; + } + + snd_soc_component_update_bits(component, RT1015_TDM1_1, + RT1015_I2S_CH_TX_MASK | RT1015_I2S_CH_RX_MASK | + RT1015_I2S_CH_TX_LEN_MASK | RT1015_I2S_CH_RX_LEN_MASK, val); + +_set_tdm_err_: + return ret; +} + static int rt1015_probe(struct snd_soc_component *component) { struct rt1015_priv *rt1015 = @@ -952,7 +1054,6 @@ static int rt1015_probe(struct snd_soc_component *component) rt1015->component = component; rt1015->bclk_ratio = 0; rt1015->cali_done = 0; - snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c); INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work); @@ -975,6 +1076,7 @@ static struct snd_soc_dai_ops rt1015_aif_dai_ops = { .hw_params = rt1015_hw_params, .set_fmt = rt1015_set_dai_fmt, .set_bclk_ratio = rt1015_set_bclk_ratio, + .set_tdm_slot = rt1015_set_tdm_slot, }; static struct snd_soc_dai_driver rt1015_dai[] = { @@ -1067,9 +1169,16 @@ static struct acpi_device_id rt1015_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt1015_acpi_match); #endif +static void rt1015_parse_dt(struct rt1015_priv *rt1015, struct device *dev) +{ + device_property_read_u32(dev, "realtek,power-up-delay-ms", + &rt1015->pdata.power_up_delay_ms); +} + static int rt1015_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct rt1015_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt1015_priv *rt1015; int ret; unsigned int val; @@ -1081,6 +1190,13 @@ static int rt1015_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt1015); + rt1015->pdata = i2s_default_platform_data; + + if (pdata) + rt1015->pdata = *pdata; + else + rt1015_parse_dt(rt1015, &i2c->dev); + rt1015->regmap = devm_regmap_init_i2c(i2c, &rt1015_regmap); if (IS_ERR(rt1015->regmap)) { ret = PTR_ERR(rt1015->regmap); @@ -1091,8 +1207,13 @@ static int rt1015_i2c_probe(struct i2c_client *i2c, rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28; - regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val); - if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) { + ret = regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val); + if (ret) { + dev_err(&i2c->dev, + "Failed to read device register: %d\n", ret); + return ret; + } else if ((val != RT1015_DEVICE_ID_VAL) && + (val != RT1015_DEVICE_ID_VAL2)) { dev_err(&i2c->dev, "Device with ID register %x is not rt1015\n", val); return -ENODEV; |