Unverified Commit 4ff52a69 authored by Mark Brown's avatar Mark Brown
Browse files

Add NAU8825C support

Merge series from David Lin <CTLIN0@nuvoton.com>:

This series adds nau8825c support. The driver can be used on
NAU8825B and NAU8825C.
parents 812a0525 955b503b
Loading
Loading
Loading
Loading
+93 −18
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ struct nau8825_fll {
	int mclk_src;
	int ratio;
	int fll_frac;
	int fll_frac_num;
	int fll_int;
	int clk_ref_div;
};
@@ -178,6 +179,8 @@ static const struct reg_default nau8825_reg_defaults[] = {
	{ NAU8825_REG_CLASSG_CTRL, 0x0 },
	{ NAU8825_REG_OPT_EFUSE_CTRL, 0x0 },
	{ NAU8825_REG_MISC_CTRL, 0x0 },
	{ NAU8825_REG_FLL2_LOWER, 0x0 },
	{ NAU8825_REG_FLL2_UPPER, 0x0 },
	{ NAU8825_REG_BIAS_ADJ, 0x0 },
	{ NAU8825_REG_TRIM_SETTINGS, 0x0 },
	{ NAU8825_REG_ANALOG_CONTROL_1, 0x0 },
@@ -200,6 +203,23 @@ static struct reg_default nau8825_xtalk_baktab[] = {
	{ NAU8825_REG_DACR_CTRL, 0x02cf },
};

/* The regmap patch for Rev C */
static const struct reg_sequence nau8825_regmap_patch[] = {
	{ NAU8825_REG_FLL2, 0x0000 },
	{ NAU8825_REG_FLL4, 0x8010 },
	{ NAU8825_REG_FLL_VCO_RSV, 0x0bc0 },
	{ NAU8825_REG_INTERRUPT_MASK, 0x0800 },
	{ NAU8825_REG_DACL_CTRL, 0x00cf },
	{ NAU8825_REG_DACR_CTRL, 0x02cf },
	{ NAU8825_REG_OPT_EFUSE_CTRL, 0x0400 },
	{ NAU8825_REG_FLL2_LOWER, 0x26e9 },
	{ NAU8825_REG_FLL2_UPPER, 0x0031 },
	{ NAU8825_REG_ANALOG_CONTROL_2, 0x0020 },
	{ NAU8825_REG_ANALOG_ADC_2, 0x0220 },
	{ NAU8825_REG_MIC_BIAS, 0x0046 },
};


static const unsigned short logtable[256] = {
	0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
	0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
@@ -608,8 +628,13 @@ static void nau8825_xtalk_prepare(struct nau8825 *nau8825)
	regmap_update_bits(nau8825->regmap,
		NAU8825_REG_INTERRUPT_MASK, NAU8825_IRQ_RMS_EN, 0);
	/* Power up left and right DAC */
	if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
		regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
	else
		regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
}

static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825)
@@ -622,9 +647,14 @@ static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825)
		NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L,
		NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
	/* Power down left and right DAC */
	if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
		regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
	else
		regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);

	/* Enable the TESTDAC and  disable L/R HP impedance */
	regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
		NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP |
@@ -855,7 +885,7 @@ static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
	case NAU8825_REG_IMM_MODE_CTRL ... NAU8825_REG_IMM_RMS_R:
	case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
	case NAU8825_REG_MISC_CTRL:
	case NAU8825_REG_I2C_DEVICE_ID ... NAU8825_REG_SARDOUT_RAM_STATUS:
	case NAU8825_REG_I2C_DEVICE_ID ... NAU8825_REG_FLL2_UPPER:
	case NAU8825_REG_BIAS_ADJ:
	case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
	case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
@@ -881,6 +911,7 @@ static bool nau8825_writeable_reg(struct device *dev, unsigned int reg)
	case NAU8825_REG_IMM_MODE_CTRL:
	case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
	case NAU8825_REG_MISC_CTRL:
	case NAU8825_REG_FLL2_LOWER ... NAU8825_REG_FLL2_UPPER:
	case NAU8825_REG_BIAS_ADJ:
	case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
	case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
@@ -996,10 +1027,25 @@ static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
		/* Disables the TESTDAC to let DAC signal pass through. */
		regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
			NAU8825_BIAS_TESTDAC_EN, 0);
		if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
			regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
					   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
		else
			regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
					   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
					   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
		break;
	case SND_SOC_DAPM_POST_PMD:
		regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
			NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
		if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
			regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
					   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
					   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
		else
			regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
					   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);

		break;
	default:
		return -EINVAL;
