--- zzzz-none-000/linux-3.10.107/sound/soc/mxs/mxs-saif.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/sound/soc/mxs/mxs-saif.c 2021-02-04 17:41:59.000000000 +0000 @@ -24,15 +24,13 @@ #include #include #include +#include #include #include -#include -#include #include #include #include #include -#include #include "mxs-saif.h" @@ -52,9 +50,9 @@ * This also means that both SAIFs must operate at the same sample rate. * * We abstract this as each saif has a master, the master could be - * himself or other saifs. In the generic saif driver, saif does not need - * to know the different clkmux. Saif only needs to know who is his master - * and operating his master to generate the proper clock rate for him. + * itself or other saifs. In the generic saif driver, saif does not need + * to know the different clkmux. Saif only needs to know who is its master + * and operating its master to generate the proper clock rate for it. * The master id is provided in mach-specific layer according to different * clkmux setting. */ @@ -78,7 +76,7 @@ * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK * is provided by other SAIF, we provide a interface here to get its master * from its master_id. - * Note that the master could be himself. + * Note that the master could be itself. */ static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif) { @@ -496,6 +494,7 @@ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); struct mxs_saif *master_saif; u32 delay; + int ret; master_saif = mxs_saif_get_master(saif); if (!master_saif) @@ -505,23 +504,37 @@ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (saif->state == MXS_SAIF_STATE_RUNNING) + return 0; + dev_dbg(cpu_dai->dev, "start\n"); - clk_enable(master_saif->clk); - if (!master_saif->mclk_in_use) - __raw_writel(BM_SAIF_CTRL_RUN, - master_saif->base + SAIF_CTRL + MXS_SET_ADDR); + ret = clk_enable(master_saif->clk); + if (ret) { + dev_err(saif->dev, "Failed to enable master clock\n"); + return ret; + } /* - * If the saif's master is not himself, we also need to enable + * If the saif's master is not itself, we also need to enable * itself clk for its internal basic logic to work. */ if (saif != master_saif) { - clk_enable(saif->clk); + ret = clk_enable(saif->clk); + if (ret) { + dev_err(saif->dev, "Failed to enable master clock\n"); + clk_disable(master_saif->clk); + return ret; + } + __raw_writel(BM_SAIF_CTRL_RUN, saif->base + SAIF_CTRL + MXS_SET_ADDR); } + if (!master_saif->mclk_in_use) + __raw_writel(BM_SAIF_CTRL_RUN, + master_saif->base + SAIF_CTRL + MXS_SET_ADDR); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* * write data to saif data register to trigger @@ -545,6 +558,7 @@ } master_saif->ongoing = 1; + saif->state = MXS_SAIF_STATE_RUNNING; dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n", __raw_readl(saif->base + SAIF_CTRL), @@ -557,6 +571,9 @@ case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (saif->state == MXS_SAIF_STATE_STOPPED) + return 0; + dev_dbg(cpu_dai->dev, "stop\n"); /* wait a while for the current sample to complete */ @@ -577,6 +594,7 @@ } master_saif->ongoing = 0; + saif->state = MXS_SAIF_STATE_STOPPED; break; default: @@ -605,8 +623,6 @@ struct mxs_saif *saif = dev_get_drvdata(dai->dev); snd_soc_dai_set_drvdata(dai, saif); - dai->playback_dma_data = &saif->dma_param; - dai->capture_dma_data = &saif->dma_param; return 0; } @@ -662,13 +678,39 @@ return IRQ_HANDLED; } +static int mxs_saif_mclk_init(struct platform_device *pdev) +{ + struct mxs_saif *saif = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + struct clk *clk; + int ret; + + clk = clk_register_divider(&pdev->dev, "mxs_saif_mclk", + __clk_get_name(saif->clk), 0, + saif->base + SAIF_CTRL, + BP_SAIF_CTRL_BITCLK_MULT_RATE, 3, + 0, NULL); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + if (ret == -EEXIST) + return 0; + dev_err(&pdev->dev, "failed to register mclk: %d\n", ret); + return PTR_ERR(clk); + } + + ret = of_clk_add_provider(np, of_clk_src_simple_get, clk); + if (ret) + return ret; + + return 0; +} + static int mxs_saif_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *iores, *dmares; + struct resource *iores; struct mxs_saif *saif; - struct pinctrl *pinctrl; - int ret = 0; + int irq, ret = 0; struct device_node *master; if (!np) @@ -707,12 +749,6 @@ mxs_saif[saif->id] = saif; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - ret = PTR_ERR(pinctrl); - return ret; - } - saif->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(saif->clk)) { ret = PTR_ERR(saif->clk); @@ -727,50 +763,33 @@ if (IS_ERR(saif->base)) return PTR_ERR(saif->base); - dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmares) { - /* - * TODO: This is a temporary solution and should be changed - * to use generic DMA binding later when the helplers get in. - */ - ret = of_property_read_u32(np, "fsl,saif-dma-channel", - &saif->dma_param.chan_num); - if (ret) { - dev_err(&pdev->dev, "failed to get dma channel\n"); - return ret; - } - } else { - saif->dma_param.chan_num = dmares->start; - } - - saif->irq = platform_get_irq(pdev, 0); - if (saif->irq < 0) { - ret = saif->irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; dev_err(&pdev->dev, "failed to get irq resource: %d\n", ret); return ret; } saif->dev = &pdev->dev; - ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, - "mxs-saif", saif); + ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, + dev_name(&pdev->dev), saif); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); return ret; } - saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1); - if (saif->dma_param.dma_data.chan_irq < 0) { - ret = saif->dma_param.dma_data.chan_irq; - dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", - ret); - return ret; - } - platform_set_drvdata(pdev, saif); - ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component, - &mxs_saif_dai, 1); + /* We only support saif0 being tx and clock master */ + if (saif->id == 0) { + ret = mxs_saif_mclk_init(pdev); + if (ret) + dev_warn(&pdev->dev, "failed to init clocks\n"); + } + + ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component, + &mxs_saif_dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); return ret; @@ -779,23 +798,10 @@ ret = mxs_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto failed_pdev_alloc; + return ret; } return 0; - -failed_pdev_alloc: - snd_soc_unregister_component(&pdev->dev); - - return ret; -} - -static int mxs_saif_remove(struct platform_device *pdev) -{ - mxs_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - - return 0; } static const struct of_device_id mxs_saif_dt_ids[] = { @@ -806,11 +812,9 @@ static struct platform_driver mxs_saif_driver = { .probe = mxs_saif_probe, - .remove = mxs_saif_remove, .driver = { .name = "mxs-saif", - .owner = THIS_MODULE, .of_match_table = mxs_saif_dt_ids, }, };