0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/module.h>
0008 #include <linux/of_platform.h>
0009 #include <linux/regmap.h>
0010 #include <sound/soc.h>
0011 #include <sound/soc-dai.h>
0012 #include <sound/pcm_params.h>
0013 #include <sound/pcm_iec958.h>
0014
0015
0016
0017
0018
0019
0020
0021
0022 #define SPDIFOUT_STAT 0x00
0023 #define SPDIFOUT_GAIN0 0x04
0024 #define SPDIFOUT_GAIN1 0x08
0025 #define SPDIFOUT_CTRL0 0x0c
0026 #define SPDIFOUT_CTRL0_EN BIT(31)
0027 #define SPDIFOUT_CTRL0_RST_OUT BIT(29)
0028 #define SPDIFOUT_CTRL0_RST_IN BIT(28)
0029 #define SPDIFOUT_CTRL0_USEL BIT(26)
0030 #define SPDIFOUT_CTRL0_USET BIT(25)
0031 #define SPDIFOUT_CTRL0_CHSTS_SEL BIT(24)
0032 #define SPDIFOUT_CTRL0_DATA_SEL BIT(20)
0033 #define SPDIFOUT_CTRL0_MSB_FIRST BIT(19)
0034 #define SPDIFOUT_CTRL0_VSEL BIT(18)
0035 #define SPDIFOUT_CTRL0_VSET BIT(17)
0036 #define SPDIFOUT_CTRL0_MASK_MASK GENMASK(11, 4)
0037 #define SPDIFOUT_CTRL0_MASK(x) ((x) << 4)
0038 #define SPDIFOUT_CTRL1 0x10
0039 #define SPDIFOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8)
0040 #define SPDIFOUT_CTRL1_MSB_POS(x) ((x) << 8)
0041 #define SPDIFOUT_CTRL1_TYPE_MASK GENMASK(6, 4)
0042 #define SPDIFOUT_CTRL1_TYPE(x) ((x) << 4)
0043 #define SPDIFOUT_PREAMB 0x14
0044 #define SPDIFOUT_SWAP 0x18
0045 #define SPDIFOUT_CHSTS0 0x1c
0046 #define SPDIFOUT_CHSTS1 0x20
0047 #define SPDIFOUT_CHSTS2 0x24
0048 #define SPDIFOUT_CHSTS3 0x28
0049 #define SPDIFOUT_CHSTS4 0x2c
0050 #define SPDIFOUT_CHSTS5 0x30
0051 #define SPDIFOUT_CHSTS6 0x34
0052 #define SPDIFOUT_CHSTS7 0x38
0053 #define SPDIFOUT_CHSTS8 0x3c
0054 #define SPDIFOUT_CHSTS9 0x40
0055 #define SPDIFOUT_CHSTSA 0x44
0056 #define SPDIFOUT_CHSTSB 0x48
0057 #define SPDIFOUT_MUTE_VAL 0x4c
0058
0059 struct axg_spdifout {
0060 struct regmap *map;
0061 struct clk *mclk;
0062 struct clk *pclk;
0063 };
0064
0065 static void axg_spdifout_enable(struct regmap *map)
0066 {
0067
0068 regmap_update_bits(map, SPDIFOUT_CTRL0,
0069 SPDIFOUT_CTRL0_RST_OUT | SPDIFOUT_CTRL0_RST_IN,
0070 0);
0071
0072
0073 regmap_update_bits(map, SPDIFOUT_CTRL0,
0074 SPDIFOUT_CTRL0_RST_OUT, SPDIFOUT_CTRL0_RST_OUT);
0075 regmap_update_bits(map, SPDIFOUT_CTRL0,
0076 SPDIFOUT_CTRL0_RST_IN, SPDIFOUT_CTRL0_RST_IN);
0077
0078
0079 regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN,
0080 SPDIFOUT_CTRL0_EN);
0081 }
0082
0083 static void axg_spdifout_disable(struct regmap *map)
0084 {
0085 regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN, 0);
0086 }
0087
0088 static int axg_spdifout_trigger(struct snd_pcm_substream *substream, int cmd,
0089 struct snd_soc_dai *dai)
0090 {
0091 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0092
0093 switch (cmd) {
0094 case SNDRV_PCM_TRIGGER_START:
0095 case SNDRV_PCM_TRIGGER_RESUME:
0096 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0097 axg_spdifout_enable(priv->map);
0098 return 0;
0099
0100 case SNDRV_PCM_TRIGGER_STOP:
0101 case SNDRV_PCM_TRIGGER_SUSPEND:
0102 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0103 axg_spdifout_disable(priv->map);
0104 return 0;
0105
0106 default:
0107 return -EINVAL;
0108 }
0109 }
0110
0111 static int axg_spdifout_mute(struct snd_soc_dai *dai, int mute, int direction)
0112 {
0113 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0114
0115
0116 regmap_update_bits(priv->map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_VSET,
0117 mute ? SPDIFOUT_CTRL0_VSET : 0);
0118
0119 return 0;
0120 }
0121
0122 static int axg_spdifout_sample_fmt(struct snd_pcm_hw_params *params,
0123 struct snd_soc_dai *dai)
0124 {
0125 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0126 unsigned int val;
0127
0128
0129 switch (params_channels(params)) {
0130 case 1:
0131 val = SPDIFOUT_CTRL0_MASK(0x1);
0132 break;
0133 case 2:
0134 val = SPDIFOUT_CTRL0_MASK(0x3);
0135 break;
0136 default:
0137 dev_err(dai->dev, "too many channels for spdif dai: %u\n",
0138 params_channels(params));
0139 return -EINVAL;
0140 }
0141
0142 regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
0143 SPDIFOUT_CTRL0_MASK_MASK, val);
0144
0145
0146 switch (params_physical_width(params)) {
0147 case 8:
0148
0149 val = SPDIFOUT_CTRL1_TYPE(0);
0150 break;
0151 case 16:
0152
0153 val = SPDIFOUT_CTRL1_TYPE(2);
0154 break;
0155 case 32:
0156
0157 val = SPDIFOUT_CTRL1_TYPE(4);
0158 break;
0159 default:
0160 dev_err(dai->dev, "Unsupported physical width: %u\n",
0161 params_physical_width(params));
0162 return -EINVAL;
0163 }
0164
0165
0166 val |= SPDIFOUT_CTRL1_MSB_POS(params_width(params) - 1);
0167
0168 regmap_update_bits(priv->map, SPDIFOUT_CTRL1,
0169 SPDIFOUT_CTRL1_MSB_POS_MASK |
0170 SPDIFOUT_CTRL1_TYPE_MASK, val);
0171
0172 regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
0173 SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
0174 0);
0175
0176 return 0;
0177 }
0178
0179 static int axg_spdifout_set_chsts(struct snd_pcm_hw_params *params,
0180 struct snd_soc_dai *dai)
0181 {
0182 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0183 unsigned int offset;
0184 int ret;
0185 u8 cs[4];
0186 u32 val;
0187
0188 ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, 4);
0189 if (ret < 0) {
0190 dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
0191 ret);
0192 return ret;
0193 }
0194 val = cs[0] | cs[1] << 8 | cs[2] << 16 | cs[3] << 24;
0195
0196
0197 regmap_write(priv->map, SPDIFOUT_CHSTS0, val);
0198
0199
0200 for (offset = SPDIFOUT_CHSTS1; offset <= SPDIFOUT_CHSTS5;
0201 offset += regmap_get_reg_stride(priv->map))
0202 regmap_write(priv->map, offset, 0);
0203
0204
0205 regmap_write(priv->map, SPDIFOUT_CHSTS6, val);
0206
0207
0208 for (offset = SPDIFOUT_CHSTS7; offset <= SPDIFOUT_CHSTSB;
0209 offset += regmap_get_reg_stride(priv->map))
0210 regmap_write(priv->map, offset, 0);
0211
0212 return 0;
0213 }
0214
0215 static int axg_spdifout_hw_params(struct snd_pcm_substream *substream,
0216 struct snd_pcm_hw_params *params,
0217 struct snd_soc_dai *dai)
0218 {
0219 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0220 unsigned int rate = params_rate(params);
0221 int ret;
0222
0223
0224 ret = clk_set_rate(priv->mclk, rate * 128);
0225 if (ret) {
0226 dev_err(dai->dev, "failed to set spdif clock\n");
0227 return ret;
0228 }
0229
0230 ret = axg_spdifout_sample_fmt(params, dai);
0231 if (ret) {
0232 dev_err(dai->dev, "failed to setup sample format\n");
0233 return ret;
0234 }
0235
0236 ret = axg_spdifout_set_chsts(params, dai);
0237 if (ret) {
0238 dev_err(dai->dev, "failed to setup channel status words\n");
0239 return ret;
0240 }
0241
0242 return 0;
0243 }
0244
0245 static int axg_spdifout_startup(struct snd_pcm_substream *substream,
0246 struct snd_soc_dai *dai)
0247 {
0248 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0249 int ret;
0250
0251
0252 ret = clk_prepare_enable(priv->pclk);
0253 if (ret) {
0254 dev_err(dai->dev, "failed to enable pclk\n");
0255 return ret;
0256 }
0257
0258
0259 axg_spdifout_disable(priv->map);
0260
0261
0262 regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
0263 SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
0264 0);
0265
0266
0267 regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
0268 SPDIFOUT_CTRL0_CHSTS_SEL | SPDIFOUT_CTRL0_VSEL |
0269 SPDIFOUT_CTRL0_USEL | SPDIFOUT_CTRL0_USET,
0270 0);
0271
0272
0273 regmap_write(priv->map, SPDIFOUT_SWAP, 0x10);
0274
0275 return 0;
0276 }
0277
0278 static void axg_spdifout_shutdown(struct snd_pcm_substream *substream,
0279 struct snd_soc_dai *dai)
0280 {
0281 struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
0282
0283 clk_disable_unprepare(priv->pclk);
0284 }
0285
0286 static const struct snd_soc_dai_ops axg_spdifout_ops = {
0287 .trigger = axg_spdifout_trigger,
0288 .mute_stream = axg_spdifout_mute,
0289 .hw_params = axg_spdifout_hw_params,
0290 .startup = axg_spdifout_startup,
0291 .shutdown = axg_spdifout_shutdown,
0292 .no_capture_mute = 1,
0293 };
0294
0295 static struct snd_soc_dai_driver axg_spdifout_dai_drv[] = {
0296 {
0297 .name = "SPDIF Output",
0298 .playback = {
0299 .stream_name = "Playback",
0300 .channels_min = 1,
0301 .channels_max = 2,
0302 .rates = (SNDRV_PCM_RATE_32000 |
0303 SNDRV_PCM_RATE_44100 |
0304 SNDRV_PCM_RATE_48000 |
0305 SNDRV_PCM_RATE_88200 |
0306 SNDRV_PCM_RATE_96000 |
0307 SNDRV_PCM_RATE_176400 |
0308 SNDRV_PCM_RATE_192000),
0309 .formats = (SNDRV_PCM_FMTBIT_S8 |
0310 SNDRV_PCM_FMTBIT_S16_LE |
0311 SNDRV_PCM_FMTBIT_S20_LE |
0312 SNDRV_PCM_FMTBIT_S24_LE),
0313 },
0314 .ops = &axg_spdifout_ops,
0315 },
0316 };
0317
0318 static const char * const spdifout_sel_texts[] = {
0319 "IN 0", "IN 1", "IN 2",
0320 };
0321
0322 static SOC_ENUM_SINGLE_DECL(axg_spdifout_sel_enum, SPDIFOUT_CTRL1, 24,
0323 spdifout_sel_texts);
0324
0325 static const struct snd_kcontrol_new axg_spdifout_in_mux =
0326 SOC_DAPM_ENUM("Input Source", axg_spdifout_sel_enum);
0327
0328 static const struct snd_soc_dapm_widget axg_spdifout_dapm_widgets[] = {
0329 SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
0330 SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
0331 SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
0332 SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_spdifout_in_mux),
0333 };
0334
0335 static const struct snd_soc_dapm_route axg_spdifout_dapm_routes[] = {
0336 { "SRC SEL", "IN 0", "IN 0" },
0337 { "SRC SEL", "IN 1", "IN 1" },
0338 { "SRC SEL", "IN 2", "IN 2" },
0339 { "Playback", NULL, "SRC SEL" },
0340 };
0341
0342 static const struct snd_kcontrol_new axg_spdifout_controls[] = {
0343 SOC_DOUBLE("Playback Volume", SPDIFOUT_GAIN0, 0, 8, 255, 0),
0344 SOC_DOUBLE("Playback Switch", SPDIFOUT_CTRL0, 22, 21, 1, 1),
0345 SOC_SINGLE("Playback Gain Enable Switch",
0346 SPDIFOUT_CTRL1, 26, 1, 0),
0347 SOC_SINGLE("Playback Channels Mix Switch",
0348 SPDIFOUT_CTRL0, 23, 1, 0),
0349 };
0350
0351 static int axg_spdifout_set_bias_level(struct snd_soc_component *component,
0352 enum snd_soc_bias_level level)
0353 {
0354 struct axg_spdifout *priv = snd_soc_component_get_drvdata(component);
0355 enum snd_soc_bias_level now =
0356 snd_soc_component_get_bias_level(component);
0357 int ret = 0;
0358
0359 switch (level) {
0360 case SND_SOC_BIAS_PREPARE:
0361 if (now == SND_SOC_BIAS_STANDBY)
0362 ret = clk_prepare_enable(priv->mclk);
0363 break;
0364
0365 case SND_SOC_BIAS_STANDBY:
0366 if (now == SND_SOC_BIAS_PREPARE)
0367 clk_disable_unprepare(priv->mclk);
0368 break;
0369
0370 case SND_SOC_BIAS_OFF:
0371 case SND_SOC_BIAS_ON:
0372 break;
0373 }
0374
0375 return ret;
0376 }
0377
0378 static const struct snd_soc_component_driver axg_spdifout_component_drv = {
0379 .controls = axg_spdifout_controls,
0380 .num_controls = ARRAY_SIZE(axg_spdifout_controls),
0381 .dapm_widgets = axg_spdifout_dapm_widgets,
0382 .num_dapm_widgets = ARRAY_SIZE(axg_spdifout_dapm_widgets),
0383 .dapm_routes = axg_spdifout_dapm_routes,
0384 .num_dapm_routes = ARRAY_SIZE(axg_spdifout_dapm_routes),
0385 .set_bias_level = axg_spdifout_set_bias_level,
0386 .legacy_dai_naming = 1,
0387 };
0388
0389 static const struct regmap_config axg_spdifout_regmap_cfg = {
0390 .reg_bits = 32,
0391 .val_bits = 32,
0392 .reg_stride = 4,
0393 .max_register = SPDIFOUT_MUTE_VAL,
0394 };
0395
0396 static const struct of_device_id axg_spdifout_of_match[] = {
0397 { .compatible = "amlogic,axg-spdifout", },
0398 {}
0399 };
0400 MODULE_DEVICE_TABLE(of, axg_spdifout_of_match);
0401
0402 static int axg_spdifout_probe(struct platform_device *pdev)
0403 {
0404 struct device *dev = &pdev->dev;
0405 struct axg_spdifout *priv;
0406 void __iomem *regs;
0407
0408 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0409 if (!priv)
0410 return -ENOMEM;
0411 platform_set_drvdata(pdev, priv);
0412
0413 regs = devm_platform_ioremap_resource(pdev, 0);
0414 if (IS_ERR(regs))
0415 return PTR_ERR(regs);
0416
0417 priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifout_regmap_cfg);
0418 if (IS_ERR(priv->map)) {
0419 dev_err(dev, "failed to init regmap: %ld\n",
0420 PTR_ERR(priv->map));
0421 return PTR_ERR(priv->map);
0422 }
0423
0424 priv->pclk = devm_clk_get(dev, "pclk");
0425 if (IS_ERR(priv->pclk))
0426 return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n");
0427
0428 priv->mclk = devm_clk_get(dev, "mclk");
0429 if (IS_ERR(priv->mclk))
0430 return dev_err_probe(dev, PTR_ERR(priv->mclk), "failed to get mclk\n");
0431
0432 return devm_snd_soc_register_component(dev, &axg_spdifout_component_drv,
0433 axg_spdifout_dai_drv, ARRAY_SIZE(axg_spdifout_dai_drv));
0434 }
0435
0436 static struct platform_driver axg_spdifout_pdrv = {
0437 .probe = axg_spdifout_probe,
0438 .driver = {
0439 .name = "axg-spdifout",
0440 .of_match_table = axg_spdifout_of_match,
0441 },
0442 };
0443 module_platform_driver(axg_spdifout_pdrv);
0444
0445 MODULE_DESCRIPTION("Amlogic AXG SPDIF Output driver");
0446 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0447 MODULE_LICENSE("GPL v2");