@@ -1207,12 +1253,13 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
		NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),

	SND_SOC_DAPM_PGA_S("Output DACL", 7,
		NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event,
		SND_SOC_NOPM, 0, 0, nau8825_output_dac_event,
		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_PGA_S("Output DACR", 7,
		NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event,
		SND_SOC_NOPM, 0, 0, nau8825_output_dac_event,
		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),


	/* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */
	SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8,
		NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0),
@@ -2206,6 +2253,7 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
	regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
		NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64);
	/* Disable DACR/L power */
	if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
		regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
				   NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
@@ -2340,9 +2388,12 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
	/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
	 * input based on FDCO, FREF and FLL ratio.
	 */
	fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
	fll_param->fll_int = (fvco >> 16) & 0x3FF;
	fvco = div_u64(fvco_max << fll_param->fll_frac_num, fref * fll_param->ratio);
	fll_param->fll_int = (fvco >> fll_param->fll_frac_num) & 0x3FF;
	if (fll_param->fll_frac_num == 16)
		fll_param->fll_frac = fvco & 0xFFFF;
	else
		fll_param->fll_frac = fvco & 0xFFFFFF;
	return 0;
}

@@ -2356,8 +2407,16 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
		NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK,
		fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT));
	/* FLL 16-bit fractional input */
	regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);
	/* FLL 16/24 bit fractional input */
	if (fll_param->fll_frac_num == 16)
		regmap_write(nau8825->regmap, NAU8825_REG_FLL2,
			     fll_param->fll_frac);
	else {
		regmap_write(nau8825->regmap, NAU8825_REG_FLL2_LOWER,
			     fll_param->fll_frac & 0xffff);
		regmap_write(nau8825->regmap, NAU8825_REG_FLL2_UPPER,
			     (fll_param->fll_frac >> 16) & 0xff);
	}
	/* FLL 10-bit integer input */
	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL3,
			NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
@@ -2399,6 +2458,11 @@ static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int
	struct nau8825_fll fll_param;
	int ret, fs;

	if (nau8825->sw_id == NAU8825_SOFTWARE_ID_NAU8825)
		fll_param.fll_frac_num = 16;
	else
		fll_param.fll_frac_num = 24;

	fs = freq_out / 256;
	ret = nau8825_calc_fll_param(freq_in, fs, &fll_param);
	if (ret < 0) {
@@ -2930,8 +2994,19 @@ static int nau8825_i2c_probe(struct i2c_client *i2c)
			ret);
		return ret;
	}
	if ((value & NAU8825_SOFTWARE_ID_MASK) !=
			NAU8825_SOFTWARE_ID_NAU8825) {
	nau8825->sw_id = value & NAU8825_SOFTWARE_ID_MASK;
	switch (nau8825->sw_id) {
	case NAU8825_SOFTWARE_ID_NAU8825:
		break;
	case NAU8825_SOFTWARE_ID_NAU8825C:
		ret = regmap_register_patch(nau8825->regmap, nau8825_regmap_patch,
					    ARRAY_SIZE(nau8825_regmap_patch));
		if (ret) {
			dev_err(dev, "Failed to register Rev C patch: %d\n", ret);
			return ret;
		}
		break;
	default:
		dev_err(dev, "Not a NAU8825 chip\n");
		return -ENODEV;
	}
+4 −0
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@
#define NAU8825_REG_MISC_CTRL		0x55
#define NAU8825_REG_I2C_DEVICE_ID		0x58
#define NAU8825_REG_SARDOUT_RAM_STATUS		0x59
#define NAU8825_REG_FLL2_LOWER		0x5a
#define NAU8825_REG_FLL2_UPPER		0x5b
#define NAU8825_REG_BIAS_ADJ		0x66
#define NAU8825_REG_TRIM_SETTINGS		0x68
#define NAU8825_REG_ANALOG_CONTROL_1		0x69
@@ -386,6 +388,7 @@
#define NAU8825_GPIO2JD1	(1 << 7)
#define NAU8825_SOFTWARE_ID_MASK	0x3
#define NAU8825_SOFTWARE_ID_NAU8825	0x0
#define NAU8825_SOFTWARE_ID_NAU8825C	0x1

/* BIAS_ADJ (0x66) */
#define NAU8825_BIAS_HPR_IMP		(1 << 15)
@@ -497,6 +500,7 @@ struct nau8825 {
	struct clk *mclk;
	struct work_struct xtalk_work;
	struct semaphore xtalk_sem;
	int sw_id;
	int irq;
	int mclk_freq; /* 0 - mclk is disabled */
	int button_pressed;