0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/reset.h>
0018
0019 #include <sound/core.h>
0020 #include <sound/dmaengine_pcm.h>
0021 #include <sound/initval.h>
0022 #include <sound/pcm.h>
0023 #include <sound/pcm_params.h>
0024 #include <sound/soc.h>
0025
0026 #define IMG_SPDIF_OUT_TX_FIFO 0x0
0027
0028 #define IMG_SPDIF_OUT_CTL 0x4
0029 #define IMG_SPDIF_OUT_CTL_FS_MASK BIT(4)
0030 #define IMG_SPDIF_OUT_CTL_CLK_MASK BIT(2)
0031 #define IMG_SPDIF_OUT_CTL_SRT_MASK BIT(0)
0032
0033 #define IMG_SPDIF_OUT_CSL 0x14
0034
0035 #define IMG_SPDIF_OUT_CSH_UV 0x18
0036 #define IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT 0
0037 #define IMG_SPDIF_OUT_CSH_UV_CSH_MASK 0xff
0038
0039 struct img_spdif_out {
0040 spinlock_t lock;
0041 void __iomem *base;
0042 struct clk *clk_sys;
0043 struct clk *clk_ref;
0044 struct snd_dmaengine_dai_dma_data dma_data;
0045 struct device *dev;
0046 struct reset_control *rst;
0047 u32 suspend_ctl;
0048 u32 suspend_csl;
0049 u32 suspend_csh;
0050 };
0051
0052 static int img_spdif_out_runtime_suspend(struct device *dev)
0053 {
0054 struct img_spdif_out *spdif = dev_get_drvdata(dev);
0055
0056 clk_disable_unprepare(spdif->clk_ref);
0057 clk_disable_unprepare(spdif->clk_sys);
0058
0059 return 0;
0060 }
0061
0062 static int img_spdif_out_runtime_resume(struct device *dev)
0063 {
0064 struct img_spdif_out *spdif = dev_get_drvdata(dev);
0065 int ret;
0066
0067 ret = clk_prepare_enable(spdif->clk_sys);
0068 if (ret) {
0069 dev_err(dev, "clk_enable failed: %d\n", ret);
0070 return ret;
0071 }
0072
0073 ret = clk_prepare_enable(spdif->clk_ref);
0074 if (ret) {
0075 dev_err(dev, "clk_enable failed: %d\n", ret);
0076 clk_disable_unprepare(spdif->clk_sys);
0077 return ret;
0078 }
0079
0080 return 0;
0081 }
0082
0083 static inline void img_spdif_out_writel(struct img_spdif_out *spdif, u32 val,
0084 u32 reg)
0085 {
0086 writel(val, spdif->base + reg);
0087 }
0088
0089 static inline u32 img_spdif_out_readl(struct img_spdif_out *spdif, u32 reg)
0090 {
0091 return readl(spdif->base + reg);
0092 }
0093
0094 static void img_spdif_out_reset(struct img_spdif_out *spdif)
0095 {
0096 u32 ctl, status_low, status_high;
0097
0098 ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL) &
0099 ~IMG_SPDIF_OUT_CTL_SRT_MASK;
0100 status_low = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
0101 status_high = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
0102
0103 reset_control_assert(spdif->rst);
0104 reset_control_deassert(spdif->rst);
0105
0106 img_spdif_out_writel(spdif, ctl, IMG_SPDIF_OUT_CTL);
0107 img_spdif_out_writel(spdif, status_low, IMG_SPDIF_OUT_CSL);
0108 img_spdif_out_writel(spdif, status_high, IMG_SPDIF_OUT_CSH_UV);
0109 }
0110
0111 static int img_spdif_out_info(struct snd_kcontrol *kcontrol,
0112 struct snd_ctl_elem_info *uinfo)
0113 {
0114 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
0115 uinfo->count = 1;
0116
0117 return 0;
0118 }
0119
0120 static int img_spdif_out_get_status_mask(struct snd_kcontrol *kcontrol,
0121 struct snd_ctl_elem_value *ucontrol)
0122 {
0123 ucontrol->value.iec958.status[0] = 0xff;
0124 ucontrol->value.iec958.status[1] = 0xff;
0125 ucontrol->value.iec958.status[2] = 0xff;
0126 ucontrol->value.iec958.status[3] = 0xff;
0127 ucontrol->value.iec958.status[4] = 0xff;
0128
0129 return 0;
0130 }
0131
0132 static int img_spdif_out_get_status(struct snd_kcontrol *kcontrol,
0133 struct snd_ctl_elem_value *ucontrol)
0134 {
0135 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0136 struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0137 u32 reg;
0138 unsigned long flags;
0139
0140 spin_lock_irqsave(&spdif->lock, flags);
0141
0142 reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
0143 ucontrol->value.iec958.status[0] = reg & 0xff;
0144 ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
0145 ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
0146 ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
0147
0148 reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
0149 ucontrol->value.iec958.status[4] =
0150 (reg & IMG_SPDIF_OUT_CSH_UV_CSH_MASK) >>
0151 IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
0152
0153 spin_unlock_irqrestore(&spdif->lock, flags);
0154
0155 return 0;
0156 }
0157
0158 static int img_spdif_out_set_status(struct snd_kcontrol *kcontrol,
0159 struct snd_ctl_elem_value *ucontrol)
0160 {
0161 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0162 struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
0163 u32 reg;
0164 unsigned long flags;
0165
0166 reg = ((u32)ucontrol->value.iec958.status[3] << 24);
0167 reg |= ((u32)ucontrol->value.iec958.status[2] << 16);
0168 reg |= ((u32)ucontrol->value.iec958.status[1] << 8);
0169 reg |= (u32)ucontrol->value.iec958.status[0];
0170
0171 spin_lock_irqsave(&spdif->lock, flags);
0172
0173 img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSL);
0174
0175 reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
0176 reg &= ~IMG_SPDIF_OUT_CSH_UV_CSH_MASK;
0177 reg |= (u32)ucontrol->value.iec958.status[4] <<
0178 IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
0179 img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSH_UV);
0180
0181 spin_unlock_irqrestore(&spdif->lock, flags);
0182
0183 return 0;
0184 }
0185
0186 static struct snd_kcontrol_new img_spdif_out_controls[] = {
0187 {
0188 .access = SNDRV_CTL_ELEM_ACCESS_READ,
0189 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0190 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
0191 .info = img_spdif_out_info,
0192 .get = img_spdif_out_get_status_mask
0193 },
0194 {
0195 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
0196 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
0197 .info = img_spdif_out_info,
0198 .get = img_spdif_out_get_status,
0199 .put = img_spdif_out_set_status
0200 }
0201 };
0202
0203 static int img_spdif_out_trigger(struct snd_pcm_substream *substream, int cmd,
0204 struct snd_soc_dai *dai)
0205 {
0206 struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
0207 u32 reg;
0208 unsigned long flags;
0209
0210 switch (cmd) {
0211 case SNDRV_PCM_TRIGGER_START:
0212 case SNDRV_PCM_TRIGGER_RESUME:
0213 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0214 reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
0215 reg |= IMG_SPDIF_OUT_CTL_SRT_MASK;
0216 img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
0217 break;
0218 case SNDRV_PCM_TRIGGER_STOP:
0219 case SNDRV_PCM_TRIGGER_SUSPEND:
0220 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0221 spin_lock_irqsave(&spdif->lock, flags);
0222 img_spdif_out_reset(spdif);
0223 spin_unlock_irqrestore(&spdif->lock, flags);
0224 break;
0225 default:
0226 return -EINVAL;
0227 }
0228
0229 return 0;
0230 }
0231
0232 static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
0233 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
0234 {
0235 struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
0236 unsigned int channels;
0237 long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
0238 u32 reg;
0239 snd_pcm_format_t format;
0240
0241 rate = params_rate(params);
0242 format = params_format(params);
0243 channels = params_channels(params);
0244
0245 dev_dbg(spdif->dev, "hw_params rate %ld channels %u format %u\n",
0246 rate, channels, format);
0247
0248 if (format != SNDRV_PCM_FORMAT_S32_LE)
0249 return -EINVAL;
0250
0251 if (channels != 2)
0252 return -EINVAL;
0253
0254 pre_div_a = clk_round_rate(spdif->clk_ref, rate * 256);
0255 if (pre_div_a < 0)
0256 return pre_div_a;
0257 pre_div_b = clk_round_rate(spdif->clk_ref, rate * 384);
0258 if (pre_div_b < 0)
0259 return pre_div_b;
0260
0261 diff_a = abs((pre_div_a / 256) - rate);
0262 diff_b = abs((pre_div_b / 384) - rate);
0263
0264
0265 if (diff_a > diff_b)
0266 clk_set_rate(spdif->clk_ref, pre_div_b);
0267 else
0268 clk_set_rate(spdif->clk_ref, pre_div_a);
0269
0270
0271
0272
0273
0274
0275 clk_rate = clk_get_rate(spdif->clk_ref);
0276
0277 diff_a = abs((clk_rate / 256) - rate);
0278 diff_b = abs((clk_rate / 384) - rate);
0279
0280 reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
0281 if (diff_a <= diff_b)
0282 reg &= ~IMG_SPDIF_OUT_CTL_CLK_MASK;
0283 else
0284 reg |= IMG_SPDIF_OUT_CTL_CLK_MASK;
0285 img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
0286
0287 return 0;
0288 }
0289
0290 static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
0291 .trigger = img_spdif_out_trigger,
0292 .hw_params = img_spdif_out_hw_params
0293 };
0294
0295 static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
0296 {
0297 struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
0298
0299 snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
0300
0301 snd_soc_add_dai_controls(dai, img_spdif_out_controls,
0302 ARRAY_SIZE(img_spdif_out_controls));
0303
0304 return 0;
0305 }
0306
0307 static struct snd_soc_dai_driver img_spdif_out_dai = {
0308 .probe = img_spdif_out_dai_probe,
0309 .playback = {
0310 .channels_min = 2,
0311 .channels_max = 2,
0312 .rates = SNDRV_PCM_RATE_8000_192000,
0313 .formats = SNDRV_PCM_FMTBIT_S32_LE
0314 },
0315 .ops = &img_spdif_out_dai_ops
0316 };
0317
0318 static const struct snd_soc_component_driver img_spdif_out_component = {
0319 .name = "img-spdif-out",
0320 .legacy_dai_naming = 1,
0321 };
0322
0323 static int img_spdif_out_probe(struct platform_device *pdev)
0324 {
0325 struct img_spdif_out *spdif;
0326 struct resource *res;
0327 void __iomem *base;
0328 int ret;
0329 struct device *dev = &pdev->dev;
0330
0331 spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
0332 if (!spdif)
0333 return -ENOMEM;
0334
0335 platform_set_drvdata(pdev, spdif);
0336
0337 spdif->dev = &pdev->dev;
0338
0339 base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0340 if (IS_ERR(base))
0341 return PTR_ERR(base);
0342
0343 spdif->base = base;
0344
0345 spdif->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
0346 if (IS_ERR(spdif->rst))
0347 return dev_err_probe(&pdev->dev, PTR_ERR(spdif->rst),
0348 "No top level reset found\n");
0349
0350 spdif->clk_sys = devm_clk_get(&pdev->dev, "sys");
0351 if (IS_ERR(spdif->clk_sys))
0352 return dev_err_probe(dev, PTR_ERR(spdif->clk_sys),
0353 "Failed to acquire clock 'sys'\n");
0354
0355 spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
0356 if (IS_ERR(spdif->clk_ref))
0357 return dev_err_probe(dev, PTR_ERR(spdif->clk_ref),
0358 "Failed to acquire clock 'ref'\n");
0359
0360 pm_runtime_enable(&pdev->dev);
0361 if (!pm_runtime_enabled(&pdev->dev)) {
0362 ret = img_spdif_out_runtime_resume(&pdev->dev);
0363 if (ret)
0364 goto err_pm_disable;
0365 }
0366 ret = pm_runtime_resume_and_get(&pdev->dev);
0367 if (ret < 0)
0368 goto err_suspend;
0369
0370 img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK,
0371 IMG_SPDIF_OUT_CTL);
0372
0373 img_spdif_out_reset(spdif);
0374 pm_runtime_put(&pdev->dev);
0375
0376 spin_lock_init(&spdif->lock);
0377
0378 spdif->dma_data.addr = res->start + IMG_SPDIF_OUT_TX_FIFO;
0379 spdif->dma_data.addr_width = 4;
0380 spdif->dma_data.maxburst = 4;
0381
0382 ret = devm_snd_soc_register_component(&pdev->dev,
0383 &img_spdif_out_component,
0384 &img_spdif_out_dai, 1);
0385 if (ret)
0386 goto err_suspend;
0387
0388 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
0389 if (ret)
0390 goto err_suspend;
0391
0392 dev_dbg(&pdev->dev, "Probe successful\n");
0393
0394 return 0;
0395
0396 err_suspend:
0397 if (!pm_runtime_status_suspended(&pdev->dev))
0398 img_spdif_out_runtime_suspend(&pdev->dev);
0399 err_pm_disable:
0400 pm_runtime_disable(&pdev->dev);
0401
0402 return ret;
0403 }
0404
0405 static int img_spdif_out_dev_remove(struct platform_device *pdev)
0406 {
0407 pm_runtime_disable(&pdev->dev);
0408 if (!pm_runtime_status_suspended(&pdev->dev))
0409 img_spdif_out_runtime_suspend(&pdev->dev);
0410
0411 return 0;
0412 }
0413
0414 #ifdef CONFIG_PM_SLEEP
0415 static int img_spdif_out_suspend(struct device *dev)
0416 {
0417 struct img_spdif_out *spdif = dev_get_drvdata(dev);
0418 int ret;
0419
0420 if (pm_runtime_status_suspended(dev)) {
0421 ret = img_spdif_out_runtime_resume(dev);
0422 if (ret)
0423 return ret;
0424 }
0425
0426 spdif->suspend_ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
0427 spdif->suspend_csl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
0428 spdif->suspend_csh = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
0429
0430 img_spdif_out_runtime_suspend(dev);
0431
0432 return 0;
0433 }
0434
0435 static int img_spdif_out_resume(struct device *dev)
0436 {
0437 struct img_spdif_out *spdif = dev_get_drvdata(dev);
0438 int ret;
0439
0440 ret = img_spdif_out_runtime_resume(dev);
0441 if (ret)
0442 return ret;
0443
0444 img_spdif_out_writel(spdif, spdif->suspend_ctl, IMG_SPDIF_OUT_CTL);
0445 img_spdif_out_writel(spdif, spdif->suspend_csl, IMG_SPDIF_OUT_CSL);
0446 img_spdif_out_writel(spdif, spdif->suspend_csh, IMG_SPDIF_OUT_CSH_UV);
0447
0448 if (pm_runtime_status_suspended(dev))
0449 img_spdif_out_runtime_suspend(dev);
0450
0451 return 0;
0452 }
0453 #endif
0454 static const struct of_device_id img_spdif_out_of_match[] = {
0455 { .compatible = "img,spdif-out" },
0456 {}
0457 };
0458 MODULE_DEVICE_TABLE(of, img_spdif_out_of_match);
0459
0460 static const struct dev_pm_ops img_spdif_out_pm_ops = {
0461 SET_RUNTIME_PM_OPS(img_spdif_out_runtime_suspend,
0462 img_spdif_out_runtime_resume, NULL)
0463 SET_SYSTEM_SLEEP_PM_OPS(img_spdif_out_suspend, img_spdif_out_resume)
0464 };
0465
0466 static struct platform_driver img_spdif_out_driver = {
0467 .driver = {
0468 .name = "img-spdif-out",
0469 .of_match_table = img_spdif_out_of_match,
0470 .pm = &img_spdif_out_pm_ops
0471 },
0472 .probe = img_spdif_out_probe,
0473 .remove = img_spdif_out_dev_remove
0474 };
0475 module_platform_driver(img_spdif_out_driver);
0476
0477 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
0478 MODULE_DESCRIPTION("IMG SPDIF Output driver");
0479 MODULE_LICENSE("GPL v2");