aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-11-06 09:59:23 -0500
committerMark Brown <broonie@kernel.org>2014-11-06 11:05:10 -0500
commitead99f89b7cd2b5cfe99601380a6f6f0a1ce7e53 (patch)
tree5f99babab7131b74b409de71ec3c762e6015f62d
parentfeec843d6c4528263724ff3f4c463ea82bf63b4a (diff)
ASoC: ssm4567: Add support for setting the DAI format and TDM configuration
The SSM4567 has support for a couple of different DAI formats. In TDM mode it is also possible to select the TDM slot. This patch adds support for this by implementing the set_fmt and set_tdm_slot callbacks. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/ssm4567.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index e1e33d8cb55a..217667926a77 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -69,6 +69,22 @@
69#define SSM4567_DAC_FS_64000_96000 0x3 69#define SSM4567_DAC_FS_64000_96000 0x3
70#define SSM4567_DAC_FS_128000_192000 0x4 70#define SSM4567_DAC_FS_128000_192000 0x4
71 71
72/* SAI_CTRL_1 */
73#define SSM4567_SAI_CTRL_1_BCLK BIT(6)
74#define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK (0x3 << 4)
75#define SSM4567_SAI_CTRL_1_TDM_BLCKS_32 (0x0 << 4)
76#define SSM4567_SAI_CTRL_1_TDM_BLCKS_48 (0x1 << 4)
77#define SSM4567_SAI_CTRL_1_TDM_BLCKS_64 (0x2 << 4)
78#define SSM4567_SAI_CTRL_1_FSYNC BIT(3)
79#define SSM4567_SAI_CTRL_1_LJ BIT(2)
80#define SSM4567_SAI_CTRL_1_TDM BIT(1)
81#define SSM4567_SAI_CTRL_1_PDM BIT(0)
82
83/* SAI_CTRL_2 */
84#define SSM4567_SAI_CTRL_2_AUTO_SLOT BIT(3)
85#define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK 0x7
86#define SSM4567_SAI_CTRL_2_TDM_SLOT(x) (x)
87
72struct ssm4567 { 88struct ssm4567 {
73 struct regmap *regmap; 89 struct regmap *regmap;
74}; 90};
@@ -194,6 +210,107 @@ static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
194 SSM4567_DAC_MUTE, val); 210 SSM4567_DAC_MUTE, val);
195} 211}
196 212
213static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
214 unsigned int rx_mask, int slots, int width)
215{
216 struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
217 unsigned int blcks;
218 int slot;
219 int ret;
220
221 if (tx_mask == 0)
222 return -EINVAL;
223
224 if (rx_mask && rx_mask != tx_mask)
225 return -EINVAL;
226
227 slot = __ffs(tx_mask);
228 if (tx_mask != BIT(slot))
229 return -EINVAL;
230
231 switch (width) {
232 case 32:
233 blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32;
234 break;
235 case 48:
236 blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48;
237 break;
238 case 64:
239 blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64;
240 break;
241 default:
242 return -EINVAL;
243 }
244
245 ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2,
246 SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK,
247 SSM4567_SAI_CTRL_2_TDM_SLOT(slot));
248 if (ret)
249 return ret;
250
251 return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
252 SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks);
253}
254
255static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
256{
257 struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
258 unsigned int ctrl1 = 0;
259 bool invert_fclk;
260
261 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
262 case SND_SOC_DAIFMT_CBS_CFS:
263 break;
264 default:
265 return -EINVAL;
266 }
267
268 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
269 case SND_SOC_DAIFMT_NB_NF:
270 invert_fclk = false;
271 break;
272 case SND_SOC_DAIFMT_IB_NF:
273 ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
274 invert_fclk = false;
275 break;
276 case SND_SOC_DAIFMT_NB_IF:
277 ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
278 invert_fclk = true;
279 break;
280 case SND_SOC_DAIFMT_IB_IF:
281 ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
282 invert_fclk = true;
283 break;
284 default:
285 return -EINVAL;
286 }
287
288 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
289 case SND_SOC_DAIFMT_I2S:
290 break;
291 case SND_SOC_DAIFMT_LEFT_J:
292 ctrl1 |= SSM4567_SAI_CTRL_1_LJ;
293 invert_fclk = !invert_fclk;
294 break;
295 case SND_SOC_DAIFMT_DSP_A:
296 ctrl1 |= SSM4567_SAI_CTRL_1_TDM;
297 break;
298 case SND_SOC_DAIFMT_DSP_B:
299 ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ;
300 break;
301 case SND_SOC_DAIFMT_PDM:
302 ctrl1 |= SSM4567_SAI_CTRL_1_PDM;
303 break;
304 default:
305 return -EINVAL;
306 }
307
308 if (invert_fclk)
309 ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
310
311 return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1);
312}
313
197static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) 314static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
198{ 315{
199 int ret = 0; 316 int ret = 0;
@@ -248,6 +365,8 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
248static const struct snd_soc_dai_ops ssm4567_dai_ops = { 365static const struct snd_soc_dai_ops ssm4567_dai_ops = {
249 .hw_params = ssm4567_hw_params, 366 .hw_params = ssm4567_hw_params,
250 .digital_mute = ssm4567_mute, 367 .digital_mute = ssm4567_mute,
368 .set_fmt = ssm4567_set_dai_fmt,
369 .set_tdm_slot = ssm4567_set_tdm_slot,
251}; 370};
252 371
253static struct snd_soc_dai_driver ssm4567_dai = { 372static struct snd_soc_dai_driver ssm4567_dai = {