1 /* 2 * Serial Sound Interface (I2S) support for SH7760/SH7780 3 * 4 * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net> 5 * 6 * licensed under the terms outlined in the file COPYING at the root 7 * of the linux kernel sources. 8 * 9 * dont forget to set IPSEL/OMSEL register bits (in your board code) to 10 * enable SSI output pins! 11 */ 12 13 /* 14 * LIMITATIONS: 15 * The SSI unit has only one physical data line, so full duplex is 16 * impossible. This can be remedied on the SH7760 by using the 17 * other SSI unit for recording; however the SH7780 has only 1 SSI 18 * unit, and its pins are shared with the AC97 unit, among others. 19 * 20 * FEATURES: 21 * The SSI features "compressed mode": in this mode it continuously 22 * streams PCM data over the I2S lines and uses LRCK as a handshake 23 * signal. Can be used to send compressed data (AC3/DTS) to a DSP. 24 * The number of bits sent over the wire in a frame can be adjusted 25 * and can be independent from the actual sample bit depth. This is 26 * useful to support TDM mode codecs like the AD1939 which have a 27 * fixed TDM slot size, regardless of sample resolution. 28 */ 29 30 #include <linux/init.h> 31 #include <linux/module.h> 32 #include <linux/platform_device.h> 33 #include <sound/core.h> 34 #include <sound/pcm.h> 35 #include <sound/initval.h> 36 #include <sound/soc.h> 37 #include <asm/io.h> 38 39 #define SSICR 0x00 40 #define SSISR 0x04 41 42 #define CR_DMAEN (1 << 28) 43 #define CR_CHNL_SHIFT 22 44 #define CR_CHNL_MASK (3 << CR_CHNL_SHIFT) 45 #define CR_DWL_SHIFT 19 46 #define CR_DWL_MASK (7 << CR_DWL_SHIFT) 47 #define CR_SWL_SHIFT 16 48 #define CR_SWL_MASK (7 << CR_SWL_SHIFT) 49 #define CR_SCK_MASTER (1 << 15) /* bitclock master bit */ 50 #define CR_SWS_MASTER (1 << 14) /* wordselect master bit */ 51 #define CR_SCKP (1 << 13) /* I2Sclock polarity */ 52 #define CR_SWSP (1 << 12) /* LRCK polarity */ 53 #define CR_SPDP (1 << 11) 54 #define CR_SDTA (1 << 10) /* i2s alignment (msb/lsb) */ 55 #define CR_PDTA (1 << 9) /* fifo data alignment */ 56 #define CR_DEL (1 << 8) /* delay data by 1 i2sclk */ 57 #define CR_BREN (1 << 7) /* clock gating in burst mode */ 58 #define CR_CKDIV_SHIFT 4 59 #define CR_CKDIV_MASK (7 << CR_CKDIV_SHIFT) /* bitclock divider */ 60 #define CR_MUTE (1 << 3) /* SSI mute */ 61 #define CR_CPEN (1 << 2) /* compressed mode */ 62 #define CR_TRMD (1 << 1) /* transmit/receive select */ 63 #define CR_EN (1 << 0) /* enable SSI */ 64 65 #define SSIREG(reg) (*(unsigned long *)(ssi->mmio + (reg))) 66 67 struct ssi_priv { 68 unsigned long mmio; 69 unsigned long sysclk; 70 int inuse; 71 } ssi_cpu_data[] = { 72 #if defined(CONFIG_CPU_SUBTYPE_SH7760) 73 { 74 .mmio = 0xFE680000, 75 }, 76 { 77 .mmio = 0xFE690000, 78 }, 79 #elif defined(CONFIG_CPU_SUBTYPE_SH7780) 80 { 81 .mmio = 0xFFE70000, 82 }, 83 #else 84 #error "Unsupported SuperH SoC" 85 #endif 86 }; 87 88 /* 89 * track usage of the SSI; it is simplex-only so prevent attempts of 90 * concurrent playback + capture. FIXME: any locking required? 91 */ 92 static int ssi_startup(struct snd_pcm_substream *substream, 93 struct snd_soc_dai *dai) 94 { 95 struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; 96 if (ssi->inuse) { 97 pr_debug("ssi: already in use!\n"); 98 return -EBUSY; 99 } else 100 ssi->inuse = 1; 101 return 0; 102 } 103 104 static void ssi_shutdown(struct snd_pcm_substream *substream, 105 struct snd_soc_dai *dai) 106 { 107 struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; 108 109 ssi->inuse = 0; 110 } 111 112 static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, 113 struct snd_soc_dai *dai) 114 { 115 struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; 116 117 switch (cmd) { 118 case SNDRV_PCM_TRIGGER_START: 119 SSIREG(SSICR) |= CR_DMAEN | CR_EN; 120 break; 121 case SNDRV_PCM_TRIGGER_STOP: 122 SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN); 123 break; 124 default: 125 return -EINVAL; 126 } 127 128 return 0; 129 } 130 131 static int ssi_hw_params(struct snd_pcm_substream *substream, 132 struct snd_pcm_hw_params *params, 133 struct snd_soc_dai *dai) 134 { 135 struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; 136 unsigned long ssicr = SSIREG(SSICR); 137 unsigned int bits, channels, swl, recv, i; 138 139 channels = params_channels(params); 140 bits = params->msbits; 141 recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1; 142 143 pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr); 144 pr_debug("bits: %u channels: %u\n", bits, channels); 145 146 ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA | 147 CR_SWL_MASK); 148 149 /* direction (send/receive) */ 150 if (!recv) 151 ssicr |= CR_TRMD; /* transmit */ 152 153 /* channels */ 154 if ((channels < 2) || (channels > 8) || (channels & 1)) { 155 pr_debug("ssi: invalid number of channels\n"); 156 return -EINVAL; 157 } 158 ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT; 159 160 /* DATA WORD LENGTH (DWL): databits in audio sample */ 161 i = 0; 162 switch (bits) { 163 case 32: ++i; 164 case 24: ++i; 165 case 22: ++i; 166 case 20: ++i; 167 case 18: ++i; 168 case 16: ++i; 169 ssicr |= i << CR_DWL_SHIFT; 170 case 8: break; 171 default: 172 pr_debug("ssi: invalid sample width\n"); 173 return -EINVAL; 174 } 175 176 /* 177 * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S 178 * wires. This is usually bits_per_sample x channels/2; i.e. in 179 * Stereo mode the SWL equals DWL. SWL can be bigger than the 180 * product of (channels_per_slot x samplebits), e.g. for codecs 181 * like the AD1939 which only accept 32bit wide TDM slots. For 182 * "standard" I2S operation we set SWL = chans / 2 * DWL here. 183 * Waiting for ASoC to get TDM support ;-) 184 */ 185 if ((bits > 16) && (bits <= 24)) { 186 bits = 24; /* these are padded by the SSI */ 187 /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */ 188 } 189 i = 0; 190 swl = (bits * channels) / 2; 191 switch (swl) { 192 case 256: ++i; 193 case 128: ++i; 194 case 64: ++i; 195 case 48: ++i; 196 case 32: ++i; 197 case 16: ++i; 198 ssicr |= i << CR_SWL_SHIFT; 199 case 8: break; 200 default: 201 pr_debug("ssi: invalid system word length computed\n"); 202 return -EINVAL; 203 } 204 205 SSIREG(SSICR) = ssicr; 206 207 pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr); 208 return 0; 209 } 210 211 static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, 212 unsigned int freq, int dir) 213 { 214 struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; 215 216 ssi->sysclk = freq; 217 218 return 0; 219 } 220 221 /* 222 * This divider is used to generate the SSI_SCK (I2S bitclock) from the 223 * clock at the HAC_BIT_CLK ("oversampling clock") pin. 224 */ 225 static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) 226 { 227 struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; 228 unsigned long ssicr; 229 int i; 230 231 i = 0; 232 ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK; 233 switch (div) { 234 case 16: ++i; 235 case 8: ++i; 236 case 4: ++i; 237 case 2: ++i; 238 SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT); 239 case 1: break; 240 default: 241 pr_debug("ssi: invalid sck divider %d\n", div); 242 return -EINVAL; 243 } 244 245 return 0; 246 } 247 248 static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 249 { 250 struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; 251 unsigned long ssicr = SSIREG(SSICR); 252 253 pr_debug("ssi_set_fmt()\nssicr was 0x%08lx\n", ssicr); 254 255 ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP | 256 CR_SWS_MASTER | CR_SCK_MASTER); 257 258 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 259 case SND_SOC_DAIFMT_I2S: 260 break; 261 case SND_SOC_DAIFMT_RIGHT_J: 262 ssicr |= CR_DEL | CR_PDTA; 263 break; 264 case SND_SOC_DAIFMT_LEFT_J: 265 ssicr |= CR_DEL; 266 break; 267 default: 268 pr_debug("ssi: unsupported format\n"); 269 return -EINVAL; 270 } 271 272 switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { 273 case SND_SOC_DAIFMT_CONT: 274 break; 275 case SND_SOC_DAIFMT_GATED: 276 ssicr |= CR_BREN; 277 break; 278 } 279 280 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 281 case SND_SOC_DAIFMT_NB_NF: 282 ssicr |= CR_SCKP; /* sample data at low clkedge */ 283 break; 284 case SND_SOC_DAIFMT_NB_IF: 285 ssicr |= CR_SCKP | CR_SWSP; 286 break; 287 case SND_SOC_DAIFMT_IB_NF: 288 break; 289 case SND_SOC_DAIFMT_IB_IF: 290 ssicr |= CR_SWSP; /* word select starts low */ 291 break; 292 default: 293 pr_debug("ssi: invalid inversion\n"); 294 return -EINVAL; 295 } 296 297 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 298 case SND_SOC_DAIFMT_CBM_CFM: 299 break; 300 case SND_SOC_DAIFMT_CBS_CFM: 301 ssicr |= CR_SCK_MASTER; 302 break; 303 case SND_SOC_DAIFMT_CBM_CFS: 304 ssicr |= CR_SWS_MASTER; 305 break; 306 case SND_SOC_DAIFMT_CBS_CFS: 307 ssicr |= CR_SWS_MASTER | CR_SCK_MASTER; 308 break; 309 default: 310 pr_debug("ssi: invalid master/slave configuration\n"); 311 return -EINVAL; 312 } 313 314 SSIREG(SSICR) = ssicr; 315 pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr); 316 317 return 0; 318 } 319 320 /* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in 321 * Master mode, so really this is board specific; the SSI can do any 322 * rate with the right bitclk and divider settings. 323 */ 324 #define SSI_RATES \ 325 SNDRV_PCM_RATE_8000_192000 326 327 /* the SSI can do 8-32 bit samples, with 8 possible channels */ 328 #define SSI_FMTS \ 329 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ 330 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ 331 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ 332 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ 333 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) 334 335 static const struct snd_soc_dai_ops ssi_dai_ops = { 336 .startup = ssi_startup, 337 .shutdown = ssi_shutdown, 338 .trigger = ssi_trigger, 339 .hw_params = ssi_hw_params, 340 .set_sysclk = ssi_set_sysclk, 341 .set_clkdiv = ssi_set_clkdiv, 342 .set_fmt = ssi_set_fmt, 343 }; 344 345 static struct snd_soc_dai_driver sh4_ssi_dai[] = { 346 { 347 .name = "ssi-dai.0", 348 .playback = { 349 .rates = SSI_RATES, 350 .formats = SSI_FMTS, 351 .channels_min = 2, 352 .channels_max = 8, 353 }, 354 .capture = { 355 .rates = SSI_RATES, 356 .formats = SSI_FMTS, 357 .channels_min = 2, 358 .channels_max = 8, 359 }, 360 .ops = &ssi_dai_ops, 361 }, 362 #ifdef CONFIG_CPU_SUBTYPE_SH7760 363 { 364 .name = "ssi-dai.1", 365 .playback = { 366 .rates = SSI_RATES, 367 .formats = SSI_FMTS, 368 .channels_min = 2, 369 .channels_max = 8, 370 }, 371 .capture = { 372 .rates = SSI_RATES, 373 .formats = SSI_FMTS, 374 .channels_min = 2, 375 .channels_max = 8, 376 }, 377 .ops = &ssi_dai_ops, 378 }, 379 #endif 380 }; 381 382 static const struct snd_soc_component_driver sh4_ssi_component = { 383 .name = "sh4-ssi", 384 }; 385 386 static int sh4_soc_dai_probe(struct platform_device *pdev) 387 { 388 return snd_soc_register_component(&pdev->dev, &sh4_ssi_component, 389 sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); 390 } 391 392 static int sh4_soc_dai_remove(struct platform_device *pdev) 393 { 394 snd_soc_unregister_component(&pdev->dev); 395 return 0; 396 } 397 398 static struct platform_driver sh4_ssi_driver = { 399 .driver = { 400 .name = "sh4-ssi-dai", 401 .owner = THIS_MODULE, 402 }, 403 404 .probe = sh4_soc_dai_probe, 405 .remove = sh4_soc_dai_remove, 406 }; 407 408 module_platform_driver(sh4_ssi_driver); 409 410 MODULE_LICENSE("GPL"); 411 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); 412 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); 413