aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/samsung/i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/samsung/i2s.c')
-rw-r--r--sound/soc/samsung/i2s.c193
1 files changed, 141 insertions, 52 deletions
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 959c702235c8..b302f3b7a587 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -40,6 +40,7 @@ enum samsung_dai_type {
40 40
41struct samsung_i2s_dai_data { 41struct samsung_i2s_dai_data {
42 int dai_type; 42 int dai_type;
43 u32 quirks;
43}; 44};
44 45
45struct i2s_dai { 46struct i2s_dai {
@@ -198,7 +199,13 @@ static inline bool is_manager(struct i2s_dai *i2s)
198/* Read RCLK of I2S (in multiples of LRCLK) */ 199/* Read RCLK of I2S (in multiples of LRCLK) */
199static inline unsigned get_rfs(struct i2s_dai *i2s) 200static inline unsigned get_rfs(struct i2s_dai *i2s)
200{ 201{
201 u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3; 202 u32 rfs;
203
204 if (i2s->quirks & QUIRK_SUPPORTS_TDM)
205 rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
206 else
207 rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
208 rfs &= MOD_RCLK_MASK;
202 209
203 switch (rfs) { 210 switch (rfs) {
204 case 3: return 768; 211 case 3: return 768;
@@ -212,21 +219,26 @@ static inline unsigned get_rfs(struct i2s_dai *i2s)
212static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) 219static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
213{ 220{
214 u32 mod = readl(i2s->addr + I2SMOD); 221 u32 mod = readl(i2s->addr + I2SMOD);
222 int rfs_shift;
215 223
216 mod &= ~MOD_RCLK_MASK; 224 if (i2s->quirks & QUIRK_SUPPORTS_TDM)
225 rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
226 else
227 rfs_shift = MOD_RCLK_SHIFT;
228 mod &= ~(MOD_RCLK_MASK << rfs_shift);
217 229
218 switch (rfs) { 230 switch (rfs) {
219 case 768: 231 case 768:
220 mod |= MOD_RCLK_768FS; 232 mod |= (MOD_RCLK_768FS << rfs_shift);
221 break; 233 break;
222 case 512: 234 case 512:
223 mod |= MOD_RCLK_512FS; 235 mod |= (MOD_RCLK_512FS << rfs_shift);
224 break; 236 break;
225 case 384: 237 case 384:
226 mod |= MOD_RCLK_384FS; 238 mod |= (MOD_RCLK_384FS << rfs_shift);
227 break; 239 break;
228 default: 240 default:
229 mod |= MOD_RCLK_256FS; 241 mod |= (MOD_RCLK_256FS << rfs_shift);
230 break; 242 break;
231 } 243 }
232 244
@@ -236,9 +248,22 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
236/* Read Bit-Clock of I2S (in multiples of LRCLK) */ 248/* Read Bit-Clock of I2S (in multiples of LRCLK) */
237static inline unsigned get_bfs(struct i2s_dai *i2s) 249static inline unsigned get_bfs(struct i2s_dai *i2s)
238{ 250{
239 u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3; 251 u32 bfs;
252
253 if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
254 bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
255 bfs &= EXYNOS5420_MOD_BCLK_MASK;
256 } else {
257 bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
258 bfs &= MOD_BCLK_MASK;
259 }
240 260
241 switch (bfs) { 261 switch (bfs) {
262 case 8: return 256;
263 case 7: return 192;
264 case 6: return 128;
265 case 5: return 96;
266 case 4: return 64;
242 case 3: return 24; 267 case 3: return 24;
243 case 2: return 16; 268 case 2: return 16;
244 case 1: return 48; 269 case 1: return 48;
@@ -250,21 +275,50 @@ static inline unsigned get_bfs(struct i2s_dai *i2s)
250static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) 275static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
251{ 276{
252 u32 mod = readl(i2s->addr + I2SMOD); 277 u32 mod = readl(i2s->addr + I2SMOD);
278 int bfs_shift;
279 int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
253 280
254 mod &= ~MOD_BCLK_MASK; 281 if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
282 bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
283 mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
284 } else {
285 bfs_shift = MOD_BCLK_SHIFT;
286 mod &= ~(MOD_BCLK_MASK << bfs_shift);
287 }
288
289 /* Non-TDM I2S controllers do not support BCLK > 48 * FS */
290 if (!tdm && bfs > 48) {
291 dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n");
292 return;
293 }
255 294
256 switch (bfs) { 295 switch (bfs) {
257 case 48: 296 case 48:
258 mod |= MOD_BCLK_48FS; 297 mod |= (MOD_BCLK_48FS << bfs_shift);
259 break; 298 break;
260 case 32: 299 case 32:
261 mod |= MOD_BCLK_32FS; 300 mod |= (MOD_BCLK_32FS << bfs_shift);
262 break; 301 break;
263 case 24: 302 case 24:
264 mod |= MOD_BCLK_24FS; 303 mod |= (MOD_BCLK_24FS << bfs_shift);
265 break; 304 break;
266 case 16: 305 case 16:
267 mod |= MOD_BCLK_16FS; 306 mod |= (MOD_BCLK_16FS << bfs_shift);
307 break;
308 case 64:
309 mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift);
310 break;
311 case 96:
312 mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift);
313 break;
314 case 128:
315 mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift);
316 break;
317 case 192:
318 mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift);
319 break;
320 case 256:
321 mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift);
268 break; 322 break;
269 default: 323 default:
270 dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n"); 324 dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
@@ -491,20 +545,32 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
491{ 545{
492 struct i2s_dai *i2s = to_info(dai); 546 struct i2s_dai *i2s = to_info(dai);
493 u32 mod = readl(i2s->addr + I2SMOD); 547 u32 mod = readl(i2s->addr + I2SMOD);
548 int lrp_shift, sdf_shift, sdf_mask, lrp_rlow;
494 u32 tmp = 0; 549 u32 tmp = 0;
495 550
551 if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
552 lrp_shift = EXYNOS5420_MOD_LRP_SHIFT;
553 sdf_shift = EXYNOS5420_MOD_SDF_SHIFT;
554 } else {
555 lrp_shift = MOD_LRP_SHIFT;
556 sdf_shift = MOD_SDF_SHIFT;
557 }
558
559 sdf_mask = MOD_SDF_MASK << sdf_shift;
560 lrp_rlow = MOD_LR_RLOW << lrp_shift;
561
496 /* Format is priority */ 562 /* Format is priority */
497 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 563 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
498 case SND_SOC_DAIFMT_RIGHT_J: 564 case SND_SOC_DAIFMT_RIGHT_J:
499 tmp |= MOD_LR_RLOW; 565 tmp |= lrp_rlow;
500 tmp |= MOD_SDF_MSB; 566 tmp |= (MOD_SDF_MSB << sdf_shift);
501 break; 567 break;
502 case SND_SOC_DAIFMT_LEFT_J: 568 case SND_SOC_DAIFMT_LEFT_J:
503 tmp |= MOD_LR_RLOW; 569 tmp |= lrp_rlow;
504 tmp |= MOD_SDF_LSB; 570 tmp |= (MOD_SDF_LSB << sdf_shift);
505 break; 571 break;
506 case SND_SOC_DAIFMT_I2S: 572 case SND_SOC_DAIFMT_I2S:
507 tmp |= MOD_SDF_IIS; 573 tmp |= (MOD_SDF_IIS << sdf_shift);
508 break; 574 break;
509 default: 575 default:
510 dev_err(&i2s->pdev->dev, "Format not supported\n"); 576 dev_err(&i2s->pdev->dev, "Format not supported\n");
@@ -519,10 +585,10 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
519 case SND_SOC_DAIFMT_NB_NF: 585 case SND_SOC_DAIFMT_NB_NF:
520 break; 586 break;
521 case SND_SOC_DAIFMT_NB_IF: 587 case SND_SOC_DAIFMT_NB_IF:
522 if (tmp & MOD_LR_RLOW) 588 if (tmp & lrp_rlow)
523 tmp &= ~MOD_LR_RLOW; 589 tmp &= ~lrp_rlow;
524 else 590 else
525 tmp |= MOD_LR_RLOW; 591 tmp |= lrp_rlow;
526 break; 592 break;
527 default: 593 default:
528 dev_err(&i2s->pdev->dev, "Polarity not supported\n"); 594 dev_err(&i2s->pdev->dev, "Polarity not supported\n");
@@ -544,15 +610,18 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
544 return -EINVAL; 610 return -EINVAL;
545 } 611 }
546 612
613 /*
614 * Don't change the I2S mode if any controller is active on this
615 * channel.
616 */
547 if (any_active(i2s) && 617 if (any_active(i2s) &&
548 ((mod & (MOD_SDF_MASK | MOD_LR_RLOW 618 ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) {
549 | MOD_SLAVE)) != tmp)) {
550 dev_err(&i2s->pdev->dev, 619 dev_err(&i2s->pdev->dev,
551 "%s:%d Other DAI busy\n", __func__, __LINE__); 620 "%s:%d Other DAI busy\n", __func__, __LINE__);
552 return -EAGAIN; 621 return -EAGAIN;
553 } 622 }
554 623
555 mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE); 624 mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE);
556 mod |= tmp; 625 mod |= tmp;
557 writel(mod, i2s->addr + I2SMOD); 626 writel(mod, i2s->addr + I2SMOD);
558 627
@@ -1007,6 +1076,8 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
1007 if (IS_ERR(i2s->pdev)) 1076 if (IS_ERR(i2s->pdev))
1008 return NULL; 1077 return NULL;
1009 1078
1079 i2s->pdev->dev.parent = &pdev->dev;
1080
1010 platform_set_drvdata(i2s->pdev, i2s); 1081 platform_set_drvdata(i2s->pdev, i2s);
1011 ret = platform_device_add(i2s->pdev); 1082 ret = platform_device_add(i2s->pdev);
1012 if (ret < 0) 1083 if (ret < 0)
@@ -1018,18 +1089,18 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
1018 1089
1019static const struct of_device_id exynos_i2s_match[]; 1090static const struct of_device_id exynos_i2s_match[];
1020 1091
1021static inline int samsung_i2s_get_driver_data(struct platform_device *pdev) 1092static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
1093 struct platform_device *pdev)
1022{ 1094{
1023#ifdef CONFIG_OF 1095#ifdef CONFIG_OF
1024 struct samsung_i2s_dai_data *data;
1025 if (pdev->dev.of_node) { 1096 if (pdev->dev.of_node) {
1026 const struct of_device_id *match; 1097 const struct of_device_id *match;
1027 match = of_match_node(exynos_i2s_match, pdev->dev.of_node); 1098 match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
1028 data = (struct samsung_i2s_dai_data *) match->data; 1099 return match->data;
1029 return data->dai_type;
1030 } else 1100 } else
1031#endif 1101#endif
1032 return platform_get_device_id(pdev)->driver_data; 1102 return (struct samsung_i2s_dai_data *)
1103 platform_get_device_id(pdev)->driver_data;
1033} 1104}
1034 1105
1035#ifdef CONFIG_PM_RUNTIME 1106#ifdef CONFIG_PM_RUNTIME
@@ -1060,13 +1131,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
1060 struct resource *res; 1131 struct resource *res;
1061 u32 regs_base, quirks = 0, idma_addr = 0; 1132 u32 regs_base, quirks = 0, idma_addr = 0;
1062 struct device_node *np = pdev->dev.of_node; 1133 struct device_node *np = pdev->dev.of_node;
1063 enum samsung_dai_type samsung_dai_type; 1134 const struct samsung_i2s_dai_data *i2s_dai_data;
1064 int ret = 0; 1135 int ret = 0;
1065 1136
1066 /* Call during Seconday interface registration */ 1137 /* Call during Seconday interface registration */
1067 samsung_dai_type = samsung_i2s_get_driver_data(pdev); 1138 i2s_dai_data = samsung_i2s_get_driver_data(pdev);
1068 1139
1069 if (samsung_dai_type == TYPE_SEC) { 1140 if (i2s_dai_data->dai_type == TYPE_SEC) {
1070 sec_dai = dev_get_drvdata(&pdev->dev); 1141 sec_dai = dev_get_drvdata(&pdev->dev);
1071 if (!sec_dai) { 1142 if (!sec_dai) {
1072 dev_err(&pdev->dev, "Unable to get drvdata\n"); 1143 dev_err(&pdev->dev, "Unable to get drvdata\n");
@@ -1075,7 +1146,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
1075 snd_soc_register_component(&sec_dai->pdev->dev, 1146 snd_soc_register_component(&sec_dai->pdev->dev,
1076 &samsung_i2s_component, 1147 &samsung_i2s_component,
1077 &sec_dai->i2s_dai_drv, 1); 1148 &sec_dai->i2s_dai_drv, 1);
1078 asoc_dma_platform_register(&pdev->dev); 1149 samsung_asoc_dma_platform_register(&pdev->dev);
1079 return 0; 1150 return 0;
1080 } 1151 }
1081 1152
@@ -1115,15 +1186,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
1115 idma_addr = i2s_cfg->idma_addr; 1186 idma_addr = i2s_cfg->idma_addr;
1116 } 1187 }
1117 } else { 1188 } else {
1118 if (of_find_property(np, "samsung,supports-6ch", NULL)) 1189 quirks = i2s_dai_data->quirks;
1119 quirks |= QUIRK_PRI_6CHAN;
1120
1121 if (of_find_property(np, "samsung,supports-secdai", NULL))
1122 quirks |= QUIRK_SEC_DAI;
1123
1124 if (of_find_property(np, "samsung,supports-rstclr", NULL))
1125 quirks |= QUIRK_NEED_RSTCLR;
1126
1127 if (of_property_read_u32(np, "samsung,idma-addr", 1190 if (of_property_read_u32(np, "samsung,idma-addr",
1128 &idma_addr)) { 1191 &idma_addr)) {
1129 if (quirks & QUIRK_SEC_DAI) { 1192 if (quirks & QUIRK_SEC_DAI) {
@@ -1200,7 +1263,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
1200 1263
1201 pm_runtime_enable(&pdev->dev); 1264 pm_runtime_enable(&pdev->dev);
1202 1265
1203 asoc_dma_platform_register(&pdev->dev); 1266 samsung_asoc_dma_platform_register(&pdev->dev);
1204 1267
1205 return 0; 1268 return 0;
1206err: 1269err:
@@ -1230,33 +1293,59 @@ static int samsung_i2s_remove(struct platform_device *pdev)
1230 i2s->pri_dai = NULL; 1293 i2s->pri_dai = NULL;
1231 i2s->sec_dai = NULL; 1294 i2s->sec_dai = NULL;
1232 1295
1233 asoc_dma_platform_unregister(&pdev->dev); 1296 samsung_asoc_dma_platform_unregister(&pdev->dev);
1234 snd_soc_unregister_component(&pdev->dev); 1297 snd_soc_unregister_component(&pdev->dev);
1235 1298
1236 return 0; 1299 return 0;
1237} 1300}
1238 1301
1302static const struct samsung_i2s_dai_data i2sv3_dai_type = {
1303 .dai_type = TYPE_PRI,
1304 .quirks = QUIRK_NO_MUXPSR,
1305};
1306
1307static const struct samsung_i2s_dai_data i2sv5_dai_type = {
1308 .dai_type = TYPE_PRI,
1309 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
1310};
1311
1312static const struct samsung_i2s_dai_data i2sv6_dai_type = {
1313 .dai_type = TYPE_PRI,
1314 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1315 QUIRK_SUPPORTS_TDM,
1316};
1317
1318static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
1319 .dai_type = TYPE_PRI,
1320};
1321
1322static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
1323 .dai_type = TYPE_SEC,
1324};
1325
1239static struct platform_device_id samsung_i2s_driver_ids[] = { 1326static struct platform_device_id samsung_i2s_driver_ids[] = {
1240 { 1327 {
1241 .name = "samsung-i2s", 1328 .name = "samsung-i2s",
1242 .driver_data = TYPE_PRI, 1329 .driver_data = (kernel_ulong_t)&samsung_dai_type_pri,
1243 }, { 1330 }, {
1244 .name = "samsung-i2s-sec", 1331 .name = "samsung-i2s-sec",
1245 .driver_data = TYPE_SEC, 1332 .driver_data = (kernel_ulong_t)&samsung_dai_type_sec,
1246 }, 1333 },
1247 {}, 1334 {},
1248}; 1335};
1249MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); 1336MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
1250 1337
1251#ifdef CONFIG_OF 1338#ifdef CONFIG_OF
1252static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
1253 [TYPE_PRI] = { TYPE_PRI },
1254 [TYPE_SEC] = { TYPE_SEC },
1255};
1256
1257static const struct of_device_id exynos_i2s_match[] = { 1339static const struct of_device_id exynos_i2s_match[] = {
1258 { .compatible = "samsung,i2s-v5", 1340 {
1259 .data = &samsung_i2s_dai_data_array[TYPE_PRI], 1341 .compatible = "samsung,s3c6410-i2s",
1342 .data = &i2sv3_dai_type,
1343 }, {
1344 .compatible = "samsung,s5pv210-i2s",
1345 .data = &i2sv5_dai_type,
1346 }, {
1347 .compatible = "samsung,exynos5420-i2s",
1348 .data = &i2sv6_dai_type,
1260 }, 1349 },
1261 {}, 1350 {},
1262}; 1351};