0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include <linux/init.h>
0028 #include <linux/module.h>
0029 #include <linux/platform_device.h>
0030 #include <sound/core.h>
0031 #include <sound/pcm.h>
0032 #include <sound/initval.h>
0033 #include <sound/soc.h>
0034 #include <asm/io.h>
0035
0036 #define SSICR 0x00
0037 #define SSISR 0x04
0038
0039 #define CR_DMAEN (1 << 28)
0040 #define CR_CHNL_SHIFT 22
0041 #define CR_CHNL_MASK (3 << CR_CHNL_SHIFT)
0042 #define CR_DWL_SHIFT 19
0043 #define CR_DWL_MASK (7 << CR_DWL_SHIFT)
0044 #define CR_SWL_SHIFT 16
0045 #define CR_SWL_MASK (7 << CR_SWL_SHIFT)
0046 #define CR_SCK_MASTER (1 << 15)
0047 #define CR_SWS_MASTER (1 << 14)
0048 #define CR_SCKP (1 << 13)
0049 #define CR_SWSP (1 << 12)
0050 #define CR_SPDP (1 << 11)
0051 #define CR_SDTA (1 << 10)
0052 #define CR_PDTA (1 << 9)
0053 #define CR_DEL (1 << 8)
0054 #define CR_BREN (1 << 7)
0055 #define CR_CKDIV_SHIFT 4
0056 #define CR_CKDIV_MASK (7 << CR_CKDIV_SHIFT)
0057 #define CR_MUTE (1 << 3)
0058 #define CR_CPEN (1 << 2)
0059 #define CR_TRMD (1 << 1)
0060 #define CR_EN (1 << 0)
0061
0062 #define SSIREG(reg) (*(unsigned long *)(ssi->mmio + (reg)))
0063
0064 struct ssi_priv {
0065 unsigned long mmio;
0066 unsigned long sysclk;
0067 int inuse;
0068 } ssi_cpu_data[] = {
0069 #if defined(CONFIG_CPU_SUBTYPE_SH7760)
0070 {
0071 .mmio = 0xFE680000,
0072 },
0073 {
0074 .mmio = 0xFE690000,
0075 },
0076 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
0077 {
0078 .mmio = 0xFFE70000,
0079 },
0080 #else
0081 #error "Unsupported SuperH SoC"
0082 #endif
0083 };
0084
0085
0086
0087
0088
0089 static int ssi_startup(struct snd_pcm_substream *substream,
0090 struct snd_soc_dai *dai)
0091 {
0092 struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
0093 if (ssi->inuse) {
0094 pr_debug("ssi: already in use!\n");
0095 return -EBUSY;
0096 } else
0097 ssi->inuse = 1;
0098 return 0;
0099 }
0100
0101 static void ssi_shutdown(struct snd_pcm_substream *substream,
0102 struct snd_soc_dai *dai)
0103 {
0104 struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
0105
0106 ssi->inuse = 0;
0107 }
0108
0109 static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
0110 struct snd_soc_dai *dai)
0111 {
0112 struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
0113
0114 switch (cmd) {
0115 case SNDRV_PCM_TRIGGER_START:
0116 SSIREG(SSICR) |= CR_DMAEN | CR_EN;
0117 break;
0118 case SNDRV_PCM_TRIGGER_STOP:
0119 SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
0120 break;
0121 default:
0122 return -EINVAL;
0123 }
0124
0125 return 0;
0126 }
0127
0128 static int ssi_hw_params(struct snd_pcm_substream *substream,
0129 struct snd_pcm_hw_params *params,
0130 struct snd_soc_dai *dai)
0131 {
0132 struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
0133 unsigned long ssicr = SSIREG(SSICR);
0134 unsigned int bits, channels, swl, recv, i;
0135
0136 channels = params_channels(params);
0137 bits = params->msbits;
0138 recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
0139
0140 pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr);
0141 pr_debug("bits: %u channels: %u\n", bits, channels);
0142
0143 ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
0144 CR_SWL_MASK);
0145
0146
0147 if (!recv)
0148 ssicr |= CR_TRMD;
0149
0150
0151 if ((channels < 2) || (channels > 8) || (channels & 1)) {
0152 pr_debug("ssi: invalid number of channels\n");
0153 return -EINVAL;
0154 }
0155 ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
0156
0157
0158 i = 0;
0159 switch (bits) {
0160 case 32: ++i;
0161 case 24: ++i;
0162 case 22: ++i;
0163 case 20: ++i;
0164 case 18: ++i;
0165 case 16: ++i;
0166 ssicr |= i << CR_DWL_SHIFT;
0167 case 8: break;
0168 default:
0169 pr_debug("ssi: invalid sample width\n");
0170 return -EINVAL;
0171 }
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 if ((bits > 16) && (bits <= 24)) {
0183 bits = 24;
0184
0185 }
0186 i = 0;
0187 swl = (bits * channels) / 2;
0188 switch (swl) {
0189 case 256: ++i;
0190 case 128: ++i;
0191 case 64: ++i;
0192 case 48: ++i;
0193 case 32: ++i;
0194 case 16: ++i;
0195 ssicr |= i << CR_SWL_SHIFT;
0196 case 8: break;
0197 default:
0198 pr_debug("ssi: invalid system word length computed\n");
0199 return -EINVAL;
0200 }
0201
0202 SSIREG(SSICR) = ssicr;
0203
0204 pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
0205 return 0;
0206 }
0207
0208 static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
0209 unsigned int freq, int dir)
0210 {
0211 struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
0212
0213 ssi->sysclk = freq;
0214
0215 return 0;
0216 }
0217
0218
0219
0220
0221
0222 static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div)
0223 {
0224 struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
0225 unsigned long ssicr;
0226 int i;
0227
0228 i = 0;
0229 ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
0230 switch (div) {
0231 case 16: ++i;
0232 case 8: ++i;
0233 case 4: ++i;
0234 case 2: ++i;
0235 SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
0236 case 1: break;
0237 default:
0238 pr_debug("ssi: invalid sck divider %d\n", div);
0239 return -EINVAL;
0240 }
0241
0242 return 0;
0243 }
0244
0245 static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0246 {
0247 struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
0248 unsigned long ssicr = SSIREG(SSICR);
0249
0250 pr_debug("ssi_set_fmt()\nssicr was 0x%08lx\n", ssicr);
0251
0252 ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
0253 CR_SWS_MASTER | CR_SCK_MASTER);
0254
0255 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0256 case SND_SOC_DAIFMT_I2S:
0257 break;
0258 case SND_SOC_DAIFMT_RIGHT_J:
0259 ssicr |= CR_DEL | CR_PDTA;
0260 break;
0261 case SND_SOC_DAIFMT_LEFT_J:
0262 ssicr |= CR_DEL;
0263 break;
0264 default:
0265 pr_debug("ssi: unsupported format\n");
0266 return -EINVAL;
0267 }
0268
0269 switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
0270 case SND_SOC_DAIFMT_CONT:
0271 break;
0272 case SND_SOC_DAIFMT_GATED:
0273 ssicr |= CR_BREN;
0274 break;
0275 }
0276
0277 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0278 case SND_SOC_DAIFMT_NB_NF:
0279 ssicr |= CR_SCKP;
0280 break;
0281 case SND_SOC_DAIFMT_NB_IF:
0282 ssicr |= CR_SCKP | CR_SWSP;
0283 break;
0284 case SND_SOC_DAIFMT_IB_NF:
0285 break;
0286 case SND_SOC_DAIFMT_IB_IF:
0287 ssicr |= CR_SWSP;
0288 break;
0289 default:
0290 pr_debug("ssi: invalid inversion\n");
0291 return -EINVAL;
0292 }
0293
0294 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0295 case SND_SOC_DAIFMT_BC_FC:
0296 break;
0297 case SND_SOC_DAIFMT_BP_FC:
0298 ssicr |= CR_SCK_MASTER;
0299 break;
0300 case SND_SOC_DAIFMT_BC_FP:
0301 ssicr |= CR_SWS_MASTER;
0302 break;
0303 case SND_SOC_DAIFMT_BP_FP:
0304 ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
0305 break;
0306 default:
0307 pr_debug("ssi: invalid master/secondary configuration\n");
0308 return -EINVAL;
0309 }
0310
0311 SSIREG(SSICR) = ssicr;
0312 pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
0313
0314 return 0;
0315 }
0316
0317
0318
0319
0320
0321 #define SSI_RATES \
0322 SNDRV_PCM_RATE_8000_192000
0323
0324
0325 #define SSI_FMTS \
0326 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
0327 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
0328 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
0329 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
0330 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
0331
0332 static const struct snd_soc_dai_ops ssi_dai_ops = {
0333 .startup = ssi_startup,
0334 .shutdown = ssi_shutdown,
0335 .trigger = ssi_trigger,
0336 .hw_params = ssi_hw_params,
0337 .set_sysclk = ssi_set_sysclk,
0338 .set_clkdiv = ssi_set_clkdiv,
0339 .set_fmt = ssi_set_fmt,
0340 };
0341
0342 static struct snd_soc_dai_driver sh4_ssi_dai[] = {
0343 {
0344 .name = "ssi-dai.0",
0345 .playback = {
0346 .rates = SSI_RATES,
0347 .formats = SSI_FMTS,
0348 .channels_min = 2,
0349 .channels_max = 8,
0350 },
0351 .capture = {
0352 .rates = SSI_RATES,
0353 .formats = SSI_FMTS,
0354 .channels_min = 2,
0355 .channels_max = 8,
0356 },
0357 .ops = &ssi_dai_ops,
0358 },
0359 #ifdef CONFIG_CPU_SUBTYPE_SH7760
0360 {
0361 .name = "ssi-dai.1",
0362 .playback = {
0363 .rates = SSI_RATES,
0364 .formats = SSI_FMTS,
0365 .channels_min = 2,
0366 .channels_max = 8,
0367 },
0368 .capture = {
0369 .rates = SSI_RATES,
0370 .formats = SSI_FMTS,
0371 .channels_min = 2,
0372 .channels_max = 8,
0373 },
0374 .ops = &ssi_dai_ops,
0375 },
0376 #endif
0377 };
0378
0379 static const struct snd_soc_component_driver sh4_ssi_component = {
0380 .name = "sh4-ssi",
0381 .legacy_dai_naming = 1,
0382 };
0383
0384 static int sh4_soc_dai_probe(struct platform_device *pdev)
0385 {
0386 return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
0387 sh4_ssi_dai,
0388 ARRAY_SIZE(sh4_ssi_dai));
0389 }
0390
0391 static struct platform_driver sh4_ssi_driver = {
0392 .driver = {
0393 .name = "sh4-ssi-dai",
0394 },
0395
0396 .probe = sh4_soc_dai_probe,
0397 };
0398
0399 module_platform_driver(sh4_ssi_driver);
0400
0401 MODULE_LICENSE("GPL v2");
0402 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
0403 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");