xref: /openbmc/linux/sound/soc/codecs/adau7118.c (revision b5bfa727)
1ca514c0fSNuno Sá // SPDX-License-Identifier: GPL-2.0
2ca514c0fSNuno Sá //
3ca514c0fSNuno Sá // Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
4ca514c0fSNuno Sá //
5ca514c0fSNuno Sá // Copyright 2019 Analog Devices Inc.
6ca514c0fSNuno Sá 
7ca514c0fSNuno Sá #include <linux/bitfield.h>
8ca514c0fSNuno Sá #include <linux/module.h>
9ca514c0fSNuno Sá #include <linux/regmap.h>
10ca514c0fSNuno Sá #include <linux/regulator/consumer.h>
11ca514c0fSNuno Sá #include <sound/pcm_params.h>
12ca514c0fSNuno Sá #include <sound/soc.h>
13ca514c0fSNuno Sá 
14ca514c0fSNuno Sá #include "adau7118.h"
15ca514c0fSNuno Sá 
16ca514c0fSNuno Sá #define ADAU7118_DEC_RATIO_MASK		GENMASK(1, 0)
17ca514c0fSNuno Sá #define ADAU7118_DEC_RATIO(x)		FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)
18ca514c0fSNuno Sá #define ADAU7118_CLK_MAP_MASK		GENMASK(7, 4)
19ca514c0fSNuno Sá #define ADAU7118_SLOT_WIDTH_MASK	GENMASK(5, 4)
20ca514c0fSNuno Sá #define ADAU7118_SLOT_WIDTH(x)		FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)
21ca514c0fSNuno Sá #define ADAU7118_TRISTATE_MASK		BIT(6)
22ca514c0fSNuno Sá #define ADAU7118_TRISTATE(x)		FIELD_PREP(ADAU7118_TRISTATE_MASK, x)
23ca514c0fSNuno Sá #define ADAU7118_DATA_FMT_MASK		GENMASK(3, 1)
24ca514c0fSNuno Sá #define ADAU7118_DATA_FMT(x)		FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)
25ca514c0fSNuno Sá #define ADAU7118_SAI_MODE_MASK		BIT(0)
26ca514c0fSNuno Sá #define ADAU7118_SAI_MODE(x)		FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)
27ca514c0fSNuno Sá #define ADAU7118_LRCLK_BCLK_POL_MASK	GENMASK(1, 0)
28ca514c0fSNuno Sá #define ADAU7118_LRCLK_BCLK_POL(x) \
29ca514c0fSNuno Sá 				FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)
30ca514c0fSNuno Sá #define ADAU7118_SPT_SLOT_MASK		GENMASK(7, 4)
31ca514c0fSNuno Sá #define ADAU7118_SPT_SLOT(x)		FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)
32ca514c0fSNuno Sá #define ADAU7118_FULL_SOFT_R_MASK	BIT(1)
33ca514c0fSNuno Sá #define ADAU7118_FULL_SOFT_R(x)		FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)
34ca514c0fSNuno Sá 
35ca514c0fSNuno Sá struct adau7118_data {
36ca514c0fSNuno Sá 	struct regmap *map;
37ca514c0fSNuno Sá 	struct device *dev;
38ca514c0fSNuno Sá 	struct regulator *iovdd;
39ca514c0fSNuno Sá 	struct regulator *dvdd;
40ca514c0fSNuno Sá 	u32 slot_width;
41ca514c0fSNuno Sá 	u32 slots;
42ca514c0fSNuno Sá 	bool hw_mode;
43ca514c0fSNuno Sá 	bool right_j;
44ca514c0fSNuno Sá };
45ca514c0fSNuno Sá 
46ca514c0fSNuno Sá /* Input Enable */
47ca514c0fSNuno Sá static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {
48ca514c0fSNuno Sá 	SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),
49ca514c0fSNuno Sá 	SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),
50ca514c0fSNuno Sá 	SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),
51ca514c0fSNuno Sá 	SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),
52ca514c0fSNuno Sá };
53ca514c0fSNuno Sá 
54ca514c0fSNuno Sá static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {
55ca514c0fSNuno Sá 	/* Input Enable Switches */
56ca514c0fSNuno Sá 	SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,
57ca514c0fSNuno Sá 			    &adau7118_dapm_pdm_control[0]),
58ca514c0fSNuno Sá 	SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,
59ca514c0fSNuno Sá 			    &adau7118_dapm_pdm_control[1]),
60ca514c0fSNuno Sá 	SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,
61ca514c0fSNuno Sá 			    &adau7118_dapm_pdm_control[2]),
62ca514c0fSNuno Sá 	SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,
63ca514c0fSNuno Sá 			    &adau7118_dapm_pdm_control[3]),
64ca514c0fSNuno Sá 
65ca514c0fSNuno Sá 	/* PDM Clocks */
66ca514c0fSNuno Sá 	SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),
67ca514c0fSNuno Sá 	SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),
68ca514c0fSNuno Sá 
69ca514c0fSNuno Sá 	/* Output channels */
70ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
71ca514c0fSNuno Sá 			     0, 0),
72ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
73ca514c0fSNuno Sá 			     0, 0),
74ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
75ca514c0fSNuno Sá 			     0, 0),
76ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
77ca514c0fSNuno Sá 			     0, 0),
78ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
79ca514c0fSNuno Sá 			     0, 0),
80ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
81ca514c0fSNuno Sá 			     0, 0),
82ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
83ca514c0fSNuno Sá 			     0, 0),
84ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
85ca514c0fSNuno Sá 			     0, 0),
86ca514c0fSNuno Sá };
87ca514c0fSNuno Sá 
88ca514c0fSNuno Sá static const struct snd_soc_dapm_route adau7118_routes_sw[] = {
89ca514c0fSNuno Sá 	{ "PDM0", "Capture Switch", "PDM_DAT0" },
90ca514c0fSNuno Sá 	{ "PDM1", "Capture Switch", "PDM_DAT1" },
91ca514c0fSNuno Sá 	{ "PDM2", "Capture Switch", "PDM_DAT2" },
92ca514c0fSNuno Sá 	{ "PDM3", "Capture Switch", "PDM_DAT3" },
93ca514c0fSNuno Sá 	{ "AIF1TX1", NULL, "PDM0" },
94ca514c0fSNuno Sá 	{ "AIF1TX2", NULL, "PDM0" },
95ca514c0fSNuno Sá 	{ "AIF1TX3", NULL, "PDM1" },
96ca514c0fSNuno Sá 	{ "AIF1TX4", NULL, "PDM1" },
97ca514c0fSNuno Sá 	{ "AIF1TX5", NULL, "PDM2" },
98ca514c0fSNuno Sá 	{ "AIF1TX6", NULL, "PDM2" },
99ca514c0fSNuno Sá 	{ "AIF1TX7", NULL, "PDM3" },
100ca514c0fSNuno Sá 	{ "AIF1TX8", NULL, "PDM3" },
101ca514c0fSNuno Sá 	{ "Capture", NULL, "PDM_CLK0" },
102ca514c0fSNuno Sá 	{ "Capture", NULL, "PDM_CLK1" },
103ca514c0fSNuno Sá };
104ca514c0fSNuno Sá 
105ca514c0fSNuno Sá static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {
106ca514c0fSNuno Sá 	SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
107ca514c0fSNuno Sá };
108ca514c0fSNuno Sá 
109ca514c0fSNuno Sá static const struct snd_soc_dapm_route adau7118_routes_hw[] = {
110ca514c0fSNuno Sá 	{ "AIF1TX", NULL, "PDM_DAT0" },
111ca514c0fSNuno Sá 	{ "AIF1TX", NULL, "PDM_DAT1" },
112ca514c0fSNuno Sá 	{ "AIF1TX", NULL, "PDM_DAT2" },
113ca514c0fSNuno Sá 	{ "AIF1TX", NULL, "PDM_DAT3" },
114ca514c0fSNuno Sá };
115ca514c0fSNuno Sá 
116ca514c0fSNuno Sá static const struct snd_soc_dapm_widget adau7118_widgets[] = {
117ca514c0fSNuno Sá 	SND_SOC_DAPM_INPUT("PDM_DAT0"),
118ca514c0fSNuno Sá 	SND_SOC_DAPM_INPUT("PDM_DAT1"),
119ca514c0fSNuno Sá 	SND_SOC_DAPM_INPUT("PDM_DAT2"),
120ca514c0fSNuno Sá 	SND_SOC_DAPM_INPUT("PDM_DAT3"),
121ca514c0fSNuno Sá };
122ca514c0fSNuno Sá 
adau7118_set_channel_map(struct snd_soc_dai * dai,unsigned int tx_num,unsigned int * tx_slot,unsigned int rx_num,unsigned int * rx_slot)123ca514c0fSNuno Sá static int adau7118_set_channel_map(struct snd_soc_dai *dai,
124ca514c0fSNuno Sá 				    unsigned int tx_num, unsigned int *tx_slot,
125ca514c0fSNuno Sá 				    unsigned int rx_num, unsigned int *rx_slot)
126ca514c0fSNuno Sá {
127ca514c0fSNuno Sá 	struct adau7118_data *st =
128ca514c0fSNuno Sá 		snd_soc_component_get_drvdata(dai->component);
129ca514c0fSNuno Sá 	int chan, ret;
130ca514c0fSNuno Sá 
131ca514c0fSNuno Sá 	dev_dbg(st->dev, "Set channel map, %d", tx_num);
132ca514c0fSNuno Sá 
133ca514c0fSNuno Sá 	for (chan = 0; chan < tx_num; chan++) {
134ca514c0fSNuno Sá 		ret = snd_soc_component_update_bits(dai->component,
135ca514c0fSNuno Sá 					ADAU7118_REG_SPT_CX(chan),
136ca514c0fSNuno Sá 					ADAU7118_SPT_SLOT_MASK,
137ca514c0fSNuno Sá 					ADAU7118_SPT_SLOT(tx_slot[chan]));
138ca514c0fSNuno Sá 		if (ret < 0)
139ca514c0fSNuno Sá 			return ret;
140ca514c0fSNuno Sá 	}
141ca514c0fSNuno Sá 
142ca514c0fSNuno Sá 	return 0;
143ca514c0fSNuno Sá }
144ca514c0fSNuno Sá 
adau7118_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)145ca514c0fSNuno Sá static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
146ca514c0fSNuno Sá {
147ca514c0fSNuno Sá 	struct adau7118_data *st =
148ca514c0fSNuno Sá 		snd_soc_component_get_drvdata(dai->component);
149ca514c0fSNuno Sá 	int ret = 0;
150ca514c0fSNuno Sá 	u32 regval;
151ca514c0fSNuno Sá 
152ca514c0fSNuno Sá 	dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
153ca514c0fSNuno Sá 
154ca514c0fSNuno Sá 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
155ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_I2S:
156ca514c0fSNuno Sá 		ret = snd_soc_component_update_bits(dai->component,
157ca514c0fSNuno Sá 						    ADAU7118_REG_SPT_CTRL1,
158ca514c0fSNuno Sá 						    ADAU7118_DATA_FMT_MASK,
159ca514c0fSNuno Sá 						    ADAU7118_DATA_FMT(0));
160ca514c0fSNuno Sá 		break;
161ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_LEFT_J:
162ca514c0fSNuno Sá 		ret = snd_soc_component_update_bits(dai->component,
163ca514c0fSNuno Sá 						    ADAU7118_REG_SPT_CTRL1,
164ca514c0fSNuno Sá 						    ADAU7118_DATA_FMT_MASK,
165ca514c0fSNuno Sá 						    ADAU7118_DATA_FMT(1));
166ca514c0fSNuno Sá 		break;
167ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_RIGHT_J:
168ca514c0fSNuno Sá 		st->right_j = true;
169ca514c0fSNuno Sá 		break;
170ca514c0fSNuno Sá 	default:
171ca514c0fSNuno Sá 		dev_err(st->dev, "Invalid format %d",
172ca514c0fSNuno Sá 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
173ca514c0fSNuno Sá 		return -EINVAL;
174ca514c0fSNuno Sá 	}
175ca514c0fSNuno Sá 
176ca514c0fSNuno Sá 	if (ret < 0)
177ca514c0fSNuno Sá 		return ret;
178ca514c0fSNuno Sá 
179ca514c0fSNuno Sá 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
180ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_NB_NF:
181ca514c0fSNuno Sá 		regval = ADAU7118_LRCLK_BCLK_POL(0);
182ca514c0fSNuno Sá 		break;
183ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_NB_IF:
184ca514c0fSNuno Sá 		regval = ADAU7118_LRCLK_BCLK_POL(2);
185ca514c0fSNuno Sá 		break;
186ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_IB_NF:
187ca514c0fSNuno Sá 		regval = ADAU7118_LRCLK_BCLK_POL(1);
188ca514c0fSNuno Sá 		break;
189ca514c0fSNuno Sá 	case SND_SOC_DAIFMT_IB_IF:
190ca514c0fSNuno Sá 		regval = ADAU7118_LRCLK_BCLK_POL(3);
191ca514c0fSNuno Sá 		break;
192ca514c0fSNuno Sá 	default:
193ca514c0fSNuno Sá 		dev_err(st->dev, "Invalid Inv mask %d",
194ca514c0fSNuno Sá 			fmt & SND_SOC_DAIFMT_INV_MASK);
195ca514c0fSNuno Sá 		return -EINVAL;
196ca514c0fSNuno Sá 	}
197ca514c0fSNuno Sá 
198ca514c0fSNuno Sá 	ret = snd_soc_component_update_bits(dai->component,
199ca514c0fSNuno Sá 					    ADAU7118_REG_SPT_CTRL2,
200ca514c0fSNuno Sá 					    ADAU7118_LRCLK_BCLK_POL_MASK,
201ca514c0fSNuno Sá 					    regval);
202ca514c0fSNuno Sá 	if (ret < 0)
203ca514c0fSNuno Sá 		return ret;
204ca514c0fSNuno Sá 
205ca514c0fSNuno Sá 	return 0;
206ca514c0fSNuno Sá }
207ca514c0fSNuno Sá 
adau7118_set_tristate(struct snd_soc_dai * dai,int tristate)208ca514c0fSNuno Sá static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
209ca514c0fSNuno Sá {
210ca514c0fSNuno Sá 	struct adau7118_data *st =
211ca514c0fSNuno Sá 		snd_soc_component_get_drvdata(dai->component);
212ca514c0fSNuno Sá 	int ret;
213ca514c0fSNuno Sá 
214ca514c0fSNuno Sá 	dev_dbg(st->dev, "Set tristate, %d\n", tristate);
215ca514c0fSNuno Sá 
216ca514c0fSNuno Sá 	ret = snd_soc_component_update_bits(dai->component,
217ca514c0fSNuno Sá 					    ADAU7118_REG_SPT_CTRL1,
218ca514c0fSNuno Sá 					    ADAU7118_TRISTATE_MASK,
219ca514c0fSNuno Sá 					    ADAU7118_TRISTATE(tristate));
220ca514c0fSNuno Sá 	if (ret < 0)
221ca514c0fSNuno Sá 		return ret;
222ca514c0fSNuno Sá 
223ca514c0fSNuno Sá 	return 0;
224ca514c0fSNuno Sá }
225ca514c0fSNuno Sá 
adau7118_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)226ca514c0fSNuno Sá static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
227ca514c0fSNuno Sá 				 unsigned int rx_mask, int slots,
228ca514c0fSNuno Sá 				 int slot_width)
229ca514c0fSNuno Sá {
230ca514c0fSNuno Sá 	struct adau7118_data *st =
231ca514c0fSNuno Sá 		snd_soc_component_get_drvdata(dai->component);
232ca514c0fSNuno Sá 	int ret = 0;
233ca514c0fSNuno Sá 	u32 regval;
234ca514c0fSNuno Sá 
235ca514c0fSNuno Sá 	dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
236ca514c0fSNuno Sá 
237ca514c0fSNuno Sá 	switch (slot_width) {
238ca514c0fSNuno Sá 	case 32:
239ca514c0fSNuno Sá 		regval = ADAU7118_SLOT_WIDTH(0);
240ca514c0fSNuno Sá 		break;
241ca514c0fSNuno Sá 	case 24:
242ca514c0fSNuno Sá 		regval = ADAU7118_SLOT_WIDTH(2);
243ca514c0fSNuno Sá 		break;
244ca514c0fSNuno Sá 	case 16:
245ca514c0fSNuno Sá 		regval = ADAU7118_SLOT_WIDTH(1);
246ca514c0fSNuno Sá 		break;
247ca514c0fSNuno Sá 	default:
248ca514c0fSNuno Sá 		dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
249ca514c0fSNuno Sá 		return -EINVAL;
250ca514c0fSNuno Sá 	}
251ca514c0fSNuno Sá 
252ca514c0fSNuno Sá 	ret = snd_soc_component_update_bits(dai->component,
253ca514c0fSNuno Sá 					    ADAU7118_REG_SPT_CTRL1,
254ca514c0fSNuno Sá 					    ADAU7118_SLOT_WIDTH_MASK, regval);
255ca514c0fSNuno Sá 	if (ret < 0)
256ca514c0fSNuno Sá 		return ret;
257ca514c0fSNuno Sá 
258ca514c0fSNuno Sá 	st->slot_width = slot_width;
259ca514c0fSNuno Sá 	st->slots = slots;
260ca514c0fSNuno Sá 
261ca514c0fSNuno Sá 	return 0;
262ca514c0fSNuno Sá }
263ca514c0fSNuno Sá 
adau7118_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)264ca514c0fSNuno Sá static int adau7118_hw_params(struct snd_pcm_substream *substream,
265ca514c0fSNuno Sá 			      struct snd_pcm_hw_params *params,
266ca514c0fSNuno Sá 			      struct snd_soc_dai *dai)
267ca514c0fSNuno Sá {
268ca514c0fSNuno Sá 	struct adau7118_data *st =
269ca514c0fSNuno Sá 		snd_soc_component_get_drvdata(dai->component);
270ca514c0fSNuno Sá 	u32 data_width = params_width(params), slots_width;
271ca514c0fSNuno Sá 	int ret;
272ca514c0fSNuno Sá 	u32 regval;
273ca514c0fSNuno Sá 
274ca514c0fSNuno Sá 	if (!st->slots) {
275ca514c0fSNuno Sá 		/* set stereo mode */
276ca514c0fSNuno Sá 		ret = snd_soc_component_update_bits(dai->component,
277ca514c0fSNuno Sá 						    ADAU7118_REG_SPT_CTRL1,
278ca514c0fSNuno Sá 						    ADAU7118_SAI_MODE_MASK,
279ca514c0fSNuno Sá 						    ADAU7118_SAI_MODE(0));
280ca514c0fSNuno Sá 		if (ret < 0)
281ca514c0fSNuno Sá 			return ret;
282ca514c0fSNuno Sá 
283ca514c0fSNuno Sá 		slots_width = 32;
284ca514c0fSNuno Sá 	} else {
285ca514c0fSNuno Sá 		slots_width = st->slot_width;
286ca514c0fSNuno Sá 	}
287ca514c0fSNuno Sá 
288ca514c0fSNuno Sá 	if (data_width > slots_width) {
289ca514c0fSNuno Sá 		dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
290ca514c0fSNuno Sá 			data_width, slots_width);
291ca514c0fSNuno Sá 		return -EINVAL;
292ca514c0fSNuno Sá 	}
293ca514c0fSNuno Sá 
294ca514c0fSNuno Sá 	if (st->right_j) {
295ca514c0fSNuno Sá 		switch (slots_width - data_width) {
296ca514c0fSNuno Sá 		case 8:
297ca514c0fSNuno Sá 			/* delay bclck by 8 */
298ca514c0fSNuno Sá 			regval = ADAU7118_DATA_FMT(2);
299ca514c0fSNuno Sá 			break;
300ca514c0fSNuno Sá 		case 12:
301ca514c0fSNuno Sá 			/* delay bclck by 12 */
302ca514c0fSNuno Sá 			regval = ADAU7118_DATA_FMT(3);
303ca514c0fSNuno Sá 			break;
304ca514c0fSNuno Sá 		case 16:
305ca514c0fSNuno Sá 			/* delay bclck by 16 */
306ca514c0fSNuno Sá 			regval = ADAU7118_DATA_FMT(4);
307ca514c0fSNuno Sá 			break;
308ca514c0fSNuno Sá 		default:
309ca514c0fSNuno Sá 			dev_err(st->dev,
310ca514c0fSNuno Sá 				"Cannot set right_j setting, slot_w:%d, data_w:%d\n",
311ca514c0fSNuno Sá 					slots_width, data_width);
312ca514c0fSNuno Sá 			return -EINVAL;
313ca514c0fSNuno Sá 		}
314ca514c0fSNuno Sá 
315ca514c0fSNuno Sá 		ret = snd_soc_component_update_bits(dai->component,
316ca514c0fSNuno Sá 						    ADAU7118_REG_SPT_CTRL1,
317ca514c0fSNuno Sá 						    ADAU7118_DATA_FMT_MASK,
318ca514c0fSNuno Sá 						    regval);
319ca514c0fSNuno Sá 		if (ret < 0)
320ca514c0fSNuno Sá 			return ret;
321ca514c0fSNuno Sá 	}
322ca514c0fSNuno Sá 
323ca514c0fSNuno Sá 	return 0;
324ca514c0fSNuno Sá }
325ca514c0fSNuno Sá 
adau7118_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)326ca514c0fSNuno Sá static int adau7118_set_bias_level(struct snd_soc_component *component,
327ca514c0fSNuno Sá 				   enum snd_soc_bias_level level)
328ca514c0fSNuno Sá {
329ca514c0fSNuno Sá 	struct adau7118_data *st = snd_soc_component_get_drvdata(component);
330ca514c0fSNuno Sá 	int ret = 0;
331ca514c0fSNuno Sá 
332ca514c0fSNuno Sá 	dev_dbg(st->dev, "Set bias level %d\n", level);
333ca514c0fSNuno Sá 
334ca514c0fSNuno Sá 	switch (level) {
335ca514c0fSNuno Sá 	case SND_SOC_BIAS_ON:
336ca514c0fSNuno Sá 	case SND_SOC_BIAS_PREPARE:
337ca514c0fSNuno Sá 		break;
338ca514c0fSNuno Sá 
339ca514c0fSNuno Sá 	case SND_SOC_BIAS_STANDBY:
340ca514c0fSNuno Sá 		if (snd_soc_component_get_bias_level(component) ==
341ca514c0fSNuno Sá 							SND_SOC_BIAS_OFF) {
342ca514c0fSNuno Sá 			/* power on */
343ca514c0fSNuno Sá 			ret = regulator_enable(st->iovdd);
344ca514c0fSNuno Sá 			if (ret)
345ca514c0fSNuno Sá 				return ret;
346ca514c0fSNuno Sá 
347ca514c0fSNuno Sá 			/* there's no timing constraints before enabling dvdd */
348ca514c0fSNuno Sá 			ret = regulator_enable(st->dvdd);
349ca514c0fSNuno Sá 			if (ret) {
350ca514c0fSNuno Sá 				regulator_disable(st->iovdd);
351ca514c0fSNuno Sá 				return ret;
352ca514c0fSNuno Sá 			}
353ca514c0fSNuno Sá 
354ca514c0fSNuno Sá 			if (st->hw_mode)
355ca514c0fSNuno Sá 				return 0;
356ca514c0fSNuno Sá 
357ca514c0fSNuno Sá 			regcache_cache_only(st->map, false);
358ca514c0fSNuno Sá 			/* sync cache */
359ca514c0fSNuno Sá 			ret = snd_soc_component_cache_sync(component);
360ca514c0fSNuno Sá 		}
361ca514c0fSNuno Sá 		break;
362ca514c0fSNuno Sá 	case SND_SOC_BIAS_OFF:
363ca514c0fSNuno Sá 		/* power off */
364ca514c0fSNuno Sá 		ret = regulator_disable(st->dvdd);
365ca514c0fSNuno Sá 		if (ret)
366ca514c0fSNuno Sá 			return ret;
367ca514c0fSNuno Sá 
368ca514c0fSNuno Sá 		ret = regulator_disable(st->iovdd);
369ca514c0fSNuno Sá 		if (ret)
370ca514c0fSNuno Sá 			return ret;
371ca514c0fSNuno Sá 
372ca514c0fSNuno Sá 		if (st->hw_mode)
373ca514c0fSNuno Sá 			return 0;
374ca514c0fSNuno Sá 
375ca514c0fSNuno Sá 		/* cache only */
376ca514c0fSNuno Sá 		regcache_mark_dirty(st->map);
377ca514c0fSNuno Sá 		regcache_cache_only(st->map, true);
378ca514c0fSNuno Sá 
379ca514c0fSNuno Sá 		break;
380ca514c0fSNuno Sá 	}
381ca514c0fSNuno Sá 
382ca514c0fSNuno Sá 	return ret;
383ca514c0fSNuno Sá }
384ca514c0fSNuno Sá 
adau7118_component_probe(struct snd_soc_component * component)385ca514c0fSNuno Sá static int adau7118_component_probe(struct snd_soc_component *component)
386ca514c0fSNuno Sá {
387ca514c0fSNuno Sá 	struct adau7118_data *st = snd_soc_component_get_drvdata(component);
388ca514c0fSNuno Sá 	struct snd_soc_dapm_context *dapm =
389ca514c0fSNuno Sá 					snd_soc_component_get_dapm(component);
390ca514c0fSNuno Sá 	int ret = 0;
391ca514c0fSNuno Sá 
392ca514c0fSNuno Sá 	if (st->hw_mode) {
393ca514c0fSNuno Sá 		ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
394ca514c0fSNuno Sá 					ARRAY_SIZE(adau7118_widgets_hw));
395ca514c0fSNuno Sá 		if (ret)
396ca514c0fSNuno Sá 			return ret;
397ca514c0fSNuno Sá 
398ca514c0fSNuno Sá 		ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
399ca514c0fSNuno Sá 					      ARRAY_SIZE(adau7118_routes_hw));
400ca514c0fSNuno Sá 	} else {
401ca514c0fSNuno Sá 		snd_soc_component_init_regmap(component, st->map);
402ca514c0fSNuno Sá 		ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
403ca514c0fSNuno Sá 					ARRAY_SIZE(adau7118_widgets_sw));
404ca514c0fSNuno Sá 		if (ret)
405ca514c0fSNuno Sá 			return ret;
406ca514c0fSNuno Sá 
407ca514c0fSNuno Sá 		ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
408ca514c0fSNuno Sá 					      ARRAY_SIZE(adau7118_routes_sw));
409ca514c0fSNuno Sá 	}
410ca514c0fSNuno Sá 
411ca514c0fSNuno Sá 	return ret;
412ca514c0fSNuno Sá }
413ca514c0fSNuno Sá 
414ca514c0fSNuno Sá static const struct snd_soc_dai_ops adau7118_ops = {
415ca514c0fSNuno Sá 	.hw_params = adau7118_hw_params,
416ca514c0fSNuno Sá 	.set_channel_map = adau7118_set_channel_map,
417ca514c0fSNuno Sá 	.set_fmt = adau7118_set_fmt,
418ca514c0fSNuno Sá 	.set_tdm_slot = adau7118_set_tdm_slot,
419ca514c0fSNuno Sá 	.set_tristate = adau7118_set_tristate,
420ca514c0fSNuno Sá };
421ca514c0fSNuno Sá 
422ca514c0fSNuno Sá static struct snd_soc_dai_driver adau7118_dai = {
423ca514c0fSNuno Sá 	.name = "adau7118-hifi-capture",
424ca514c0fSNuno Sá 	.capture = {
425ca514c0fSNuno Sá 		.stream_name = "Capture",
426ca514c0fSNuno Sá 		.channels_min = 1,
427ca514c0fSNuno Sá 		.channels_max = 8,
428ca514c0fSNuno Sá 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
429ca514c0fSNuno Sá 			SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
430ca514c0fSNuno Sá 			SNDRV_PCM_FMTBIT_S24_3LE,
431ca514c0fSNuno Sá 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
432ca514c0fSNuno Sá 		.rate_min = 4000,
433ca514c0fSNuno Sá 		.rate_max = 192000,
434ca514c0fSNuno Sá 		.sig_bits = 24,
435ca514c0fSNuno Sá 	},
436ca514c0fSNuno Sá };
437ca514c0fSNuno Sá 
438ca514c0fSNuno Sá static const struct snd_soc_component_driver adau7118_component_driver = {
439ca514c0fSNuno Sá 	.probe			= adau7118_component_probe,
440ca514c0fSNuno Sá 	.set_bias_level		= adau7118_set_bias_level,
441ca514c0fSNuno Sá 	.dapm_widgets		= adau7118_widgets,
442ca514c0fSNuno Sá 	.num_dapm_widgets	= ARRAY_SIZE(adau7118_widgets),
443ca514c0fSNuno Sá 	.use_pmdown_time	= 1,
444ca514c0fSNuno Sá 	.endianness		= 1,
445ca514c0fSNuno Sá };
446ca514c0fSNuno Sá 
adau7118_regulator_setup(struct adau7118_data * st)447ca514c0fSNuno Sá static int adau7118_regulator_setup(struct adau7118_data *st)
448ca514c0fSNuno Sá {
449b2d6ee75SNuno Sá 	st->iovdd = devm_regulator_get(st->dev, "iovdd");
450ca514c0fSNuno Sá 	if (IS_ERR(st->iovdd)) {
451ca514c0fSNuno Sá 		dev_err(st->dev, "Could not get iovdd: %ld\n",
452ca514c0fSNuno Sá 			PTR_ERR(st->iovdd));
453ca514c0fSNuno Sá 		return PTR_ERR(st->iovdd);
454ca514c0fSNuno Sá 	}
455ca514c0fSNuno Sá 
456b2d6ee75SNuno Sá 	st->dvdd = devm_regulator_get(st->dev, "dvdd");
457ca514c0fSNuno Sá 	if (IS_ERR(st->dvdd)) {
458ca514c0fSNuno Sá 		dev_err(st->dev, "Could not get dvdd: %ld\n",
459ca514c0fSNuno Sá 			PTR_ERR(st->dvdd));
460ca514c0fSNuno Sá 		return PTR_ERR(st->dvdd);
461ca514c0fSNuno Sá 	}
462ca514c0fSNuno Sá 	/* just assume the device is in reset */
463ca514c0fSNuno Sá 	if (!st->hw_mode) {
464ca514c0fSNuno Sá 		regcache_mark_dirty(st->map);
465ca514c0fSNuno Sá 		regcache_cache_only(st->map, true);
466ca514c0fSNuno Sá 	}
467ca514c0fSNuno Sá 
468*b5bfa727SNuno Sá 	return 0;
469ca514c0fSNuno Sá }
470ca514c0fSNuno Sá 
adau7118_parset_dt(const struct adau7118_data * st)471ca514c0fSNuno Sá static int adau7118_parset_dt(const struct adau7118_data *st)
472ca514c0fSNuno Sá {
473ca514c0fSNuno Sá 	int ret;
474ca514c0fSNuno Sá 	u32 dec_ratio = 0;
475ca514c0fSNuno Sá 	/* 4 inputs */
476ca514c0fSNuno Sá 	u32 clk_map[4], regval;
477ca514c0fSNuno Sá 
478ca514c0fSNuno Sá 	if (st->hw_mode)
479ca514c0fSNuno Sá 		return 0;
480ca514c0fSNuno Sá 
481ca514c0fSNuno Sá 	ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
482ca514c0fSNuno Sá 				       &dec_ratio);
483ca514c0fSNuno Sá 	if (!ret) {
484ca514c0fSNuno Sá 		switch (dec_ratio) {
485ca514c0fSNuno Sá 		case 64:
486ca514c0fSNuno Sá 			regval = ADAU7118_DEC_RATIO(0);
487ca514c0fSNuno Sá 			break;
488ca514c0fSNuno Sá 		case 32:
489ca514c0fSNuno Sá 			regval = ADAU7118_DEC_RATIO(1);
490ca514c0fSNuno Sá 			break;
491ca514c0fSNuno Sá 		case 16:
492ca514c0fSNuno Sá 			regval = ADAU7118_DEC_RATIO(2);
493ca514c0fSNuno Sá 			break;
494ca514c0fSNuno Sá 		default:
495ca514c0fSNuno Sá 			dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
496ca514c0fSNuno Sá 			return -EINVAL;
497ca514c0fSNuno Sá 		}
498ca514c0fSNuno Sá 
499ca514c0fSNuno Sá 		ret = regmap_update_bits(st->map,
500ca514c0fSNuno Sá 					 ADAU7118_REG_DEC_RATIO_CLK_MAP,
501ca514c0fSNuno Sá 					 ADAU7118_DEC_RATIO_MASK, regval);
502ca514c0fSNuno Sá 		if (ret)
503ca514c0fSNuno Sá 			return ret;
504ca514c0fSNuno Sá 	}
505ca514c0fSNuno Sá 
506ca514c0fSNuno Sá 	ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
507ca514c0fSNuno Sá 					     clk_map, ARRAY_SIZE(clk_map));
508ca514c0fSNuno Sá 	if (!ret) {
509ca514c0fSNuno Sá 		int pdm;
510ca514c0fSNuno Sá 		u32 _clk_map = 0;
511ca514c0fSNuno Sá 
512ca514c0fSNuno Sá 		for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
513ca514c0fSNuno Sá 			_clk_map |= (clk_map[pdm] << (pdm + 4));
514ca514c0fSNuno Sá 
515ca514c0fSNuno Sá 		ret = regmap_update_bits(st->map,
516ca514c0fSNuno Sá 					 ADAU7118_REG_DEC_RATIO_CLK_MAP,
517ca514c0fSNuno Sá 					 ADAU7118_CLK_MAP_MASK, _clk_map);
518ca514c0fSNuno Sá 		if (ret)
519ca514c0fSNuno Sá 			return ret;
520ca514c0fSNuno Sá 	}
521ca514c0fSNuno Sá 
522ca514c0fSNuno Sá 	return 0;
523ca514c0fSNuno Sá }
524ca514c0fSNuno Sá 
adau7118_probe(struct device * dev,struct regmap * map,bool hw_mode)525ca514c0fSNuno Sá int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
526ca514c0fSNuno Sá {
527ca514c0fSNuno Sá 	struct adau7118_data *st;
528ca514c0fSNuno Sá 	int ret;
529ca514c0fSNuno Sá 
530ca514c0fSNuno Sá 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
531ca514c0fSNuno Sá 	if (!st)
532ca514c0fSNuno Sá 		return -ENOMEM;
533ca514c0fSNuno Sá 
534ca514c0fSNuno Sá 	st->dev = dev;
535ca514c0fSNuno Sá 	st->hw_mode = hw_mode;
536ca514c0fSNuno Sá 	dev_set_drvdata(dev, st);
537ca514c0fSNuno Sá 
538ca514c0fSNuno Sá 	if (!hw_mode) {
539ca514c0fSNuno Sá 		st->map = map;
540ca514c0fSNuno Sá 		adau7118_dai.ops = &adau7118_ops;
541ca514c0fSNuno Sá 		/*
542ca514c0fSNuno Sá 		 * Perform a full soft reset. This will set all register's
543ca514c0fSNuno Sá 		 * with their reset values.
544ca514c0fSNuno Sá 		 */
545ca514c0fSNuno Sá 		ret = regmap_update_bits(map, ADAU7118_REG_RESET,
546ca514c0fSNuno Sá 					 ADAU7118_FULL_SOFT_R_MASK,
547ca514c0fSNuno Sá 					 ADAU7118_FULL_SOFT_R(1));
548ca514c0fSNuno Sá 		if (ret)
549ca514c0fSNuno Sá 			return ret;
550ca514c0fSNuno Sá 	}
551ca514c0fSNuno Sá 
552ca514c0fSNuno Sá 	ret = adau7118_parset_dt(st);
553ca514c0fSNuno Sá 	if (ret)
554ca514c0fSNuno Sá 		return ret;
555ca514c0fSNuno Sá 
556ca514c0fSNuno Sá 	ret = adau7118_regulator_setup(st);
557ca514c0fSNuno Sá 	if (ret)
558ca514c0fSNuno Sá 		return ret;
559ca514c0fSNuno Sá 
560ca514c0fSNuno Sá 	return devm_snd_soc_register_component(dev,
561ca514c0fSNuno Sá 					       &adau7118_component_driver,
562ca514c0fSNuno Sá 					       &adau7118_dai, 1);
563ca514c0fSNuno Sá }
564ca514c0fSNuno Sá EXPORT_SYMBOL_GPL(adau7118_probe);
565ca514c0fSNuno Sá 
566ca514c0fSNuno Sá MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
567ca514c0fSNuno Sá MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
568ca514c0fSNuno Sá MODULE_LICENSE("GPL");
569