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