staticbool rtq9128_is_readable_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case 0x00 ... 0x2B: case 0x30 ... 0x35: case 0x40 ... 0x56: case 0x5C ... 0x76: case 0x80 ... 0xAD: case 0xB0 ... 0xBA: case 0xC0 ... 0xE5: case 0xF0 ... 0xFB: returntrue; default: returnfalse;
}
}
staticbool rtq9128_is_writeable_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case 0x00 ... 0x1F: case 0x21 ... 0x2B: case 0x30 ... 0x35: case 0x40 ... 0x56: case 0x5C ... 0x76: case 0x80 ... 0x8B: case 0xA0 ... 0xAD: case 0xB0 ... 0xBA: case 0xC0: case 0xD0 ... 0xDE: case 0xE0 ... 0xE5: case 0xF0 ... 0xF3: case 0xF6 ... 0xF8: case 0xFA ... 0xFB: returntrue; default: returnfalse;
}
}
staticbool rtq9128_is_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case 0x0F ... 0x17: case 0x20: case 0x53: case 0x55: case 0x5C ... 0x6F: case 0x8C ... 0x9F: case 0xC0 ... 0xCF: case 0xDF: case 0xF0 ... 0xF1: case 0xF4 ... 0xF5: returntrue; default: returnfalse;
}
}
/* * In general usage, DVDD could be 1P8V, 3P0V or 3P3V. * This DVDD undervoltage protection is to prevent from the abnormal power * lose case while the amplifier is operating. Due to the different DVDD * application, treat this threshold as a user choosable option.
*/ staticconststruct soc_enum rtq9128_dvdduv_select_enum =
SOC_ENUM_SINGLE(RTQ9128_REG_PROT_OPT, 6, ARRAY_SIZE(dvdduv_select_text),
dvdduv_select_text);
/* Turn channel state to Normal or HiZ */
ret = snd_soc_component_write_field(comp, RTQ9128_REG_STATE_CTRL, mask,
event != SND_SOC_DAPM_POST_PMU); if (ret < 0) return ret;
/* * For each channel turns on, HW will trigger DC load detect and DC * offset calibration, the time is needed for all the actions done.
*/ if (event == SND_SOC_DAPM_POST_PMU)
msleep(25);
/* Only support bitclock & framesync as consumer */ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) {
dev_err(dev, "Only support BCK and LRCK as consumer\n"); return -EINVAL;
}
/* Store here and will be used in runtime hw_params for DAI format setting */
data->daifmt = fmt;
return 0;
}
staticint rtq9128_dai_set_tdm_slot(struct snd_soc_dai *dai, unsignedint tx_mask, unsignedint rx_mask, int slots, int slot_width)
{ struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai); struct snd_soc_component *comp = dai->component; struct device *dev = dai->dev; unsignedint mask, start_loc, srcin_select; int i, frame_length, ret;
for (mask = tx_mask, i = 0; i < 4 && mask; i++) {
start_loc = (ffs(mask) - 1) * slot_width / 8;
mask &= ~BIT(ffs(mask) - 1);
ret = snd_soc_component_write(comp, RTQ9128_REG_TDM_TX_CH1 + i, start_loc); if (ret < 0) {
dev_err(dev, "Failed to assign tx_loc %d (%d)\n", i, ret); return ret;
}
}
for (mask = rx_mask, i = 0; i < 4 && mask; i++) {
start_loc = (ffs(mask) - 1) * slot_width / 8;
mask &= ~BIT(ffs(mask) - 1);
ret = snd_soc_component_write(comp, RTQ9128_REG_TDM_RX_CH1 + i, start_loc); if (ret < 0) {
dev_err(dev, "Failed to assign rx_loc %d (%d)\n", i, ret); return ret;
}
}
srcin_select = data->tdm_input_data2_select ? RTQ9128_TDMSRCIN_MASK : 0;
ret = snd_soc_component_update_bits(comp, RTQ9128_REG_SDO_SEL, RTQ9128_TDMSRCIN_MASK,
srcin_select); if (ret < 0) {
dev_err(dev, "Failed to configure TDM source input select\n"); return ret;
}
fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, data->daifmt); if (data->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && fmtval != SND_SOC_DAIFMT_DSP_B) {
dev_err(dev, "TDM is used, format only support DSP_A or DSP_B\n"); return -EINVAL;
}
switch (fmtval) { case SND_SOC_DAIFMT_I2S:
audfmt = 8; break; case SND_SOC_DAIFMT_LEFT_J:
audfmt = 9; break; case SND_SOC_DAIFMT_RIGHT_J:
audfmt = 10; break; case SND_SOC_DAIFMT_DSP_A:
audfmt = data->tdm_slots ? 12 : 11; break; case SND_SOC_DAIFMT_DSP_B:
audfmt = data->tdm_slots ? 4 : 3; break; default:
dev_err(dev, "Unsupported format 0x%8x\n", fmtval); return -EINVAL;
}
switch (width = params_width(param)) { case 16:
audbit = 0; break; case 18:
audbit = 1; break; case 20:
audbit = 2; break; case 24: case 32:
audbit = 3; break; default:
dev_err(dev, "Unsupported width (%d)\n", width); return -EINVAL;
}
slot_width = params_physical_width(param);
if (data->tdm_slots) { if (slot_width > data->tdm_slot_width) {
dev_err(dev, "slot width is larger than TDM slot width\n"); return -EINVAL;
}
/* Check BCK not exceed the maximum supported rate 24.576MHz */
bitrate = data->tdm_slots * data->tdm_slot_width * params_rate(param); if (bitrate > 24576000) {
dev_err(dev, "bitrate exceed the maximum (%d)\n", bitrate); return -EINVAL;
}
/* If TDM is used, configure slot width as TDM slot witdh */
slot_width = data->tdm_slot_width;
}
/* * Due to the bad design to combine SOFT_RESET bit with other function, * directly use generic i2c API to trigger SOFT_RESET.
*/
ret = i2c_smbus_write_byte_data(i2c, RTQ9128_REG_MISC, RTQ9128_SOFT_RESET_VAL); if (ret) return dev_err_probe(dev, ret, "Failed to trigger software reset\n");
/* After trigger soft reset, have to wait 10ms for digital reset done */
usleep_range(10000, 11000);
regmap = devm_regmap_init(dev, &rtq9128_regmap_bus, dev, &rtq9128_regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
ret = regmap_read(regmap, RTQ9128_REG_VENDOR_ID, &venid); if (ret) return dev_err_probe(dev, ret, "Failed to get vendor id\n");
venid = FIELD_GET(RTQ9128_VENDOR_ID_MASK, venid); if (venid != RTQ9128_VENDOR_ID_VAL) return dev_err_probe(dev, -ENODEV, "Vendor ID not match (0x%x)\n", venid);
pm_runtime_set_active(dev);
pm_runtime_mark_last_busy(dev);
ret = devm_pm_runtime_enable(dev); if (ret) return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
/* If 'enable' gpio not specified, change all channels to ultra low quiescent */ if (!data->enable) return regmap_write(regmap, RTQ9128_REG_STATE_CTRL, RTQ9128_ALLCH_ULQM_VAL);
/* If 'enable' gpio not specified, change all channels to default Hi-Z */ if (!data->enable) return regmap_write(regmap, RTQ9128_REG_STATE_CTRL, RTQ9128_ALLCH_HIZ_VAL);
gpiod_set_value_cansleep(data->enable, 1);
/* Wait digital block to be ready */
usleep_range(10000, 11000);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.