Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 // Copyright 2020 NXP
0003 
0004 #include <linux/clk.h>
0005 #include <linux/clk-provider.h>
0006 #include <linux/delay.h>
0007 #include <linux/dmaengine.h>
0008 #include <linux/module.h>
0009 #include <linux/of_device.h>
0010 #include <linux/of_address.h>
0011 #include <linux/pm_runtime.h>
0012 #include <linux/regmap.h>
0013 #include <linux/slab.h>
0014 #include <linux/time.h>
0015 #include <linux/pm_qos.h>
0016 #include <sound/core.h>
0017 #include <sound/dmaengine_pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <linux/dma-mapping.h>
0020 
0021 #include "fsl_aud2htx.h"
0022 #include "imx-pcm.h"
0023 
0024 static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
0025                    struct snd_soc_dai *dai)
0026 {
0027     struct fsl_aud2htx *aud2htx = snd_soc_dai_get_drvdata(dai);
0028 
0029     switch (cmd) {
0030     case SNDRV_PCM_TRIGGER_START:
0031     case SNDRV_PCM_TRIGGER_RESUME:
0032     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0033         regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
0034                    AUD2HTX_CTRL_EN, AUD2HTX_CTRL_EN);
0035         regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
0036                    AUD2HTX_CTRE_DE, AUD2HTX_CTRE_DE);
0037         break;
0038     case SNDRV_PCM_TRIGGER_SUSPEND:
0039     case SNDRV_PCM_TRIGGER_STOP:
0040     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0041         regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
0042                    AUD2HTX_CTRE_DE, 0);
0043         regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
0044                    AUD2HTX_CTRL_EN, 0);
0045         break;
0046     default:
0047         return -EINVAL;
0048     }
0049     return 0;
0050 }
0051 
0052 static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
0053     .trigger    = fsl_aud2htx_trigger,
0054 };
0055 
0056 static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
0057 {
0058     struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
0059 
0060     /* DMA request when number of entries < WTMK_LOW */
0061     regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
0062                AUD2HTX_CTRE_DT_MASK, 0);
0063 
0064     /* Disable interrupts*/
0065     regmap_update_bits(aud2htx->regmap, AUD2HTX_IRQ_MASK,
0066                AUD2HTX_WM_HIGH_IRQ_MASK |
0067                AUD2HTX_WM_LOW_IRQ_MASK |
0068                AUD2HTX_OVF_MASK,
0069                AUD2HTX_WM_HIGH_IRQ_MASK |
0070                AUD2HTX_WM_LOW_IRQ_MASK |
0071                AUD2HTX_OVF_MASK);
0072 
0073     /* Configure watermark */
0074     regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
0075                AUD2HTX_CTRE_WL_MASK,
0076                AUD2HTX_WTMK_LOW << AUD2HTX_CTRE_WL_SHIFT);
0077     regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
0078                AUD2HTX_CTRE_WH_MASK,
0079                AUD2HTX_WTMK_HIGH << AUD2HTX_CTRE_WH_SHIFT);
0080 
0081     snd_soc_dai_init_dma_data(cpu_dai, &aud2htx->dma_params_tx,
0082                   &aud2htx->dma_params_rx);
0083 
0084     return 0;
0085 }
0086 
0087 static struct snd_soc_dai_driver fsl_aud2htx_dai = {
0088     .probe = fsl_aud2htx_dai_probe,
0089     .playback = {
0090         .stream_name = "CPU-Playback",
0091         .channels_min = 1,
0092         .channels_max = 8,
0093         .rates = SNDRV_PCM_RATE_32000 |
0094              SNDRV_PCM_RATE_44100 |
0095              SNDRV_PCM_RATE_48000 |
0096              SNDRV_PCM_RATE_88200 |
0097              SNDRV_PCM_RATE_96000 |
0098              SNDRV_PCM_RATE_176400 |
0099              SNDRV_PCM_RATE_192000,
0100         .formats = FSL_AUD2HTX_FORMATS,
0101     },
0102     .ops = &fsl_aud2htx_dai_ops,
0103 };
0104 
0105 static const struct snd_soc_component_driver fsl_aud2htx_component = {
0106     .name           = "fsl-aud2htx",
0107     .legacy_dai_naming  = 1,
0108 };
0109 
0110 static const struct reg_default fsl_aud2htx_reg_defaults[] = {
0111     {AUD2HTX_CTRL,      0x00000000},
0112     {AUD2HTX_CTRL_EXT,  0x00000000},
0113     {AUD2HTX_WR,        0x00000000},
0114     {AUD2HTX_STATUS,    0x00000000},
0115     {AUD2HTX_IRQ_NOMASK,    0x00000000},
0116     {AUD2HTX_IRQ_MASKED,    0x00000000},
0117     {AUD2HTX_IRQ_MASK,  0x00000000},
0118 };
0119 
0120 static bool fsl_aud2htx_readable_reg(struct device *dev, unsigned int reg)
0121 {
0122     switch (reg) {
0123     case AUD2HTX_CTRL:
0124     case AUD2HTX_CTRL_EXT:
0125     case AUD2HTX_STATUS:
0126     case AUD2HTX_IRQ_NOMASK:
0127     case AUD2HTX_IRQ_MASKED:
0128     case AUD2HTX_IRQ_MASK:
0129         return true;
0130     default:
0131         return false;
0132     }
0133 }
0134 
0135 static bool fsl_aud2htx_writeable_reg(struct device *dev, unsigned int reg)
0136 {
0137     switch (reg) {
0138     case AUD2HTX_CTRL:
0139     case AUD2HTX_CTRL_EXT:
0140     case AUD2HTX_WR:
0141     case AUD2HTX_IRQ_NOMASK:
0142     case AUD2HTX_IRQ_MASKED:
0143     case AUD2HTX_IRQ_MASK:
0144         return true;
0145     default:
0146         return false;
0147     }
0148 }
0149 
0150 static bool fsl_aud2htx_volatile_reg(struct device *dev, unsigned int reg)
0151 {
0152     switch (reg) {
0153     case AUD2HTX_STATUS:
0154     case AUD2HTX_IRQ_NOMASK:
0155     case AUD2HTX_IRQ_MASKED:
0156         return true;
0157     default:
0158         return false;
0159     }
0160 }
0161 
0162 static const struct regmap_config fsl_aud2htx_regmap_config = {
0163     .reg_bits = 32,
0164     .reg_stride = 4,
0165     .val_bits = 32,
0166 
0167     .max_register = AUD2HTX_IRQ_MASK,
0168     .reg_defaults = fsl_aud2htx_reg_defaults,
0169     .num_reg_defaults = ARRAY_SIZE(fsl_aud2htx_reg_defaults),
0170     .readable_reg = fsl_aud2htx_readable_reg,
0171     .volatile_reg = fsl_aud2htx_volatile_reg,
0172     .writeable_reg = fsl_aud2htx_writeable_reg,
0173     .cache_type = REGCACHE_RBTREE,
0174 };
0175 
0176 static const struct of_device_id fsl_aud2htx_dt_ids[] = {
0177     { .compatible = "fsl,imx8mp-aud2htx",},
0178     {}
0179 };
0180 MODULE_DEVICE_TABLE(of, fsl_aud2htx_dt_ids);
0181 
0182 static irqreturn_t fsl_aud2htx_isr(int irq, void *dev_id)
0183 {
0184     return IRQ_HANDLED;
0185 }
0186 
0187 static int fsl_aud2htx_probe(struct platform_device *pdev)
0188 {
0189     struct fsl_aud2htx *aud2htx;
0190     struct resource *res;
0191     void __iomem *regs;
0192     int ret, irq;
0193 
0194     aud2htx = devm_kzalloc(&pdev->dev, sizeof(*aud2htx), GFP_KERNEL);
0195     if (!aud2htx)
0196         return -ENOMEM;
0197 
0198     aud2htx->pdev = pdev;
0199 
0200     regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0201     if (IS_ERR(regs))
0202         return PTR_ERR(regs);
0203 
0204     aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
0205                         &fsl_aud2htx_regmap_config);
0206     if (IS_ERR(aud2htx->regmap)) {
0207         dev_err(&pdev->dev, "failed to init regmap");
0208         return PTR_ERR(aud2htx->regmap);
0209     }
0210 
0211     irq = platform_get_irq(pdev, 0);
0212     if (irq < 0)
0213         return irq;
0214 
0215     ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0,
0216                    dev_name(&pdev->dev), aud2htx);
0217     if (ret) {
0218         dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
0219         return ret;
0220     }
0221 
0222     aud2htx->bus_clk = devm_clk_get(&pdev->dev, "bus");
0223     if (IS_ERR(aud2htx->bus_clk)) {
0224         dev_err(&pdev->dev, "failed to get mem clock\n");
0225         return PTR_ERR(aud2htx->bus_clk);
0226     }
0227 
0228     aud2htx->dma_params_tx.chan_name = "tx";
0229     aud2htx->dma_params_tx.maxburst = AUD2HTX_MAXBURST;
0230     aud2htx->dma_params_tx.addr = res->start + AUD2HTX_WR;
0231 
0232     platform_set_drvdata(pdev, aud2htx);
0233     pm_runtime_enable(&pdev->dev);
0234 
0235     regcache_cache_only(aud2htx->regmap, true);
0236 
0237     /*
0238      * Register platform component before registering cpu dai for there
0239      * is not defer probe for platform component in snd_soc_add_pcm_runtime().
0240      */
0241     ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
0242     if (ret) {
0243         dev_err(&pdev->dev, "failed to pcm register\n");
0244         pm_runtime_disable(&pdev->dev);
0245         return ret;
0246     }
0247 
0248     ret = devm_snd_soc_register_component(&pdev->dev,
0249                           &fsl_aud2htx_component,
0250                           &fsl_aud2htx_dai, 1);
0251     if (ret) {
0252         dev_err(&pdev->dev, "failed to register ASoC DAI\n");
0253         pm_runtime_disable(&pdev->dev);
0254         return ret;
0255     }
0256 
0257     return ret;
0258 }
0259 
0260 static int fsl_aud2htx_remove(struct platform_device *pdev)
0261 {
0262     pm_runtime_disable(&pdev->dev);
0263 
0264     return 0;
0265 }
0266 
0267 static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
0268 {
0269     struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
0270 
0271     regcache_cache_only(aud2htx->regmap, true);
0272     clk_disable_unprepare(aud2htx->bus_clk);
0273 
0274     return 0;
0275 }
0276 
0277 static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
0278 {
0279     struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
0280     int ret;
0281 
0282     ret = clk_prepare_enable(aud2htx->bus_clk);
0283     if (ret)
0284         return ret;
0285 
0286     regcache_cache_only(aud2htx->regmap, false);
0287     regcache_mark_dirty(aud2htx->regmap);
0288     regcache_sync(aud2htx->regmap);
0289 
0290     return 0;
0291 }
0292 
0293 static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
0294     SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend,
0295                fsl_aud2htx_runtime_resume,
0296                NULL)
0297     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0298                 pm_runtime_force_resume)
0299 };
0300 
0301 static struct platform_driver fsl_aud2htx_driver = {
0302     .probe = fsl_aud2htx_probe,
0303     .remove = fsl_aud2htx_remove,
0304     .driver = {
0305         .name = "fsl-aud2htx",
0306         .pm = &fsl_aud2htx_pm_ops,
0307         .of_match_table = fsl_aud2htx_dt_ids,
0308     },
0309 };
0310 module_platform_driver(fsl_aud2htx_driver);
0311 
0312 MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
0313 MODULE_DESCRIPTION("NXP AUD2HTX driver");
0314 MODULE_LICENSE("GPL v2");