1*76c2145dSArnaud Pouliquen /* 2*76c2145dSArnaud Pouliquen * Copyright (C) STMicroelectronics SA 2015 3*76c2145dSArnaud Pouliquen * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> 4*76c2145dSArnaud Pouliquen * for STMicroelectronics. 5*76c2145dSArnaud Pouliquen * License terms: GNU General Public License (GPL), version 2 6*76c2145dSArnaud Pouliquen */ 7*76c2145dSArnaud Pouliquen 8*76c2145dSArnaud Pouliquen #include <linux/clk.h> 9*76c2145dSArnaud Pouliquen #include <linux/delay.h> 10*76c2145dSArnaud Pouliquen #include <linux/io.h> 11*76c2145dSArnaud Pouliquen #include <linux/mfd/syscon.h> 12*76c2145dSArnaud Pouliquen 13*76c2145dSArnaud Pouliquen #include <sound/asoundef.h> 14*76c2145dSArnaud Pouliquen #include <sound/soc.h> 15*76c2145dSArnaud Pouliquen 16*76c2145dSArnaud Pouliquen #include "uniperif.h" 17*76c2145dSArnaud Pouliquen 18*76c2145dSArnaud Pouliquen /* 19*76c2145dSArnaud Pouliquen * Some hardware-related definitions 20*76c2145dSArnaud Pouliquen */ 21*76c2145dSArnaud Pouliquen 22*76c2145dSArnaud Pouliquen /* sys config registers definitions */ 23*76c2145dSArnaud Pouliquen #define SYS_CFG_AUDIO_GLUE 0xA4 24*76c2145dSArnaud Pouliquen #define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 25*76c2145dSArnaud Pouliquen 26*76c2145dSArnaud Pouliquen /* 27*76c2145dSArnaud Pouliquen * Driver specific types. 28*76c2145dSArnaud Pouliquen */ 29*76c2145dSArnaud Pouliquen #define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ 30*76c2145dSArnaud Pouliquen ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) 31*76c2145dSArnaud Pouliquen #define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ 32*76c2145dSArnaud Pouliquen ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) 33*76c2145dSArnaud Pouliquen #define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ 34*76c2145dSArnaud Pouliquen ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) 35*76c2145dSArnaud Pouliquen #define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ 36*76c2145dSArnaud Pouliquen (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ 37*76c2145dSArnaud Pouliquen UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) 38*76c2145dSArnaud Pouliquen 39*76c2145dSArnaud Pouliquen /* 40*76c2145dSArnaud Pouliquen * Note: snd_pcm_hardware is linked to DMA controller but is declared here to 41*76c2145dSArnaud Pouliquen * integrate DAI_CPU capability in term of rate and supported channels 42*76c2145dSArnaud Pouliquen */ 43*76c2145dSArnaud Pouliquen const struct snd_pcm_hardware uni_player_pcm_hw = { 44*76c2145dSArnaud Pouliquen .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 45*76c2145dSArnaud Pouliquen SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | 46*76c2145dSArnaud Pouliquen SNDRV_PCM_INFO_MMAP_VALID, 47*76c2145dSArnaud Pouliquen .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, 48*76c2145dSArnaud Pouliquen 49*76c2145dSArnaud Pouliquen .rates = SNDRV_PCM_RATE_CONTINUOUS, 50*76c2145dSArnaud Pouliquen .rate_min = 8000, 51*76c2145dSArnaud Pouliquen .rate_max = 192000, 52*76c2145dSArnaud Pouliquen 53*76c2145dSArnaud Pouliquen .channels_min = 2, 54*76c2145dSArnaud Pouliquen .channels_max = 8, 55*76c2145dSArnaud Pouliquen 56*76c2145dSArnaud Pouliquen .periods_min = 2, 57*76c2145dSArnaud Pouliquen .periods_max = 48, 58*76c2145dSArnaud Pouliquen 59*76c2145dSArnaud Pouliquen .period_bytes_min = 128, 60*76c2145dSArnaud Pouliquen .period_bytes_max = 64 * PAGE_SIZE, 61*76c2145dSArnaud Pouliquen .buffer_bytes_max = 256 * PAGE_SIZE 62*76c2145dSArnaud Pouliquen }; 63*76c2145dSArnaud Pouliquen 64*76c2145dSArnaud Pouliquen static inline int reset_player(struct uniperif *player) 65*76c2145dSArnaud Pouliquen { 66*76c2145dSArnaud Pouliquen int count = 10; 67*76c2145dSArnaud Pouliquen 68*76c2145dSArnaud Pouliquen if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { 69*76c2145dSArnaud Pouliquen while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { 70*76c2145dSArnaud Pouliquen udelay(5); 71*76c2145dSArnaud Pouliquen count--; 72*76c2145dSArnaud Pouliquen } 73*76c2145dSArnaud Pouliquen } 74*76c2145dSArnaud Pouliquen 75*76c2145dSArnaud Pouliquen if (!count) { 76*76c2145dSArnaud Pouliquen dev_err(player->dev, "Failed to reset uniperif"); 77*76c2145dSArnaud Pouliquen return -EIO; 78*76c2145dSArnaud Pouliquen } 79*76c2145dSArnaud Pouliquen 80*76c2145dSArnaud Pouliquen return 0; 81*76c2145dSArnaud Pouliquen } 82*76c2145dSArnaud Pouliquen 83*76c2145dSArnaud Pouliquen /* 84*76c2145dSArnaud Pouliquen * uni_player_irq_handler 85*76c2145dSArnaud Pouliquen * In case of error audio stream is stopped; stop action is protected via PCM 86*76c2145dSArnaud Pouliquen * stream lock to avoid race condition with trigger callback. 87*76c2145dSArnaud Pouliquen */ 88*76c2145dSArnaud Pouliquen static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) 89*76c2145dSArnaud Pouliquen { 90*76c2145dSArnaud Pouliquen irqreturn_t ret = IRQ_NONE; 91*76c2145dSArnaud Pouliquen struct uniperif *player = dev_id; 92*76c2145dSArnaud Pouliquen unsigned int status; 93*76c2145dSArnaud Pouliquen unsigned int tmp; 94*76c2145dSArnaud Pouliquen 95*76c2145dSArnaud Pouliquen if (player->state == UNIPERIF_STATE_STOPPED) { 96*76c2145dSArnaud Pouliquen /* Unexpected IRQ: do nothing */ 97*76c2145dSArnaud Pouliquen return IRQ_NONE; 98*76c2145dSArnaud Pouliquen } 99*76c2145dSArnaud Pouliquen 100*76c2145dSArnaud Pouliquen /* Get interrupt status & clear them immediately */ 101*76c2145dSArnaud Pouliquen status = GET_UNIPERIF_ITS(player); 102*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITS_BCLR(player, status); 103*76c2145dSArnaud Pouliquen 104*76c2145dSArnaud Pouliquen /* Check for fifo error (underrun) */ 105*76c2145dSArnaud Pouliquen if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { 106*76c2145dSArnaud Pouliquen dev_err(player->dev, "FIFO underflow error detected"); 107*76c2145dSArnaud Pouliquen 108*76c2145dSArnaud Pouliquen /* Interrupt is just for information when underflow recovery */ 109*76c2145dSArnaud Pouliquen if (player->info->underflow_enabled) { 110*76c2145dSArnaud Pouliquen /* Update state to underflow */ 111*76c2145dSArnaud Pouliquen player->state = UNIPERIF_STATE_UNDERFLOW; 112*76c2145dSArnaud Pouliquen 113*76c2145dSArnaud Pouliquen } else { 114*76c2145dSArnaud Pouliquen /* Disable interrupt so doesn't continually fire */ 115*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); 116*76c2145dSArnaud Pouliquen 117*76c2145dSArnaud Pouliquen /* Stop the player */ 118*76c2145dSArnaud Pouliquen snd_pcm_stream_lock(player->substream); 119*76c2145dSArnaud Pouliquen snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); 120*76c2145dSArnaud Pouliquen snd_pcm_stream_unlock(player->substream); 121*76c2145dSArnaud Pouliquen } 122*76c2145dSArnaud Pouliquen 123*76c2145dSArnaud Pouliquen ret = IRQ_HANDLED; 124*76c2145dSArnaud Pouliquen } 125*76c2145dSArnaud Pouliquen 126*76c2145dSArnaud Pouliquen /* Check for dma error (overrun) */ 127*76c2145dSArnaud Pouliquen if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { 128*76c2145dSArnaud Pouliquen dev_err(player->dev, "DMA error detected"); 129*76c2145dSArnaud Pouliquen 130*76c2145dSArnaud Pouliquen /* Disable interrupt so doesn't continually fire */ 131*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); 132*76c2145dSArnaud Pouliquen 133*76c2145dSArnaud Pouliquen /* Stop the player */ 134*76c2145dSArnaud Pouliquen snd_pcm_stream_lock(player->substream); 135*76c2145dSArnaud Pouliquen snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); 136*76c2145dSArnaud Pouliquen snd_pcm_stream_unlock(player->substream); 137*76c2145dSArnaud Pouliquen 138*76c2145dSArnaud Pouliquen ret = IRQ_HANDLED; 139*76c2145dSArnaud Pouliquen } 140*76c2145dSArnaud Pouliquen 141*76c2145dSArnaud Pouliquen /* Check for underflow recovery done */ 142*76c2145dSArnaud Pouliquen if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { 143*76c2145dSArnaud Pouliquen if (!player->info->underflow_enabled) { 144*76c2145dSArnaud Pouliquen dev_err(player->dev, "unexpected Underflow recovering"); 145*76c2145dSArnaud Pouliquen return -EPERM; 146*76c2145dSArnaud Pouliquen } 147*76c2145dSArnaud Pouliquen /* Read the underflow recovery duration */ 148*76c2145dSArnaud Pouliquen tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); 149*76c2145dSArnaud Pouliquen 150*76c2145dSArnaud Pouliquen /* Clear the underflow recovery duration */ 151*76c2145dSArnaud Pouliquen SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); 152*76c2145dSArnaud Pouliquen 153*76c2145dSArnaud Pouliquen /* Update state to started */ 154*76c2145dSArnaud Pouliquen player->state = UNIPERIF_STATE_STARTED; 155*76c2145dSArnaud Pouliquen 156*76c2145dSArnaud Pouliquen ret = IRQ_HANDLED; 157*76c2145dSArnaud Pouliquen } 158*76c2145dSArnaud Pouliquen 159*76c2145dSArnaud Pouliquen /* Check if underflow recovery failed */ 160*76c2145dSArnaud Pouliquen if (unlikely(status & 161*76c2145dSArnaud Pouliquen UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { 162*76c2145dSArnaud Pouliquen dev_err(player->dev, "Underflow recovery failed"); 163*76c2145dSArnaud Pouliquen 164*76c2145dSArnaud Pouliquen /* Stop the player */ 165*76c2145dSArnaud Pouliquen snd_pcm_stream_lock(player->substream); 166*76c2145dSArnaud Pouliquen snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); 167*76c2145dSArnaud Pouliquen snd_pcm_stream_unlock(player->substream); 168*76c2145dSArnaud Pouliquen 169*76c2145dSArnaud Pouliquen ret = IRQ_HANDLED; 170*76c2145dSArnaud Pouliquen } 171*76c2145dSArnaud Pouliquen 172*76c2145dSArnaud Pouliquen return ret; 173*76c2145dSArnaud Pouliquen } 174*76c2145dSArnaud Pouliquen 175*76c2145dSArnaud Pouliquen static void uni_player_set_channel_status(struct uniperif *player, 176*76c2145dSArnaud Pouliquen struct snd_pcm_runtime *runtime) 177*76c2145dSArnaud Pouliquen { 178*76c2145dSArnaud Pouliquen int n; 179*76c2145dSArnaud Pouliquen unsigned int status; 180*76c2145dSArnaud Pouliquen 181*76c2145dSArnaud Pouliquen /* 182*76c2145dSArnaud Pouliquen * Some AVRs and TVs require the channel status to contain a correct 183*76c2145dSArnaud Pouliquen * sampling frequency. If no sample rate is already specified, then 184*76c2145dSArnaud Pouliquen * set one. 185*76c2145dSArnaud Pouliquen */ 186*76c2145dSArnaud Pouliquen if (runtime && (player->stream_settings.iec958.status[3] 187*76c2145dSArnaud Pouliquen == IEC958_AES3_CON_FS_NOTID)) { 188*76c2145dSArnaud Pouliquen switch (runtime->rate) { 189*76c2145dSArnaud Pouliquen case 22050: 190*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 191*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_22050; 192*76c2145dSArnaud Pouliquen break; 193*76c2145dSArnaud Pouliquen case 44100: 194*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 195*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_44100; 196*76c2145dSArnaud Pouliquen break; 197*76c2145dSArnaud Pouliquen case 88200: 198*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 199*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_88200; 200*76c2145dSArnaud Pouliquen break; 201*76c2145dSArnaud Pouliquen case 176400: 202*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 203*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_176400; 204*76c2145dSArnaud Pouliquen break; 205*76c2145dSArnaud Pouliquen case 24000: 206*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 207*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_24000; 208*76c2145dSArnaud Pouliquen break; 209*76c2145dSArnaud Pouliquen case 48000: 210*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 211*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_48000; 212*76c2145dSArnaud Pouliquen break; 213*76c2145dSArnaud Pouliquen case 96000: 214*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 215*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_96000; 216*76c2145dSArnaud Pouliquen break; 217*76c2145dSArnaud Pouliquen case 192000: 218*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 219*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_192000; 220*76c2145dSArnaud Pouliquen break; 221*76c2145dSArnaud Pouliquen case 32000: 222*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 223*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_32000; 224*76c2145dSArnaud Pouliquen break; 225*76c2145dSArnaud Pouliquen default: 226*76c2145dSArnaud Pouliquen /* Mark as sampling frequency not indicated */ 227*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 228*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_NOTID; 229*76c2145dSArnaud Pouliquen break; 230*76c2145dSArnaud Pouliquen } 231*76c2145dSArnaud Pouliquen } 232*76c2145dSArnaud Pouliquen 233*76c2145dSArnaud Pouliquen /* Audio mode: 234*76c2145dSArnaud Pouliquen * Use audio mode status to select PCM or encoded mode 235*76c2145dSArnaud Pouliquen */ 236*76c2145dSArnaud Pouliquen if (player->stream_settings.iec958.status[0] & IEC958_AES0_NONAUDIO) 237*76c2145dSArnaud Pouliquen player->stream_settings.encoding_mode = 238*76c2145dSArnaud Pouliquen UNIPERIF_IEC958_ENCODING_MODE_ENCODED; 239*76c2145dSArnaud Pouliquen else 240*76c2145dSArnaud Pouliquen player->stream_settings.encoding_mode = 241*76c2145dSArnaud Pouliquen UNIPERIF_IEC958_ENCODING_MODE_PCM; 242*76c2145dSArnaud Pouliquen 243*76c2145dSArnaud Pouliquen if (player->stream_settings.encoding_mode == 244*76c2145dSArnaud Pouliquen UNIPERIF_IEC958_ENCODING_MODE_PCM) 245*76c2145dSArnaud Pouliquen /* Clear user validity bits */ 246*76c2145dSArnaud Pouliquen SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); 247*76c2145dSArnaud Pouliquen else 248*76c2145dSArnaud Pouliquen /* Set user validity bits */ 249*76c2145dSArnaud Pouliquen SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 1); 250*76c2145dSArnaud Pouliquen 251*76c2145dSArnaud Pouliquen /* Program the new channel status */ 252*76c2145dSArnaud Pouliquen for (n = 0; n < 6; ++n) { 253*76c2145dSArnaud Pouliquen status = 254*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[0 + (n * 4)] & 0xf; 255*76c2145dSArnaud Pouliquen status |= 256*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[1 + (n * 4)] << 8; 257*76c2145dSArnaud Pouliquen status |= 258*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[2 + (n * 4)] << 16; 259*76c2145dSArnaud Pouliquen status |= 260*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3 + (n * 4)] << 24; 261*76c2145dSArnaud Pouliquen SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); 262*76c2145dSArnaud Pouliquen } 263*76c2145dSArnaud Pouliquen 264*76c2145dSArnaud Pouliquen /* Update the channel status */ 265*76c2145dSArnaud Pouliquen if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) 266*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); 267*76c2145dSArnaud Pouliquen else 268*76c2145dSArnaud Pouliquen SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); 269*76c2145dSArnaud Pouliquen } 270*76c2145dSArnaud Pouliquen 271*76c2145dSArnaud Pouliquen static int uni_player_prepare_iec958(struct uniperif *player, 272*76c2145dSArnaud Pouliquen struct snd_pcm_runtime *runtime) 273*76c2145dSArnaud Pouliquen { 274*76c2145dSArnaud Pouliquen int clk_div; 275*76c2145dSArnaud Pouliquen 276*76c2145dSArnaud Pouliquen clk_div = player->mclk / runtime->rate; 277*76c2145dSArnaud Pouliquen 278*76c2145dSArnaud Pouliquen /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ 279*76c2145dSArnaud Pouliquen if ((clk_div % 128) || (clk_div <= 0)) { 280*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid clk_div %d", 281*76c2145dSArnaud Pouliquen __func__, clk_div); 282*76c2145dSArnaud Pouliquen return -EINVAL; 283*76c2145dSArnaud Pouliquen } 284*76c2145dSArnaud Pouliquen 285*76c2145dSArnaud Pouliquen switch (runtime->format) { 286*76c2145dSArnaud Pouliquen case SNDRV_PCM_FORMAT_S16_LE: 287*76c2145dSArnaud Pouliquen /* 16/16 memory format */ 288*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); 289*76c2145dSArnaud Pouliquen /* 16-bits per sub-frame */ 290*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NBIT_32(player); 291*76c2145dSArnaud Pouliquen /* Set 16-bit sample precision */ 292*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); 293*76c2145dSArnaud Pouliquen break; 294*76c2145dSArnaud Pouliquen case SNDRV_PCM_FORMAT_S32_LE: 295*76c2145dSArnaud Pouliquen /* 16/0 memory format */ 296*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); 297*76c2145dSArnaud Pouliquen /* 32-bits per sub-frame */ 298*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NBIT_32(player); 299*76c2145dSArnaud Pouliquen /* Set 24-bit sample precision */ 300*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); 301*76c2145dSArnaud Pouliquen break; 302*76c2145dSArnaud Pouliquen default: 303*76c2145dSArnaud Pouliquen dev_err(player->dev, "format not supported"); 304*76c2145dSArnaud Pouliquen return -EINVAL; 305*76c2145dSArnaud Pouliquen } 306*76c2145dSArnaud Pouliquen 307*76c2145dSArnaud Pouliquen /* Set parity to be calculated by the hardware */ 308*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(player); 309*76c2145dSArnaud Pouliquen 310*76c2145dSArnaud Pouliquen /* Set channel status bits to be inserted by the hardware */ 311*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(player); 312*76c2145dSArnaud Pouliquen 313*76c2145dSArnaud Pouliquen /* Set user data bits to be inserted by the hardware */ 314*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(player); 315*76c2145dSArnaud Pouliquen 316*76c2145dSArnaud Pouliquen /* Set validity bits to be inserted by the hardware */ 317*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(player); 318*76c2145dSArnaud Pouliquen 319*76c2145dSArnaud Pouliquen /* Set full software control to disabled */ 320*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(player); 321*76c2145dSArnaud Pouliquen 322*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); 323*76c2145dSArnaud Pouliquen 324*76c2145dSArnaud Pouliquen /* Update the channel status */ 325*76c2145dSArnaud Pouliquen uni_player_set_channel_status(player, runtime); 326*76c2145dSArnaud Pouliquen 327*76c2145dSArnaud Pouliquen /* Clear the user validity user bits */ 328*76c2145dSArnaud Pouliquen SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); 329*76c2145dSArnaud Pouliquen 330*76c2145dSArnaud Pouliquen /* Disable one-bit audio mode */ 331*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); 332*76c2145dSArnaud Pouliquen 333*76c2145dSArnaud Pouliquen /* Enable consecutive frames repetition of Z preamble (not for HBRA) */ 334*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(player); 335*76c2145dSArnaud Pouliquen 336*76c2145dSArnaud Pouliquen /* Change to SUF0_SUBF1 and left/right channels swap! */ 337*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(player); 338*76c2145dSArnaud Pouliquen 339*76c2145dSArnaud Pouliquen /* Set data output as MSB first */ 340*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); 341*76c2145dSArnaud Pouliquen 342*76c2145dSArnaud Pouliquen if (player->stream_settings.encoding_mode == 343*76c2145dSArnaud Pouliquen UNIPERIF_IEC958_ENCODING_MODE_ENCODED) 344*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(player); 345*76c2145dSArnaud Pouliquen else 346*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(player); 347*76c2145dSArnaud Pouliquen 348*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); 349*76c2145dSArnaud Pouliquen 350*76c2145dSArnaud Pouliquen /* Set rounding to off */ 351*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_ROUNDING_OFF(player); 352*76c2145dSArnaud Pouliquen 353*76c2145dSArnaud Pouliquen /* Set clock divisor */ 354*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / 128); 355*76c2145dSArnaud Pouliquen 356*76c2145dSArnaud Pouliquen /* Set the spdif latency to not wait before starting player */ 357*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); 358*76c2145dSArnaud Pouliquen 359*76c2145dSArnaud Pouliquen /* 360*76c2145dSArnaud Pouliquen * Ensure iec958 formatting is off. It will be enabled in function 361*76c2145dSArnaud Pouliquen * uni_player_start() at the same time as the operation 362*76c2145dSArnaud Pouliquen * mode is set to work around a silicon issue. 363*76c2145dSArnaud Pouliquen */ 364*76c2145dSArnaud Pouliquen if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) 365*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); 366*76c2145dSArnaud Pouliquen else 367*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); 368*76c2145dSArnaud Pouliquen 369*76c2145dSArnaud Pouliquen return 0; 370*76c2145dSArnaud Pouliquen } 371*76c2145dSArnaud Pouliquen 372*76c2145dSArnaud Pouliquen static int uni_player_prepare_pcm(struct uniperif *player, 373*76c2145dSArnaud Pouliquen struct snd_pcm_runtime *runtime) 374*76c2145dSArnaud Pouliquen { 375*76c2145dSArnaud Pouliquen int output_frame_size, slot_width, clk_div; 376*76c2145dSArnaud Pouliquen 377*76c2145dSArnaud Pouliquen /* Force slot width to 32 in I2S mode (HW constraint) */ 378*76c2145dSArnaud Pouliquen if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == 379*76c2145dSArnaud Pouliquen SND_SOC_DAIFMT_I2S) { 380*76c2145dSArnaud Pouliquen slot_width = 32; 381*76c2145dSArnaud Pouliquen } else { 382*76c2145dSArnaud Pouliquen switch (runtime->format) { 383*76c2145dSArnaud Pouliquen case SNDRV_PCM_FORMAT_S16_LE: 384*76c2145dSArnaud Pouliquen slot_width = 16; 385*76c2145dSArnaud Pouliquen break; 386*76c2145dSArnaud Pouliquen default: 387*76c2145dSArnaud Pouliquen slot_width = 32; 388*76c2145dSArnaud Pouliquen break; 389*76c2145dSArnaud Pouliquen } 390*76c2145dSArnaud Pouliquen } 391*76c2145dSArnaud Pouliquen output_frame_size = slot_width * runtime->channels; 392*76c2145dSArnaud Pouliquen 393*76c2145dSArnaud Pouliquen clk_div = player->mclk / runtime->rate; 394*76c2145dSArnaud Pouliquen /* 395*76c2145dSArnaud Pouliquen * For 32 bits subframe clk_div must be a multiple of 128, 396*76c2145dSArnaud Pouliquen * for 16 bits must be a multiple of 64 397*76c2145dSArnaud Pouliquen */ 398*76c2145dSArnaud Pouliquen if ((slot_width == 32) && (clk_div % 128)) { 399*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid clk_div", __func__); 400*76c2145dSArnaud Pouliquen return -EINVAL; 401*76c2145dSArnaud Pouliquen } 402*76c2145dSArnaud Pouliquen 403*76c2145dSArnaud Pouliquen if ((slot_width == 16) && (clk_div % 64)) { 404*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid clk_div", __func__); 405*76c2145dSArnaud Pouliquen return -EINVAL; 406*76c2145dSArnaud Pouliquen } 407*76c2145dSArnaud Pouliquen 408*76c2145dSArnaud Pouliquen /* 409*76c2145dSArnaud Pouliquen * Number of bits per subframe (which is one channel sample) 410*76c2145dSArnaud Pouliquen * on output - Transfer 16 or 32 bits from FIFO 411*76c2145dSArnaud Pouliquen */ 412*76c2145dSArnaud Pouliquen switch (slot_width) { 413*76c2145dSArnaud Pouliquen case 32: 414*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NBIT_32(player); 415*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); 416*76c2145dSArnaud Pouliquen break; 417*76c2145dSArnaud Pouliquen case 16: 418*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NBIT_16(player); 419*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); 420*76c2145dSArnaud Pouliquen break; 421*76c2145dSArnaud Pouliquen default: 422*76c2145dSArnaud Pouliquen dev_err(player->dev, "subframe format not supported"); 423*76c2145dSArnaud Pouliquen return -EINVAL; 424*76c2145dSArnaud Pouliquen } 425*76c2145dSArnaud Pouliquen 426*76c2145dSArnaud Pouliquen /* Configure data memory format */ 427*76c2145dSArnaud Pouliquen switch (runtime->format) { 428*76c2145dSArnaud Pouliquen case SNDRV_PCM_FORMAT_S16_LE: 429*76c2145dSArnaud Pouliquen /* One data word contains two samples */ 430*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); 431*76c2145dSArnaud Pouliquen break; 432*76c2145dSArnaud Pouliquen 433*76c2145dSArnaud Pouliquen case SNDRV_PCM_FORMAT_S32_LE: 434*76c2145dSArnaud Pouliquen /* 435*76c2145dSArnaud Pouliquen * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits 436*76c2145dSArnaud Pouliquen * on the left than zeros (if less than 32 bytes)"... ;-) 437*76c2145dSArnaud Pouliquen */ 438*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); 439*76c2145dSArnaud Pouliquen break; 440*76c2145dSArnaud Pouliquen 441*76c2145dSArnaud Pouliquen default: 442*76c2145dSArnaud Pouliquen dev_err(player->dev, "format not supported"); 443*76c2145dSArnaud Pouliquen return -EINVAL; 444*76c2145dSArnaud Pouliquen } 445*76c2145dSArnaud Pouliquen 446*76c2145dSArnaud Pouliquen /* Set rounding to off */ 447*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_ROUNDING_OFF(player); 448*76c2145dSArnaud Pouliquen 449*76c2145dSArnaud Pouliquen /* Set clock divisor */ 450*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / (2 * output_frame_size)); 451*76c2145dSArnaud Pouliquen 452*76c2145dSArnaud Pouliquen /* Number of channelsmust be even*/ 453*76c2145dSArnaud Pouliquen if ((runtime->channels % 2) || (runtime->channels < 2) || 454*76c2145dSArnaud Pouliquen (runtime->channels > 10)) { 455*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid nb of channels", __func__); 456*76c2145dSArnaud Pouliquen return -EINVAL; 457*76c2145dSArnaud Pouliquen } 458*76c2145dSArnaud Pouliquen 459*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); 460*76c2145dSArnaud Pouliquen 461*76c2145dSArnaud Pouliquen /* Set 1-bit audio format to disabled */ 462*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); 463*76c2145dSArnaud Pouliquen 464*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); 465*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); 466*76c2145dSArnaud Pouliquen 467*76c2145dSArnaud Pouliquen /* No iec958 formatting as outputting to DAC */ 468*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); 469*76c2145dSArnaud Pouliquen 470*76c2145dSArnaud Pouliquen return 0; 471*76c2145dSArnaud Pouliquen } 472*76c2145dSArnaud Pouliquen 473*76c2145dSArnaud Pouliquen static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, 474*76c2145dSArnaud Pouliquen unsigned int freq, int dir) 475*76c2145dSArnaud Pouliquen { 476*76c2145dSArnaud Pouliquen struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 477*76c2145dSArnaud Pouliquen struct uniperif *player = priv->dai_data.uni; 478*76c2145dSArnaud Pouliquen 479*76c2145dSArnaud Pouliquen if (dir == SND_SOC_CLOCK_IN) 480*76c2145dSArnaud Pouliquen return 0; 481*76c2145dSArnaud Pouliquen 482*76c2145dSArnaud Pouliquen if (clk_id != 0) 483*76c2145dSArnaud Pouliquen return -EINVAL; 484*76c2145dSArnaud Pouliquen 485*76c2145dSArnaud Pouliquen player->mclk = freq; 486*76c2145dSArnaud Pouliquen 487*76c2145dSArnaud Pouliquen return clk_set_rate(player->clk, freq); 488*76c2145dSArnaud Pouliquen } 489*76c2145dSArnaud Pouliquen 490*76c2145dSArnaud Pouliquen static int uni_player_prepare(struct snd_pcm_substream *substream, 491*76c2145dSArnaud Pouliquen struct snd_soc_dai *dai) 492*76c2145dSArnaud Pouliquen { 493*76c2145dSArnaud Pouliquen struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 494*76c2145dSArnaud Pouliquen struct uniperif *player = priv->dai_data.uni; 495*76c2145dSArnaud Pouliquen struct snd_pcm_runtime *runtime = substream->runtime; 496*76c2145dSArnaud Pouliquen int transfer_size, trigger_limit; 497*76c2145dSArnaud Pouliquen int ret; 498*76c2145dSArnaud Pouliquen 499*76c2145dSArnaud Pouliquen /* The player should be stopped */ 500*76c2145dSArnaud Pouliquen if (player->state != UNIPERIF_STATE_STOPPED) { 501*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid player state %d", __func__, 502*76c2145dSArnaud Pouliquen player->state); 503*76c2145dSArnaud Pouliquen return -EINVAL; 504*76c2145dSArnaud Pouliquen } 505*76c2145dSArnaud Pouliquen 506*76c2145dSArnaud Pouliquen /* Calculate transfer size (in fifo cells and bytes) for frame count */ 507*76c2145dSArnaud Pouliquen transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; 508*76c2145dSArnaud Pouliquen 509*76c2145dSArnaud Pouliquen /* Calculate number of empty cells available before asserting DREQ */ 510*76c2145dSArnaud Pouliquen if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { 511*76c2145dSArnaud Pouliquen trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; 512*76c2145dSArnaud Pouliquen } else { 513*76c2145dSArnaud Pouliquen /* 514*76c2145dSArnaud Pouliquen * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 515*76c2145dSArnaud Pouliquen * FDMA_TRIGGER_LIMIT also controls when the state switches 516*76c2145dSArnaud Pouliquen * from OFF or STANDBY to AUDIO DATA. 517*76c2145dSArnaud Pouliquen */ 518*76c2145dSArnaud Pouliquen trigger_limit = transfer_size; 519*76c2145dSArnaud Pouliquen } 520*76c2145dSArnaud Pouliquen 521*76c2145dSArnaud Pouliquen /* Trigger limit must be an even number */ 522*76c2145dSArnaud Pouliquen if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || 523*76c2145dSArnaud Pouliquen (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { 524*76c2145dSArnaud Pouliquen dev_err(player->dev, "invalid trigger limit %d", trigger_limit); 525*76c2145dSArnaud Pouliquen return -EINVAL; 526*76c2145dSArnaud Pouliquen } 527*76c2145dSArnaud Pouliquen 528*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); 529*76c2145dSArnaud Pouliquen 530*76c2145dSArnaud Pouliquen /* Uniperipheral setup depends on player type */ 531*76c2145dSArnaud Pouliquen switch (player->info->player_type) { 532*76c2145dSArnaud Pouliquen case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: 533*76c2145dSArnaud Pouliquen ret = uni_player_prepare_iec958(player, runtime); 534*76c2145dSArnaud Pouliquen break; 535*76c2145dSArnaud Pouliquen case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: 536*76c2145dSArnaud Pouliquen ret = uni_player_prepare_pcm(player, runtime); 537*76c2145dSArnaud Pouliquen break; 538*76c2145dSArnaud Pouliquen case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: 539*76c2145dSArnaud Pouliquen ret = uni_player_prepare_iec958(player, runtime); 540*76c2145dSArnaud Pouliquen break; 541*76c2145dSArnaud Pouliquen default: 542*76c2145dSArnaud Pouliquen dev_err(player->dev, "invalid player type"); 543*76c2145dSArnaud Pouliquen return -EINVAL; 544*76c2145dSArnaud Pouliquen } 545*76c2145dSArnaud Pouliquen 546*76c2145dSArnaud Pouliquen if (ret) 547*76c2145dSArnaud Pouliquen return ret; 548*76c2145dSArnaud Pouliquen 549*76c2145dSArnaud Pouliquen switch (player->daifmt & SND_SOC_DAIFMT_INV_MASK) { 550*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_NB_NF: 551*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); 552*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); 553*76c2145dSArnaud Pouliquen break; 554*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_NB_IF: 555*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); 556*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); 557*76c2145dSArnaud Pouliquen break; 558*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_IB_NF: 559*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); 560*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); 561*76c2145dSArnaud Pouliquen break; 562*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_IB_IF: 563*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); 564*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); 565*76c2145dSArnaud Pouliquen } 566*76c2145dSArnaud Pouliquen 567*76c2145dSArnaud Pouliquen switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { 568*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_I2S: 569*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); 570*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(player); 571*76c2145dSArnaud Pouliquen break; 572*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_LEFT_J: 573*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); 574*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); 575*76c2145dSArnaud Pouliquen break; 576*76c2145dSArnaud Pouliquen case SND_SOC_DAIFMT_RIGHT_J: 577*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(player); 578*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); 579*76c2145dSArnaud Pouliquen break; 580*76c2145dSArnaud Pouliquen default: 581*76c2145dSArnaud Pouliquen dev_err(player->dev, "format not supported"); 582*76c2145dSArnaud Pouliquen return -EINVAL; 583*76c2145dSArnaud Pouliquen } 584*76c2145dSArnaud Pouliquen 585*76c2145dSArnaud Pouliquen SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); 586*76c2145dSArnaud Pouliquen 587*76c2145dSArnaud Pouliquen /* Reset uniperipheral player */ 588*76c2145dSArnaud Pouliquen SET_UNIPERIF_SOFT_RST_SOFT_RST(player); 589*76c2145dSArnaud Pouliquen 590*76c2145dSArnaud Pouliquen return reset_player(player); 591*76c2145dSArnaud Pouliquen } 592*76c2145dSArnaud Pouliquen 593*76c2145dSArnaud Pouliquen static int uni_player_start(struct uniperif *player) 594*76c2145dSArnaud Pouliquen { 595*76c2145dSArnaud Pouliquen int ret; 596*76c2145dSArnaud Pouliquen 597*76c2145dSArnaud Pouliquen /* The player should be stopped */ 598*76c2145dSArnaud Pouliquen if (player->state != UNIPERIF_STATE_STOPPED) { 599*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid player state", __func__); 600*76c2145dSArnaud Pouliquen return -EINVAL; 601*76c2145dSArnaud Pouliquen } 602*76c2145dSArnaud Pouliquen 603*76c2145dSArnaud Pouliquen ret = clk_prepare_enable(player->clk); 604*76c2145dSArnaud Pouliquen if (ret) { 605*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: Failed to enable clock", __func__); 606*76c2145dSArnaud Pouliquen return ret; 607*76c2145dSArnaud Pouliquen } 608*76c2145dSArnaud Pouliquen 609*76c2145dSArnaud Pouliquen /* Clear any pending interrupts */ 610*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITS_BCLR(player, GET_UNIPERIF_ITS(player)); 611*76c2145dSArnaud Pouliquen 612*76c2145dSArnaud Pouliquen /* Set the interrupt mask */ 613*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BSET_DMA_ERROR(player); 614*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player); 615*76c2145dSArnaud Pouliquen 616*76c2145dSArnaud Pouliquen /* Enable underflow recovery interrupts */ 617*76c2145dSArnaud Pouliquen if (player->info->underflow_enabled) { 618*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player); 619*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); 620*76c2145dSArnaud Pouliquen } 621*76c2145dSArnaud Pouliquen 622*76c2145dSArnaud Pouliquen /* Reset uniperipheral player */ 623*76c2145dSArnaud Pouliquen SET_UNIPERIF_SOFT_RST_SOFT_RST(player); 624*76c2145dSArnaud Pouliquen 625*76c2145dSArnaud Pouliquen ret = reset_player(player); 626*76c2145dSArnaud Pouliquen if (ret < 0) 627*76c2145dSArnaud Pouliquen return ret; 628*76c2145dSArnaud Pouliquen 629*76c2145dSArnaud Pouliquen /* 630*76c2145dSArnaud Pouliquen * Does not use IEC61937 features of the uniperipheral hardware. 631*76c2145dSArnaud Pouliquen * Instead it performs IEC61937 in software and inserts it directly 632*76c2145dSArnaud Pouliquen * into the audio data stream. As such, when encoded mode is selected, 633*76c2145dSArnaud Pouliquen * linear pcm mode is still used, but with the differences of the 634*76c2145dSArnaud Pouliquen * channel status bits set for encoded mode and the validity bits set. 635*76c2145dSArnaud Pouliquen */ 636*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(player); 637*76c2145dSArnaud Pouliquen 638*76c2145dSArnaud Pouliquen /* 639*76c2145dSArnaud Pouliquen * If iec958 formatting is required for hdmi or spdif, then it must be 640*76c2145dSArnaud Pouliquen * enabled after the operation mode is set. If set prior to this, it 641*76c2145dSArnaud Pouliquen * will not take affect and hang the player. 642*76c2145dSArnaud Pouliquen */ 643*76c2145dSArnaud Pouliquen if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) 644*76c2145dSArnaud Pouliquen if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) 645*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); 646*76c2145dSArnaud Pouliquen 647*76c2145dSArnaud Pouliquen /* Force channel status update (no update if clk disable) */ 648*76c2145dSArnaud Pouliquen if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) 649*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); 650*76c2145dSArnaud Pouliquen else 651*76c2145dSArnaud Pouliquen SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); 652*76c2145dSArnaud Pouliquen 653*76c2145dSArnaud Pouliquen /* Update state to started */ 654*76c2145dSArnaud Pouliquen player->state = UNIPERIF_STATE_STARTED; 655*76c2145dSArnaud Pouliquen 656*76c2145dSArnaud Pouliquen return 0; 657*76c2145dSArnaud Pouliquen } 658*76c2145dSArnaud Pouliquen 659*76c2145dSArnaud Pouliquen static int uni_player_stop(struct uniperif *player) 660*76c2145dSArnaud Pouliquen { 661*76c2145dSArnaud Pouliquen int ret; 662*76c2145dSArnaud Pouliquen 663*76c2145dSArnaud Pouliquen /* The player should not be in stopped state */ 664*76c2145dSArnaud Pouliquen if (player->state == UNIPERIF_STATE_STOPPED) { 665*76c2145dSArnaud Pouliquen dev_err(player->dev, "%s: invalid player state", __func__); 666*76c2145dSArnaud Pouliquen return -EINVAL; 667*76c2145dSArnaud Pouliquen } 668*76c2145dSArnaud Pouliquen 669*76c2145dSArnaud Pouliquen /* Turn the player off */ 670*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_OPERATION_OFF(player); 671*76c2145dSArnaud Pouliquen 672*76c2145dSArnaud Pouliquen /* Soft reset the player */ 673*76c2145dSArnaud Pouliquen SET_UNIPERIF_SOFT_RST_SOFT_RST(player); 674*76c2145dSArnaud Pouliquen 675*76c2145dSArnaud Pouliquen ret = reset_player(player); 676*76c2145dSArnaud Pouliquen if (ret < 0) 677*76c2145dSArnaud Pouliquen return ret; 678*76c2145dSArnaud Pouliquen 679*76c2145dSArnaud Pouliquen /* Disable interrupts */ 680*76c2145dSArnaud Pouliquen SET_UNIPERIF_ITM_BCLR(player, GET_UNIPERIF_ITM(player)); 681*76c2145dSArnaud Pouliquen 682*76c2145dSArnaud Pouliquen /* Disable clock */ 683*76c2145dSArnaud Pouliquen clk_disable_unprepare(player->clk); 684*76c2145dSArnaud Pouliquen 685*76c2145dSArnaud Pouliquen /* Update state to stopped and return */ 686*76c2145dSArnaud Pouliquen player->state = UNIPERIF_STATE_STOPPED; 687*76c2145dSArnaud Pouliquen 688*76c2145dSArnaud Pouliquen return 0; 689*76c2145dSArnaud Pouliquen } 690*76c2145dSArnaud Pouliquen 691*76c2145dSArnaud Pouliquen int uni_player_resume(struct uniperif *player) 692*76c2145dSArnaud Pouliquen { 693*76c2145dSArnaud Pouliquen int ret; 694*76c2145dSArnaud Pouliquen 695*76c2145dSArnaud Pouliquen /* Select the frequency synthesizer clock */ 696*76c2145dSArnaud Pouliquen if (player->clk_sel) { 697*76c2145dSArnaud Pouliquen ret = regmap_field_write(player->clk_sel, 1); 698*76c2145dSArnaud Pouliquen if (ret) { 699*76c2145dSArnaud Pouliquen dev_err(player->dev, 700*76c2145dSArnaud Pouliquen "%s: Failed to select freq synth clock", 701*76c2145dSArnaud Pouliquen __func__); 702*76c2145dSArnaud Pouliquen return ret; 703*76c2145dSArnaud Pouliquen } 704*76c2145dSArnaud Pouliquen } 705*76c2145dSArnaud Pouliquen 706*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); 707*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_ROUNDING_OFF(player); 708*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); 709*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); 710*76c2145dSArnaud Pouliquen 711*76c2145dSArnaud Pouliquen return 0; 712*76c2145dSArnaud Pouliquen } 713*76c2145dSArnaud Pouliquen EXPORT_SYMBOL_GPL(uni_player_resume); 714*76c2145dSArnaud Pouliquen 715*76c2145dSArnaud Pouliquen static int uni_player_trigger(struct snd_pcm_substream *substream, 716*76c2145dSArnaud Pouliquen int cmd, struct snd_soc_dai *dai) 717*76c2145dSArnaud Pouliquen { 718*76c2145dSArnaud Pouliquen struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 719*76c2145dSArnaud Pouliquen struct uniperif *player = priv->dai_data.uni; 720*76c2145dSArnaud Pouliquen 721*76c2145dSArnaud Pouliquen switch (cmd) { 722*76c2145dSArnaud Pouliquen case SNDRV_PCM_TRIGGER_START: 723*76c2145dSArnaud Pouliquen return uni_player_start(player); 724*76c2145dSArnaud Pouliquen case SNDRV_PCM_TRIGGER_STOP: 725*76c2145dSArnaud Pouliquen return uni_player_stop(player); 726*76c2145dSArnaud Pouliquen case SNDRV_PCM_TRIGGER_RESUME: 727*76c2145dSArnaud Pouliquen return uni_player_resume(player); 728*76c2145dSArnaud Pouliquen default: 729*76c2145dSArnaud Pouliquen return -EINVAL; 730*76c2145dSArnaud Pouliquen } 731*76c2145dSArnaud Pouliquen } 732*76c2145dSArnaud Pouliquen 733*76c2145dSArnaud Pouliquen static void uni_player_shutdown(struct snd_pcm_substream *substream, 734*76c2145dSArnaud Pouliquen struct snd_soc_dai *dai) 735*76c2145dSArnaud Pouliquen { 736*76c2145dSArnaud Pouliquen struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); 737*76c2145dSArnaud Pouliquen struct uniperif *player = priv->dai_data.uni; 738*76c2145dSArnaud Pouliquen 739*76c2145dSArnaud Pouliquen if (player->state != UNIPERIF_STATE_STOPPED) 740*76c2145dSArnaud Pouliquen /* Stop the player */ 741*76c2145dSArnaud Pouliquen uni_player_stop(player); 742*76c2145dSArnaud Pouliquen } 743*76c2145dSArnaud Pouliquen 744*76c2145dSArnaud Pouliquen static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, 745*76c2145dSArnaud Pouliquen struct uniperif *player) 746*76c2145dSArnaud Pouliquen { 747*76c2145dSArnaud Pouliquen int bit_offset; 748*76c2145dSArnaud Pouliquen struct device_node *node = pdev->dev.of_node; 749*76c2145dSArnaud Pouliquen struct regmap *regmap; 750*76c2145dSArnaud Pouliquen 751*76c2145dSArnaud Pouliquen bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; 752*76c2145dSArnaud Pouliquen 753*76c2145dSArnaud Pouliquen regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); 754*76c2145dSArnaud Pouliquen 755*76c2145dSArnaud Pouliquen if (regmap) { 756*76c2145dSArnaud Pouliquen struct reg_field regfield = 757*76c2145dSArnaud Pouliquen REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); 758*76c2145dSArnaud Pouliquen 759*76c2145dSArnaud Pouliquen player->clk_sel = regmap_field_alloc(regmap, regfield); 760*76c2145dSArnaud Pouliquen } else { 761*76c2145dSArnaud Pouliquen dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); 762*76c2145dSArnaud Pouliquen return -EINVAL; 763*76c2145dSArnaud Pouliquen } 764*76c2145dSArnaud Pouliquen 765*76c2145dSArnaud Pouliquen return 0; 766*76c2145dSArnaud Pouliquen } 767*76c2145dSArnaud Pouliquen 768*76c2145dSArnaud Pouliquen static int uni_player_parse_dt(struct platform_device *pdev, 769*76c2145dSArnaud Pouliquen struct uniperif *player) 770*76c2145dSArnaud Pouliquen { 771*76c2145dSArnaud Pouliquen struct uniperif_info *info; 772*76c2145dSArnaud Pouliquen struct device *dev = &pdev->dev; 773*76c2145dSArnaud Pouliquen struct device_node *pnode = pdev->dev.of_node; 774*76c2145dSArnaud Pouliquen const char *mode; 775*76c2145dSArnaud Pouliquen 776*76c2145dSArnaud Pouliquen /* Allocate memory for the info structure */ 777*76c2145dSArnaud Pouliquen info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 778*76c2145dSArnaud Pouliquen if (!info) 779*76c2145dSArnaud Pouliquen return -ENOMEM; 780*76c2145dSArnaud Pouliquen 781*76c2145dSArnaud Pouliquen of_property_read_u32(pnode, "version", &player->ver); 782*76c2145dSArnaud Pouliquen if (player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { 783*76c2145dSArnaud Pouliquen dev_err(dev, "Unknown uniperipheral version "); 784*76c2145dSArnaud Pouliquen return -EINVAL; 785*76c2145dSArnaud Pouliquen } 786*76c2145dSArnaud Pouliquen /* Underflow recovery is only supported on later ip revisions */ 787*76c2145dSArnaud Pouliquen if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) 788*76c2145dSArnaud Pouliquen info->underflow_enabled = 1; 789*76c2145dSArnaud Pouliquen 790*76c2145dSArnaud Pouliquen of_property_read_u32(pnode, "uniperiph-id", &info->id); 791*76c2145dSArnaud Pouliquen 792*76c2145dSArnaud Pouliquen /* Read the device mode property */ 793*76c2145dSArnaud Pouliquen of_property_read_string(pnode, "mode", &mode); 794*76c2145dSArnaud Pouliquen 795*76c2145dSArnaud Pouliquen if (strcasecmp(mode, "hdmi") == 0) 796*76c2145dSArnaud Pouliquen info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; 797*76c2145dSArnaud Pouliquen else if (strcasecmp(mode, "pcm") == 0) 798*76c2145dSArnaud Pouliquen info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; 799*76c2145dSArnaud Pouliquen else if (strcasecmp(mode, "spdif") == 0) 800*76c2145dSArnaud Pouliquen info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; 801*76c2145dSArnaud Pouliquen else 802*76c2145dSArnaud Pouliquen info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; 803*76c2145dSArnaud Pouliquen 804*76c2145dSArnaud Pouliquen /* Save the info structure */ 805*76c2145dSArnaud Pouliquen player->info = info; 806*76c2145dSArnaud Pouliquen 807*76c2145dSArnaud Pouliquen /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ 808*76c2145dSArnaud Pouliquen if (uni_player_parse_dt_clk_glue(pdev, player)) 809*76c2145dSArnaud Pouliquen return -EINVAL; 810*76c2145dSArnaud Pouliquen 811*76c2145dSArnaud Pouliquen return 0; 812*76c2145dSArnaud Pouliquen } 813*76c2145dSArnaud Pouliquen 814*76c2145dSArnaud Pouliquen const struct snd_soc_dai_ops uni_player_dai_ops = { 815*76c2145dSArnaud Pouliquen .shutdown = uni_player_shutdown, 816*76c2145dSArnaud Pouliquen .prepare = uni_player_prepare, 817*76c2145dSArnaud Pouliquen .trigger = uni_player_trigger, 818*76c2145dSArnaud Pouliquen .hw_params = sti_uniperiph_dai_hw_params, 819*76c2145dSArnaud Pouliquen .set_fmt = sti_uniperiph_dai_set_fmt, 820*76c2145dSArnaud Pouliquen .set_sysclk = uni_player_set_sysclk 821*76c2145dSArnaud Pouliquen }; 822*76c2145dSArnaud Pouliquen 823*76c2145dSArnaud Pouliquen int uni_player_init(struct platform_device *pdev, 824*76c2145dSArnaud Pouliquen struct uniperif *player) 825*76c2145dSArnaud Pouliquen { 826*76c2145dSArnaud Pouliquen int ret = 0; 827*76c2145dSArnaud Pouliquen 828*76c2145dSArnaud Pouliquen player->dev = &pdev->dev; 829*76c2145dSArnaud Pouliquen player->state = UNIPERIF_STATE_STOPPED; 830*76c2145dSArnaud Pouliquen player->hw = &uni_player_pcm_hw; 831*76c2145dSArnaud Pouliquen player->dai_ops = &uni_player_dai_ops; 832*76c2145dSArnaud Pouliquen 833*76c2145dSArnaud Pouliquen ret = uni_player_parse_dt(pdev, player); 834*76c2145dSArnaud Pouliquen 835*76c2145dSArnaud Pouliquen if (ret < 0) { 836*76c2145dSArnaud Pouliquen dev_err(player->dev, "Failed to parse DeviceTree"); 837*76c2145dSArnaud Pouliquen return ret; 838*76c2145dSArnaud Pouliquen } 839*76c2145dSArnaud Pouliquen 840*76c2145dSArnaud Pouliquen /* Get uniperif resource */ 841*76c2145dSArnaud Pouliquen player->clk = of_clk_get(pdev->dev.of_node, 0); 842*76c2145dSArnaud Pouliquen if (IS_ERR(player->clk)) 843*76c2145dSArnaud Pouliquen ret = (int)PTR_ERR(player->clk); 844*76c2145dSArnaud Pouliquen 845*76c2145dSArnaud Pouliquen /* Select the frequency synthesizer clock */ 846*76c2145dSArnaud Pouliquen if (player->clk_sel) { 847*76c2145dSArnaud Pouliquen ret = regmap_field_write(player->clk_sel, 1); 848*76c2145dSArnaud Pouliquen if (ret) { 849*76c2145dSArnaud Pouliquen dev_err(player->dev, 850*76c2145dSArnaud Pouliquen "%s: Failed to select freq synth clock", 851*76c2145dSArnaud Pouliquen __func__); 852*76c2145dSArnaud Pouliquen return ret; 853*76c2145dSArnaud Pouliquen } 854*76c2145dSArnaud Pouliquen } 855*76c2145dSArnaud Pouliquen 856*76c2145dSArnaud Pouliquen ret = devm_request_irq(&pdev->dev, player->irq, 857*76c2145dSArnaud Pouliquen uni_player_irq_handler, IRQF_SHARED, 858*76c2145dSArnaud Pouliquen dev_name(&pdev->dev), player); 859*76c2145dSArnaud Pouliquen if (ret < 0) 860*76c2145dSArnaud Pouliquen return ret; 861*76c2145dSArnaud Pouliquen 862*76c2145dSArnaud Pouliquen /* Ensure that disabled by default */ 863*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); 864*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_ROUNDING_OFF(player); 865*76c2145dSArnaud Pouliquen SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); 866*76c2145dSArnaud Pouliquen SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); 867*76c2145dSArnaud Pouliquen 868*76c2145dSArnaud Pouliquen if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { 869*76c2145dSArnaud Pouliquen /* Set default iec958 status bits */ 870*76c2145dSArnaud Pouliquen 871*76c2145dSArnaud Pouliquen /* Consumer, PCM, copyright, 2ch, mode 0 */ 872*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[0] = 0x00; 873*76c2145dSArnaud Pouliquen /* Broadcast reception category */ 874*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[1] = 875*76c2145dSArnaud Pouliquen IEC958_AES1_CON_GENERAL; 876*76c2145dSArnaud Pouliquen /* Do not take into account source or channel number */ 877*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[2] = 878*76c2145dSArnaud Pouliquen IEC958_AES2_CON_SOURCE_UNSPEC; 879*76c2145dSArnaud Pouliquen /* Sampling frequency not indicated */ 880*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[3] = 881*76c2145dSArnaud Pouliquen IEC958_AES3_CON_FS_NOTID; 882*76c2145dSArnaud Pouliquen /* Max sample word 24-bit, sample word length not indicated */ 883*76c2145dSArnaud Pouliquen player->stream_settings.iec958.status[4] = 884*76c2145dSArnaud Pouliquen IEC958_AES4_CON_MAX_WORDLEN_24 | 885*76c2145dSArnaud Pouliquen IEC958_AES4_CON_WORDLEN_24_20; 886*76c2145dSArnaud Pouliquen } 887*76c2145dSArnaud Pouliquen 888*76c2145dSArnaud Pouliquen return 0; 889*76c2145dSArnaud Pouliquen } 890*76c2145dSArnaud Pouliquen EXPORT_SYMBOL_GPL(uni_player_init); 891