diff options
Diffstat (limited to 'sound/soc/samsung/i2s.c')
-rw-r--r-- | sound/soc/samsung/i2s.c | 193 |
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 | ||
41 | struct samsung_i2s_dai_data { | 41 | struct samsung_i2s_dai_data { |
42 | int dai_type; | 42 | int dai_type; |
43 | u32 quirks; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct i2s_dai { | 46 | struct 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) */ |
199 | static inline unsigned get_rfs(struct i2s_dai *i2s) | 200 | static 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) | |||
212 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | 219 | static 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) */ |
237 | static inline unsigned get_bfs(struct i2s_dai *i2s) | 249 | static 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) | |||
250 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) | 275 | static 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 | ||
1019 | static const struct of_device_id exynos_i2s_match[]; | 1090 | static const struct of_device_id exynos_i2s_match[]; |
1020 | 1091 | ||
1021 | static inline int samsung_i2s_get_driver_data(struct platform_device *pdev) | 1092 | static 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; |
1206 | err: | 1269 | err: |
@@ -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 | ||
1302 | static const struct samsung_i2s_dai_data i2sv3_dai_type = { | ||
1303 | .dai_type = TYPE_PRI, | ||
1304 | .quirks = QUIRK_NO_MUXPSR, | ||
1305 | }; | ||
1306 | |||
1307 | static 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 | |||
1312 | static 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 | |||
1318 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { | ||
1319 | .dai_type = TYPE_PRI, | ||
1320 | }; | ||
1321 | |||
1322 | static const struct samsung_i2s_dai_data samsung_dai_type_sec = { | ||
1323 | .dai_type = TYPE_SEC, | ||
1324 | }; | ||
1325 | |||
1239 | static struct platform_device_id samsung_i2s_driver_ids[] = { | 1326 | static 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 | }; |
1249 | MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); | 1336 | MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); |
1250 | 1337 | ||
1251 | #ifdef CONFIG_OF | 1338 | #ifdef CONFIG_OF |
1252 | static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = { | ||
1253 | [TYPE_PRI] = { TYPE_PRI }, | ||
1254 | [TYPE_SEC] = { TYPE_SEC }, | ||
1255 | }; | ||
1256 | |||
1257 | static const struct of_device_id exynos_i2s_match[] = { | 1339 | static 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 | }; |