Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Xilinx ASoC SPDIF audio support
0004 //
0005 // Copyright (C) 2018 Xilinx, Inc.
0006 //
0007 // Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
0008 //
0009 
0010 #include <linux/clk.h>
0011 #include <linux/io.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/platform_device.h>
0016 #include <sound/pcm_params.h>
0017 #include <sound/soc.h>
0018 
0019 #define XLNX_SPDIF_RATES \
0020     (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
0021     SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
0022     SNDRV_PCM_RATE_192000)
0023 
0024 #define XLNX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
0025 
0026 #define XSPDIF_IRQ_STS_REG      0x20
0027 #define XSPDIF_IRQ_ENABLE_REG       0x28
0028 #define XSPDIF_SOFT_RESET_REG       0x40
0029 #define XSPDIF_CONTROL_REG      0x44
0030 #define XSPDIF_CHAN_0_STS_REG       0x4C
0031 #define XSPDIF_GLOBAL_IRQ_ENABLE_REG    0x1C
0032 #define XSPDIF_CH_A_USER_DATA_REG_0 0x64
0033 
0034 #define XSPDIF_CORE_ENABLE_MASK     BIT(0)
0035 #define XSPDIF_FIFO_FLUSH_MASK      BIT(1)
0036 #define XSPDIF_CH_STS_MASK      BIT(5)
0037 #define XSPDIF_GLOBAL_IRQ_ENABLE    BIT(31)
0038 #define XSPDIF_CLOCK_CONFIG_BITS_MASK   GENMASK(5, 2)
0039 #define XSPDIF_CLOCK_CONFIG_BITS_SHIFT  2
0040 #define XSPDIF_SOFT_RESET_VALUE     0xA
0041 
0042 #define MAX_CHANNELS            2
0043 #define AES_SAMPLE_WIDTH        32
0044 #define CH_STATUS_UPDATE_TIMEOUT    40
0045 
0046 struct spdif_dev_data {
0047     u32 mode;
0048     u32 aclk;
0049     bool rx_chsts_updated;
0050     void __iomem *base;
0051     struct clk *axi_clk;
0052     wait_queue_head_t chsts_q;
0053 };
0054 
0055 static irqreturn_t xlnx_spdifrx_irq_handler(int irq, void *arg)
0056 {
0057     u32 val;
0058     struct spdif_dev_data *ctx = arg;
0059 
0060     val = readl(ctx->base + XSPDIF_IRQ_STS_REG);
0061     if (val & XSPDIF_CH_STS_MASK) {
0062         writel(val & XSPDIF_CH_STS_MASK,
0063                ctx->base + XSPDIF_IRQ_STS_REG);
0064         val = readl(ctx->base +
0065                 XSPDIF_IRQ_ENABLE_REG);
0066         writel(val & ~XSPDIF_CH_STS_MASK,
0067                ctx->base + XSPDIF_IRQ_ENABLE_REG);
0068 
0069         ctx->rx_chsts_updated = true;
0070         wake_up_interruptible(&ctx->chsts_q);
0071         return IRQ_HANDLED;
0072     }
0073 
0074     return IRQ_NONE;
0075 }
0076 
0077 static int xlnx_spdif_startup(struct snd_pcm_substream *substream,
0078                   struct snd_soc_dai *dai)
0079 {
0080     u32 val;
0081     struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
0082 
0083     val = readl(ctx->base + XSPDIF_CONTROL_REG);
0084     val |= XSPDIF_FIFO_FLUSH_MASK;
0085     writel(val, ctx->base + XSPDIF_CONTROL_REG);
0086 
0087     if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
0088         writel(XSPDIF_CH_STS_MASK,
0089                ctx->base + XSPDIF_IRQ_ENABLE_REG);
0090         writel(XSPDIF_GLOBAL_IRQ_ENABLE,
0091                ctx->base + XSPDIF_GLOBAL_IRQ_ENABLE_REG);
0092     }
0093 
0094     return 0;
0095 }
0096 
0097 static void xlnx_spdif_shutdown(struct snd_pcm_substream *substream,
0098                 struct snd_soc_dai *dai)
0099 {
0100     struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
0101 
0102     writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG);
0103 }
0104 
0105 static int xlnx_spdif_hw_params(struct snd_pcm_substream *substream,
0106                 struct snd_pcm_hw_params *params,
0107                 struct snd_soc_dai *dai)
0108 {
0109     u32 val, clk_div, clk_cfg;
0110     struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
0111 
0112     clk_div = DIV_ROUND_CLOSEST(ctx->aclk, MAX_CHANNELS * AES_SAMPLE_WIDTH *
0113                     params_rate(params));
0114 
0115     switch (clk_div) {
0116     case 4:
0117         clk_cfg = 0;
0118         break;
0119     case 8:
0120         clk_cfg = 1;
0121         break;
0122     case 16:
0123         clk_cfg = 2;
0124         break;
0125     case 24:
0126         clk_cfg = 3;
0127         break;
0128     case 32:
0129         clk_cfg = 4;
0130         break;
0131     case 48:
0132         clk_cfg = 5;
0133         break;
0134     case 64:
0135         clk_cfg = 6;
0136         break;
0137     default:
0138         return -EINVAL;
0139     }
0140 
0141     val = readl(ctx->base + XSPDIF_CONTROL_REG);
0142     val &= ~XSPDIF_CLOCK_CONFIG_BITS_MASK;
0143     val |= clk_cfg << XSPDIF_CLOCK_CONFIG_BITS_SHIFT;
0144     writel(val, ctx->base + XSPDIF_CONTROL_REG);
0145 
0146     return 0;
0147 }
0148 
0149 static int rx_stream_detect(struct snd_soc_dai *dai)
0150 {
0151     int err;
0152     struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
0153     unsigned long jiffies = msecs_to_jiffies(CH_STATUS_UPDATE_TIMEOUT);
0154 
0155     /* start capture only if stream is detected within 40ms timeout */
0156     err = wait_event_interruptible_timeout(ctx->chsts_q,
0157                            ctx->rx_chsts_updated,
0158                            jiffies);
0159     if (!err) {
0160         dev_err(dai->dev, "No streaming audio detected!\n");
0161         return -EINVAL;
0162     }
0163     ctx->rx_chsts_updated = false;
0164 
0165     return 0;
0166 }
0167 
0168 static int xlnx_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
0169                   struct snd_soc_dai *dai)
0170 {
0171     u32 val;
0172     int ret = 0;
0173     struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev);
0174 
0175     val = readl(ctx->base + XSPDIF_CONTROL_REG);
0176     switch (cmd) {
0177     case SNDRV_PCM_TRIGGER_START:
0178     case SNDRV_PCM_TRIGGER_RESUME:
0179     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0180         val |= XSPDIF_CORE_ENABLE_MASK;
0181         writel(val, ctx->base + XSPDIF_CONTROL_REG);
0182         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
0183             ret = rx_stream_detect(dai);
0184         break;
0185     case SNDRV_PCM_TRIGGER_STOP:
0186     case SNDRV_PCM_TRIGGER_SUSPEND:
0187     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0188         val &= ~XSPDIF_CORE_ENABLE_MASK;
0189         writel(val, ctx->base + XSPDIF_CONTROL_REG);
0190         break;
0191     default:
0192         ret = -EINVAL;
0193     }
0194 
0195     return ret;
0196 }
0197 
0198 static const struct snd_soc_dai_ops xlnx_spdif_dai_ops = {
0199     .startup = xlnx_spdif_startup,
0200     .shutdown = xlnx_spdif_shutdown,
0201     .trigger = xlnx_spdif_trigger,
0202     .hw_params = xlnx_spdif_hw_params,
0203 };
0204 
0205 static struct snd_soc_dai_driver xlnx_spdif_tx_dai = {
0206     .name = "xlnx_spdif_tx",
0207     .playback = {
0208         .channels_min = 2,
0209         .channels_max = 2,
0210         .rates = XLNX_SPDIF_RATES,
0211         .formats = XLNX_SPDIF_FORMATS,
0212     },
0213     .ops = &xlnx_spdif_dai_ops,
0214 };
0215 
0216 static struct snd_soc_dai_driver xlnx_spdif_rx_dai = {
0217     .name = "xlnx_spdif_rx",
0218     .capture = {
0219         .channels_min = 2,
0220         .channels_max = 2,
0221         .rates = XLNX_SPDIF_RATES,
0222         .formats = XLNX_SPDIF_FORMATS,
0223     },
0224     .ops = &xlnx_spdif_dai_ops,
0225 };
0226 
0227 static const struct snd_soc_component_driver xlnx_spdif_component = {
0228     .name = "xlnx-spdif",
0229     .legacy_dai_naming = 1,
0230 };
0231 
0232 static const struct of_device_id xlnx_spdif_of_match[] = {
0233     { .compatible = "xlnx,spdif-2.0", },
0234     {},
0235 };
0236 MODULE_DEVICE_TABLE(of, xlnx_spdif_of_match);
0237 
0238 static int xlnx_spdif_probe(struct platform_device *pdev)
0239 {
0240     int ret;
0241     struct snd_soc_dai_driver *dai_drv;
0242     struct spdif_dev_data *ctx;
0243 
0244     struct device *dev = &pdev->dev;
0245     struct device_node *node = dev->of_node;
0246 
0247     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0248     if (!ctx)
0249         return -ENOMEM;
0250 
0251     ctx->axi_clk = devm_clk_get(dev, "s_axi_aclk");
0252     if (IS_ERR(ctx->axi_clk)) {
0253         ret = PTR_ERR(ctx->axi_clk);
0254         dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret);
0255         return ret;
0256     }
0257     ret = clk_prepare_enable(ctx->axi_clk);
0258     if (ret) {
0259         dev_err(dev, "failed to enable s_axi_aclk(%d)\n", ret);
0260         return ret;
0261     }
0262 
0263     ctx->base = devm_platform_ioremap_resource(pdev, 0);
0264     if (IS_ERR(ctx->base)) {
0265         ret = PTR_ERR(ctx->base);
0266         goto clk_err;
0267     }
0268     ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode);
0269     if (ret < 0) {
0270         dev_err(dev, "cannot get SPDIF mode\n");
0271         goto clk_err;
0272     }
0273     if (ctx->mode) {
0274         dai_drv = &xlnx_spdif_tx_dai;
0275     } else {
0276         ret = platform_get_irq(pdev, 0);
0277         if (ret < 0)
0278             goto clk_err;
0279         ret = devm_request_irq(dev, ret,
0280                        xlnx_spdifrx_irq_handler,
0281                        0, "XLNX_SPDIF_RX", ctx);
0282         if (ret) {
0283             dev_err(dev, "spdif rx irq request failed\n");
0284             ret = -ENODEV;
0285             goto clk_err;
0286         }
0287 
0288         init_waitqueue_head(&ctx->chsts_q);
0289         dai_drv = &xlnx_spdif_rx_dai;
0290     }
0291 
0292     ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk);
0293     if (ret < 0) {
0294         dev_err(dev, "cannot get aud_clk_i value\n");
0295         goto clk_err;
0296     }
0297 
0298     dev_set_drvdata(dev, ctx);
0299 
0300     ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component,
0301                           dai_drv, 1);
0302     if (ret) {
0303         dev_err(dev, "SPDIF component registration failed\n");
0304         goto clk_err;
0305     }
0306 
0307     writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG);
0308     dev_info(dev, "%s DAI registered\n", dai_drv->name);
0309 
0310 clk_err:
0311     clk_disable_unprepare(ctx->axi_clk);
0312     return ret;
0313 }
0314 
0315 static int xlnx_spdif_remove(struct platform_device *pdev)
0316 {
0317     struct spdif_dev_data *ctx = dev_get_drvdata(&pdev->dev);
0318 
0319     clk_disable_unprepare(ctx->axi_clk);
0320     return 0;
0321 }
0322 
0323 static struct platform_driver xlnx_spdif_driver = {
0324     .driver = {
0325         .name = "xlnx-spdif",
0326         .of_match_table = xlnx_spdif_of_match,
0327     },
0328     .probe = xlnx_spdif_probe,
0329     .remove = xlnx_spdif_remove,
0330 };
0331 module_platform_driver(xlnx_spdif_driver);
0332 
0333 MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
0334 MODULE_DESCRIPTION("XILINX SPDIF driver");
0335 MODULE_LICENSE("GPL v2");