diff options
author | Nicolin Chen <nicoleotsuka@gmail.com> | 2018-02-12 17:03:24 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-02-21 07:30:59 -0500 |
commit | 76f3845110d7d40eb60c12bc64cdfe431a985947 (patch) | |
tree | 43801e0d8ac526de420d4b5e82467a08c41c3cdb | |
parent | badc9595bc15686be3b01e3554421647de348df0 (diff) |
ASoC: fsl_ssi: Move DT related code to a separate probe()
This patch cleans up probe() function by moving all Device Tree
related code into a separate function. It allows the probe() to
be Device Tree independent. This will be very useful for future
integration of imx-ssi driver which has similar functionalities
while exists only because it supports non-DT cases.
This patch also moves symmetric_channels of AC97 from the probe
to the structure snd_soc_dai_driver for simplification.
Additionally, since PowerPC and AC97 use the same pdev pointer
to register a platform device, this patch also unifies related
code.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Tested-by: Caleb Crome <caleb@crome.org>
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Reviewed-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 219 |
1 files changed, 124 insertions, 95 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index b58fabe77c6f..5bc67ad8000f 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -239,8 +239,12 @@ struct fsl_ssi_soc_data { | |||
239 | * | 239 | * |
240 | * @fiq_params: FIQ stream filtering parameters | 240 | * @fiq_params: FIQ stream filtering parameters |
241 | * | 241 | * |
242 | * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only) | 242 | * @card_pdev: Platform_device pointer to register a sound card for PowerPC or |
243 | * TODO: Should be replaced with simple-sound-card | 243 | * to register a CODEC platform device for AC97 |
244 | * @card_name: Platform_device name to register a sound card for PowerPC or | ||
245 | * to register a CODEC platform device for AC97 | ||
246 | * @card_idx: The index of SSI to register a sound card for PowerPC or | ||
247 | * to register a CODEC platform device for AC97 | ||
244 | * | 248 | * |
245 | * @dbg_stats: Debugging statistics | 249 | * @dbg_stats: Debugging statistics |
246 | * | 250 | * |
@@ -285,7 +289,9 @@ struct fsl_ssi { | |||
285 | 289 | ||
286 | struct imx_pcm_fiq_params fiq_params; | 290 | struct imx_pcm_fiq_params fiq_params; |
287 | 291 | ||
288 | struct platform_device *pdev; | 292 | struct platform_device *card_pdev; |
293 | char card_name[32]; | ||
294 | u32 card_idx; | ||
289 | 295 | ||
290 | struct fsl_ssi_dbg dbg_stats; | 296 | struct fsl_ssi_dbg dbg_stats; |
291 | 297 | ||
@@ -1134,6 +1140,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = { | |||
1134 | 1140 | ||
1135 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { | 1141 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { |
1136 | .bus_control = true, | 1142 | .bus_control = true, |
1143 | .symmetric_channels = 1, | ||
1137 | .probe = fsl_ssi_dai_probe, | 1144 | .probe = fsl_ssi_dai_probe, |
1138 | .playback = { | 1145 | .playback = { |
1139 | .stream_name = "AC97 Playback", | 1146 | .stream_name = "AC97 Playback", |
@@ -1291,9 +1298,7 @@ static void make_lowercase(char *s) | |||
1291 | static int fsl_ssi_imx_probe(struct platform_device *pdev, | 1298 | static int fsl_ssi_imx_probe(struct platform_device *pdev, |
1292 | struct fsl_ssi *ssi, void __iomem *iomem) | 1299 | struct fsl_ssi *ssi, void __iomem *iomem) |
1293 | { | 1300 | { |
1294 | struct device_node *np = pdev->dev.of_node; | ||
1295 | struct device *dev = &pdev->dev; | 1301 | struct device *dev = &pdev->dev; |
1296 | u32 dmas[4]; | ||
1297 | int ret; | 1302 | int ret; |
1298 | 1303 | ||
1299 | /* Backward compatible for a DT without ipg clock name assigned */ | 1304 | /* Backward compatible for a DT without ipg clock name assigned */ |
@@ -1327,14 +1332,8 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, | |||
1327 | ssi->dma_params_tx.addr = ssi->ssi_phys + REG_SSI_STX0; | 1332 | ssi->dma_params_tx.addr = ssi->ssi_phys + REG_SSI_STX0; |
1328 | ssi->dma_params_rx.addr = ssi->ssi_phys + REG_SSI_SRX0; | 1333 | ssi->dma_params_rx.addr = ssi->ssi_phys + REG_SSI_SRX0; |
1329 | 1334 | ||
1330 | /* Set to dual FIFO mode according to the SDMA sciprt */ | 1335 | /* Use even numbers to avoid channel swap due to SDMA script design */ |
1331 | ret = of_property_read_u32_array(np, "dmas", dmas, 4); | 1336 | if (ssi->use_dual_fifo) { |
1332 | if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) { | ||
1333 | ssi->use_dual_fifo = true; | ||
1334 | /* | ||
1335 | * Use even numbers to avoid channel swap due to SDMA | ||
1336 | * script design | ||
1337 | */ | ||
1338 | ssi->dma_params_tx.maxburst &= ~0x1; | 1337 | ssi->dma_params_tx.maxburst &= ~0x1; |
1339 | ssi->dma_params_rx.maxburst &= ~0x1; | 1338 | ssi->dma_params_rx.maxburst &= ~0x1; |
1340 | } | 1339 | } |
@@ -1375,41 +1374,109 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev, struct fsl_ssi *ssi) | |||
1375 | clk_disable_unprepare(ssi->clk); | 1374 | clk_disable_unprepare(ssi->clk); |
1376 | } | 1375 | } |
1377 | 1376 | ||
1378 | static int fsl_ssi_probe(struct platform_device *pdev) | 1377 | static int fsl_ssi_probe_from_dt(struct fsl_ssi *ssi) |
1379 | { | 1378 | { |
1380 | struct fsl_ssi *ssi; | 1379 | struct device *dev = ssi->dev; |
1381 | int ret = 0; | 1380 | struct device_node *np = dev->of_node; |
1382 | struct device_node *np = pdev->dev.of_node; | ||
1383 | struct device *dev = &pdev->dev; | ||
1384 | const struct of_device_id *of_id; | 1381 | const struct of_device_id *of_id; |
1385 | const char *p, *sprop; | 1382 | const char *p, *sprop; |
1386 | const __be32 *iprop; | 1383 | const __be32 *iprop; |
1387 | struct resource *res; | 1384 | u32 dmas[4]; |
1388 | void __iomem *iomem; | 1385 | int ret; |
1389 | char name[64]; | ||
1390 | struct regmap_config regconfig = fsl_ssi_regconfig; | ||
1391 | 1386 | ||
1392 | of_id = of_match_device(fsl_ssi_ids, dev); | 1387 | of_id = of_match_device(fsl_ssi_ids, dev); |
1393 | if (!of_id || !of_id->data) | 1388 | if (!of_id || !of_id->data) |
1394 | return -EINVAL; | 1389 | return -EINVAL; |
1395 | 1390 | ||
1396 | ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); | ||
1397 | if (!ssi) | ||
1398 | return -ENOMEM; | ||
1399 | |||
1400 | ssi->soc = of_id->data; | 1391 | ssi->soc = of_id->data; |
1401 | ssi->dev = dev; | 1392 | |
1393 | ret = of_property_match_string(np, "clock-names", "ipg"); | ||
1394 | /* Get error code if not found */ | ||
1395 | ssi->has_ipg_clk_name = ret >= 0; | ||
1402 | 1396 | ||
1403 | /* Check if being used in AC97 mode */ | 1397 | /* Check if being used in AC97 mode */ |
1404 | sprop = of_get_property(np, "fsl,mode", NULL); | 1398 | sprop = of_get_property(np, "fsl,mode", NULL); |
1405 | if (sprop) { | 1399 | if (sprop && !strcmp(sprop, "ac97-slave")) { |
1406 | if (!strcmp(sprop, "ac97-slave")) | 1400 | ssi->dai_fmt = FSLSSI_AC97_DAIFMT; |
1407 | ssi->dai_fmt = FSLSSI_AC97_DAIFMT; | 1401 | |
1402 | ret = of_property_read_u32(np, "cell-index", &ssi->card_idx); | ||
1403 | if (ret) { | ||
1404 | dev_err(dev, "failed to get SSI index property\n"); | ||
1405 | return -EINVAL; | ||
1406 | } | ||
1407 | strcpy(ssi->card_name, "ac97-codec"); | ||
1408 | } else if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { | ||
1409 | /* | ||
1410 | * In synchronous mode, STCK and STFS ports are used by RX | ||
1411 | * as well. So the software should limit the sample rates, | ||
1412 | * sample bits and channels to be symmetric. | ||
1413 | * | ||
1414 | * This is exclusive with FSLSSI_AC97_FORMATS as AC97 runs | ||
1415 | * in the SSI synchronous mode however it does not have to | ||
1416 | * limit symmetric sample rates and sample bits. | ||
1417 | */ | ||
1418 | ssi->synchronous = true; | ||
1408 | } | 1419 | } |
1409 | 1420 | ||
1410 | /* Select DMA or FIQ */ | 1421 | /* Select DMA or FIQ */ |
1411 | ssi->use_dma = !of_property_read_bool(np, "fsl,fiq-stream-filter"); | 1422 | ssi->use_dma = !of_property_read_bool(np, "fsl,fiq-stream-filter"); |
1412 | 1423 | ||
1424 | /* Fetch FIFO depth; Set to 8 for older DT without this property */ | ||
1425 | iprop = of_get_property(np, "fsl,fifo-depth", NULL); | ||
1426 | if (iprop) | ||
1427 | ssi->fifo_depth = be32_to_cpup(iprop); | ||
1428 | else | ||
1429 | ssi->fifo_depth = 8; | ||
1430 | |||
1431 | /* Use dual FIFO mode depending on the support from SDMA script */ | ||
1432 | ret = of_property_read_u32_array(np, "dmas", dmas, 4); | ||
1433 | if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) | ||
1434 | ssi->use_dual_fifo = true; | ||
1435 | |||
1436 | /* | ||
1437 | * Backward compatible for older bindings by manually triggering the | ||
1438 | * machine driver's probe(). Use /compatible property, including the | ||
1439 | * address of CPU DAI driver structure, as the name of machine driver | ||
1440 | * | ||
1441 | * If card_name is set by AC97 earlier, bypass here since it uses a | ||
1442 | * different name to register the device. | ||
1443 | */ | ||
1444 | if (!ssi->card_name[0] && of_get_property(np, "codec-handle", NULL)) { | ||
1445 | sprop = of_get_property(of_find_node_by_path("/"), | ||
1446 | "compatible", NULL); | ||
1447 | /* Strip "fsl," in the compatible name if applicable */ | ||
1448 | p = strrchr(sprop, ','); | ||
1449 | if (p) | ||
1450 | sprop = p + 1; | ||
1451 | snprintf(ssi->card_name, sizeof(ssi->card_name), | ||
1452 | "snd-soc-%s", sprop); | ||
1453 | make_lowercase(ssi->card_name); | ||
1454 | ssi->card_idx = 0; | ||
1455 | } | ||
1456 | |||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | static int fsl_ssi_probe(struct platform_device *pdev) | ||
1461 | { | ||
1462 | struct regmap_config regconfig = fsl_ssi_regconfig; | ||
1463 | struct device *dev = &pdev->dev; | ||
1464 | struct fsl_ssi *ssi; | ||
1465 | struct resource *res; | ||
1466 | void __iomem *iomem; | ||
1467 | int ret = 0; | ||
1468 | |||
1469 | ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); | ||
1470 | if (!ssi) | ||
1471 | return -ENOMEM; | ||
1472 | |||
1473 | ssi->dev = dev; | ||
1474 | |||
1475 | /* Probe from DT */ | ||
1476 | ret = fsl_ssi_probe_from_dt(ssi); | ||
1477 | if (ret) | ||
1478 | return ret; | ||
1479 | |||
1413 | if (fsl_ssi_is_ac97(ssi)) { | 1480 | if (fsl_ssi_is_ac97(ssi)) { |
1414 | memcpy(&ssi->cpu_dai_drv, &fsl_ssi_ac97_dai, | 1481 | memcpy(&ssi->cpu_dai_drv, &fsl_ssi_ac97_dai, |
1415 | sizeof(fsl_ssi_ac97_dai)); | 1482 | sizeof(fsl_ssi_ac97_dai)); |
@@ -1433,15 +1500,11 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1433 | REG_SSI_SRMSK / sizeof(uint32_t) + 1; | 1500 | REG_SSI_SRMSK / sizeof(uint32_t) + 1; |
1434 | } | 1501 | } |
1435 | 1502 | ||
1436 | ret = of_property_match_string(np, "clock-names", "ipg"); | 1503 | if (ssi->has_ipg_clk_name) |
1437 | if (ret < 0) { | ||
1438 | ssi->has_ipg_clk_name = false; | ||
1439 | ssi->regs = devm_regmap_init_mmio(dev, iomem, ®config); | ||
1440 | } else { | ||
1441 | ssi->has_ipg_clk_name = true; | ||
1442 | ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem, | 1504 | ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem, |
1443 | ®config); | 1505 | ®config); |
1444 | } | 1506 | else |
1507 | ssi->regs = devm_regmap_init_mmio(dev, iomem, ®config); | ||
1445 | if (IS_ERR(ssi->regs)) { | 1508 | if (IS_ERR(ssi->regs)) { |
1446 | dev_err(dev, "failed to init register map\n"); | 1509 | dev_err(dev, "failed to init register map\n"); |
1447 | return PTR_ERR(ssi->regs); | 1510 | return PTR_ERR(ssi->regs); |
@@ -1453,24 +1516,13 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1453 | return ssi->irq; | 1516 | return ssi->irq; |
1454 | } | 1517 | } |
1455 | 1518 | ||
1456 | /* Set software limitations for synchronous mode */ | 1519 | /* Set software limitations for synchronous mode except AC97 */ |
1457 | if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { | 1520 | if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) { |
1458 | if (!fsl_ssi_is_ac97(ssi)) { | 1521 | ssi->cpu_dai_drv.symmetric_rates = 1; |
1459 | ssi->cpu_dai_drv.symmetric_rates = 1; | ||
1460 | ssi->cpu_dai_drv.symmetric_samplebits = 1; | ||
1461 | ssi->synchronous = true; | ||
1462 | } | ||
1463 | |||
1464 | ssi->cpu_dai_drv.symmetric_channels = 1; | 1522 | ssi->cpu_dai_drv.symmetric_channels = 1; |
1523 | ssi->cpu_dai_drv.symmetric_samplebits = 1; | ||
1465 | } | 1524 | } |
1466 | 1525 | ||
1467 | /* Fetch FIFO depth; Set to 8 for older DT without this property */ | ||
1468 | iprop = of_get_property(np, "fsl,fifo-depth", NULL); | ||
1469 | if (iprop) | ||
1470 | ssi->fifo_depth = be32_to_cpup(iprop); | ||
1471 | else | ||
1472 | ssi->fifo_depth = 8; | ||
1473 | |||
1474 | /* | 1526 | /* |
1475 | * Configure TX and RX DMA watermarks -- when to send a DMA request | 1527 | * Configure TX and RX DMA watermarks -- when to send a DMA request |
1476 | * | 1528 | * |
@@ -1535,50 +1587,27 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1535 | if (ret) | 1587 | if (ret) |
1536 | goto error_asoc_register; | 1588 | goto error_asoc_register; |
1537 | 1589 | ||
1538 | /* Bypass it if using newer DT bindings of ASoC machine drivers */ | ||
1539 | if (!of_get_property(np, "codec-handle", NULL)) | ||
1540 | goto done; | ||
1541 | |||
1542 | /* | ||
1543 | * Backward compatible for older bindings by manually triggering the | ||
1544 | * machine driver's probe(). Use /compatible property, including the | ||
1545 | * address of CPU DAI driver structure, as the name of machine driver. | ||
1546 | */ | ||
1547 | sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL); | ||
1548 | /* Sometimes the compatible name has a "fsl," prefix, so we strip it. */ | ||
1549 | p = strrchr(sprop, ','); | ||
1550 | if (p) | ||
1551 | sprop = p + 1; | ||
1552 | snprintf(name, sizeof(name), "snd-soc-%s", sprop); | ||
1553 | make_lowercase(name); | ||
1554 | |||
1555 | ssi->pdev = platform_device_register_data(dev, name, 0, NULL, 0); | ||
1556 | if (IS_ERR(ssi->pdev)) { | ||
1557 | ret = PTR_ERR(ssi->pdev); | ||
1558 | dev_err(dev, "failed to register platform: %d\n", ret); | ||
1559 | goto error_sound_card; | ||
1560 | } | ||
1561 | |||
1562 | done: | ||
1563 | /* Initially configures SSI registers */ | 1590 | /* Initially configures SSI registers */ |
1564 | fsl_ssi_hw_init(ssi); | 1591 | fsl_ssi_hw_init(ssi); |
1565 | 1592 | ||
1566 | if (fsl_ssi_is_ac97(ssi)) { | 1593 | /* Register a platform device for older bindings or AC97 */ |
1567 | u32 ssi_idx; | 1594 | if (ssi->card_name[0]) { |
1568 | 1595 | struct device *parent = dev; | |
1569 | ret = of_property_read_u32(np, "cell-index", &ssi_idx); | 1596 | /* |
1570 | if (ret) { | 1597 | * Do not set SSI dev as the parent of AC97 CODEC device since |
1571 | dev_err(dev, "failed to get SSI index property\n"); | 1598 | * it does not have a DT node. Otherwise ASoC core will assume |
1572 | goto error_sound_card; | 1599 | * CODEC has the same DT node as the SSI, so it may bypass the |
1573 | } | 1600 | * dai_probe() of SSI and then cause NULL DMA data pointers. |
1574 | 1601 | */ | |
1575 | ssi->pdev = platform_device_register_data(NULL, "ac97-codec", | 1602 | if (fsl_ssi_is_ac97(ssi)) |
1576 | ssi_idx, NULL, 0); | 1603 | parent = NULL; |
1577 | if (IS_ERR(ssi->pdev)) { | 1604 | |
1578 | ret = PTR_ERR(ssi->pdev); | 1605 | ssi->card_pdev = platform_device_register_data(parent, |
1579 | dev_err(dev, | 1606 | ssi->card_name, ssi->card_idx, NULL, 0); |
1580 | "failed to register AC97 codec platform: %d\n", | 1607 | if (IS_ERR(ssi->card_pdev)) { |
1581 | ret); | 1608 | ret = PTR_ERR(ssi->card_pdev); |
1609 | dev_err(dev, "failed to register %s: %d\n", | ||
1610 | ssi->card_name, ret); | ||
1582 | goto error_sound_card; | 1611 | goto error_sound_card; |
1583 | } | 1612 | } |
1584 | } | 1613 | } |
@@ -1606,8 +1635,8 @@ static int fsl_ssi_remove(struct platform_device *pdev) | |||
1606 | 1635 | ||
1607 | fsl_ssi_debugfs_remove(&ssi->dbg_stats); | 1636 | fsl_ssi_debugfs_remove(&ssi->dbg_stats); |
1608 | 1637 | ||
1609 | if (ssi->pdev) | 1638 | if (ssi->card_pdev) |
1610 | platform_device_unregister(ssi->pdev); | 1639 | platform_device_unregister(ssi->card_pdev); |
1611 | 1640 | ||
1612 | /* Clean up SSI registers */ | 1641 | /* Clean up SSI registers */ |
1613 | fsl_ssi_hw_clean(ssi); | 1642 | fsl_ssi_hw_clean(ssi); |