1*3592b7f6SOla Lilja /* 2*3592b7f6SOla Lilja * Copyright (C) ST-Ericsson SA 2012 3*3592b7f6SOla Lilja * 4*3592b7f6SOla Lilja * Author: Ola Lilja <ola.o.lilja@stericsson.com>, 5*3592b7f6SOla Lilja * Roger Nilsson <roger.xr.nilsson@stericsson.com> 6*3592b7f6SOla Lilja * for ST-Ericsson. 7*3592b7f6SOla Lilja * 8*3592b7f6SOla Lilja * License terms: 9*3592b7f6SOla Lilja * 10*3592b7f6SOla Lilja * This program is free software; you can redistribute it and/or modify 11*3592b7f6SOla Lilja * it under the terms of the GNU General Public License version 2 as published 12*3592b7f6SOla Lilja * by the Free Software Foundation. 13*3592b7f6SOla Lilja */ 14*3592b7f6SOla Lilja 15*3592b7f6SOla Lilja #include <linux/module.h> 16*3592b7f6SOla Lilja #include <linux/slab.h> 17*3592b7f6SOla Lilja #include <linux/bitops.h> 18*3592b7f6SOla Lilja #include <linux/platform_device.h> 19*3592b7f6SOla Lilja #include <linux/clk.h> 20*3592b7f6SOla Lilja #include <linux/regulator/consumer.h> 21*3592b7f6SOla Lilja #include <linux/mfd/dbx500-prcmu.h> 22*3592b7f6SOla Lilja 23*3592b7f6SOla Lilja #include <mach/hardware.h> 24*3592b7f6SOla Lilja #include <mach/board-mop500-msp.h> 25*3592b7f6SOla Lilja 26*3592b7f6SOla Lilja #include <sound/soc.h> 27*3592b7f6SOla Lilja #include <sound/soc-dai.h> 28*3592b7f6SOla Lilja 29*3592b7f6SOla Lilja #include "ux500_msp_i2s.h" 30*3592b7f6SOla Lilja #include "ux500_msp_dai.h" 31*3592b7f6SOla Lilja 32*3592b7f6SOla Lilja static int setup_pcm_multichan(struct snd_soc_dai *dai, 33*3592b7f6SOla Lilja struct ux500_msp_config *msp_config) 34*3592b7f6SOla Lilja { 35*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 36*3592b7f6SOla Lilja struct msp_multichannel_config *multi = 37*3592b7f6SOla Lilja &msp_config->multichannel_config; 38*3592b7f6SOla Lilja 39*3592b7f6SOla Lilja if (drvdata->slots > 1) { 40*3592b7f6SOla Lilja msp_config->multichannel_configured = 1; 41*3592b7f6SOla Lilja 42*3592b7f6SOla Lilja multi->tx_multichannel_enable = true; 43*3592b7f6SOla Lilja multi->rx_multichannel_enable = true; 44*3592b7f6SOla Lilja multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED; 45*3592b7f6SOla Lilja 46*3592b7f6SOla Lilja multi->tx_channel_0_enable = drvdata->tx_mask; 47*3592b7f6SOla Lilja multi->tx_channel_1_enable = 0; 48*3592b7f6SOla Lilja multi->tx_channel_2_enable = 0; 49*3592b7f6SOla Lilja multi->tx_channel_3_enable = 0; 50*3592b7f6SOla Lilja 51*3592b7f6SOla Lilja multi->rx_channel_0_enable = drvdata->rx_mask; 52*3592b7f6SOla Lilja multi->rx_channel_1_enable = 0; 53*3592b7f6SOla Lilja multi->rx_channel_2_enable = 0; 54*3592b7f6SOla Lilja multi->rx_channel_3_enable = 0; 55*3592b7f6SOla Lilja 56*3592b7f6SOla Lilja dev_dbg(dai->dev, 57*3592b7f6SOla Lilja "%s: Multichannel enabled. Slots: %d, TX: %u, RX: %u\n", 58*3592b7f6SOla Lilja __func__, drvdata->slots, multi->tx_channel_0_enable, 59*3592b7f6SOla Lilja multi->rx_channel_0_enable); 60*3592b7f6SOla Lilja } 61*3592b7f6SOla Lilja 62*3592b7f6SOla Lilja return 0; 63*3592b7f6SOla Lilja } 64*3592b7f6SOla Lilja 65*3592b7f6SOla Lilja static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate, 66*3592b7f6SOla Lilja struct msp_protdesc *prot_desc) 67*3592b7f6SOla Lilja { 68*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 69*3592b7f6SOla Lilja 70*3592b7f6SOla Lilja switch (drvdata->slots) { 71*3592b7f6SOla Lilja case 1: 72*3592b7f6SOla Lilja switch (rate) { 73*3592b7f6SOla Lilja case 8000: 74*3592b7f6SOla Lilja prot_desc->frame_period = 75*3592b7f6SOla Lilja FRAME_PER_SINGLE_SLOT_8_KHZ; 76*3592b7f6SOla Lilja break; 77*3592b7f6SOla Lilja 78*3592b7f6SOla Lilja case 16000: 79*3592b7f6SOla Lilja prot_desc->frame_period = 80*3592b7f6SOla Lilja FRAME_PER_SINGLE_SLOT_16_KHZ; 81*3592b7f6SOla Lilja break; 82*3592b7f6SOla Lilja 83*3592b7f6SOla Lilja case 44100: 84*3592b7f6SOla Lilja prot_desc->frame_period = 85*3592b7f6SOla Lilja FRAME_PER_SINGLE_SLOT_44_1_KHZ; 86*3592b7f6SOla Lilja break; 87*3592b7f6SOla Lilja 88*3592b7f6SOla Lilja case 48000: 89*3592b7f6SOla Lilja prot_desc->frame_period = 90*3592b7f6SOla Lilja FRAME_PER_SINGLE_SLOT_48_KHZ; 91*3592b7f6SOla Lilja break; 92*3592b7f6SOla Lilja 93*3592b7f6SOla Lilja default: 94*3592b7f6SOla Lilja dev_err(dai->dev, 95*3592b7f6SOla Lilja "%s: Error: Unsupported sample-rate (freq = %d)!\n", 96*3592b7f6SOla Lilja __func__, rate); 97*3592b7f6SOla Lilja return -EINVAL; 98*3592b7f6SOla Lilja } 99*3592b7f6SOla Lilja break; 100*3592b7f6SOla Lilja 101*3592b7f6SOla Lilja case 2: 102*3592b7f6SOla Lilja prot_desc->frame_period = FRAME_PER_2_SLOTS; 103*3592b7f6SOla Lilja break; 104*3592b7f6SOla Lilja 105*3592b7f6SOla Lilja case 8: 106*3592b7f6SOla Lilja prot_desc->frame_period = FRAME_PER_8_SLOTS; 107*3592b7f6SOla Lilja break; 108*3592b7f6SOla Lilja 109*3592b7f6SOla Lilja case 16: 110*3592b7f6SOla Lilja prot_desc->frame_period = FRAME_PER_16_SLOTS; 111*3592b7f6SOla Lilja break; 112*3592b7f6SOla Lilja default: 113*3592b7f6SOla Lilja dev_err(dai->dev, 114*3592b7f6SOla Lilja "%s: Error: Unsupported slot-count (slots = %d)!\n", 115*3592b7f6SOla Lilja __func__, drvdata->slots); 116*3592b7f6SOla Lilja return -EINVAL; 117*3592b7f6SOla Lilja } 118*3592b7f6SOla Lilja 119*3592b7f6SOla Lilja prot_desc->clocks_per_frame = 120*3592b7f6SOla Lilja prot_desc->frame_period+1; 121*3592b7f6SOla Lilja 122*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: Clocks per frame: %u\n", 123*3592b7f6SOla Lilja __func__, 124*3592b7f6SOla Lilja prot_desc->clocks_per_frame); 125*3592b7f6SOla Lilja 126*3592b7f6SOla Lilja return 0; 127*3592b7f6SOla Lilja } 128*3592b7f6SOla Lilja 129*3592b7f6SOla Lilja static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate, 130*3592b7f6SOla Lilja struct msp_protdesc *prot_desc) 131*3592b7f6SOla Lilja { 132*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 133*3592b7f6SOla Lilja 134*3592b7f6SOla Lilja u32 frame_length = MSP_FRAME_LEN_1; 135*3592b7f6SOla Lilja prot_desc->frame_width = 0; 136*3592b7f6SOla Lilja 137*3592b7f6SOla Lilja switch (drvdata->slots) { 138*3592b7f6SOla Lilja case 1: 139*3592b7f6SOla Lilja frame_length = MSP_FRAME_LEN_1; 140*3592b7f6SOla Lilja break; 141*3592b7f6SOla Lilja 142*3592b7f6SOla Lilja case 2: 143*3592b7f6SOla Lilja frame_length = MSP_FRAME_LEN_2; 144*3592b7f6SOla Lilja break; 145*3592b7f6SOla Lilja 146*3592b7f6SOla Lilja case 8: 147*3592b7f6SOla Lilja frame_length = MSP_FRAME_LEN_8; 148*3592b7f6SOla Lilja break; 149*3592b7f6SOla Lilja 150*3592b7f6SOla Lilja case 16: 151*3592b7f6SOla Lilja frame_length = MSP_FRAME_LEN_16; 152*3592b7f6SOla Lilja break; 153*3592b7f6SOla Lilja default: 154*3592b7f6SOla Lilja dev_err(dai->dev, 155*3592b7f6SOla Lilja "%s: Error: Unsupported slot-count (slots = %d)!\n", 156*3592b7f6SOla Lilja __func__, drvdata->slots); 157*3592b7f6SOla Lilja return -EINVAL; 158*3592b7f6SOla Lilja } 159*3592b7f6SOla Lilja 160*3592b7f6SOla Lilja prot_desc->tx_frame_len_1 = frame_length; 161*3592b7f6SOla Lilja prot_desc->rx_frame_len_1 = frame_length; 162*3592b7f6SOla Lilja prot_desc->tx_frame_len_2 = frame_length; 163*3592b7f6SOla Lilja prot_desc->rx_frame_len_2 = frame_length; 164*3592b7f6SOla Lilja 165*3592b7f6SOla Lilja prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16; 166*3592b7f6SOla Lilja prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16; 167*3592b7f6SOla Lilja prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16; 168*3592b7f6SOla Lilja prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16; 169*3592b7f6SOla Lilja 170*3592b7f6SOla Lilja return setup_frameper(dai, rate, prot_desc); 171*3592b7f6SOla Lilja } 172*3592b7f6SOla Lilja 173*3592b7f6SOla Lilja static int setup_clocking(struct snd_soc_dai *dai, 174*3592b7f6SOla Lilja unsigned int fmt, 175*3592b7f6SOla Lilja struct ux500_msp_config *msp_config) 176*3592b7f6SOla Lilja { 177*3592b7f6SOla Lilja switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 178*3592b7f6SOla Lilja case SND_SOC_DAIFMT_NB_NF: 179*3592b7f6SOla Lilja break; 180*3592b7f6SOla Lilja 181*3592b7f6SOla Lilja case SND_SOC_DAIFMT_NB_IF: 182*3592b7f6SOla Lilja msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT; 183*3592b7f6SOla Lilja msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT; 184*3592b7f6SOla Lilja 185*3592b7f6SOla Lilja break; 186*3592b7f6SOla Lilja 187*3592b7f6SOla Lilja default: 188*3592b7f6SOla Lilja dev_err(dai->dev, 189*3592b7f6SOla Lilja "%s: Error: Unsopported inversion (fmt = 0x%x)!\n", 190*3592b7f6SOla Lilja __func__, fmt); 191*3592b7f6SOla Lilja 192*3592b7f6SOla Lilja return -EINVAL; 193*3592b7f6SOla Lilja } 194*3592b7f6SOla Lilja 195*3592b7f6SOla Lilja switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 196*3592b7f6SOla Lilja case SND_SOC_DAIFMT_CBM_CFM: 197*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: Codec is master.\n", __func__); 198*3592b7f6SOla Lilja 199*3592b7f6SOla Lilja msp_config->iodelay = 0x20; 200*3592b7f6SOla Lilja msp_config->rx_fsync_sel = 0; 201*3592b7f6SOla Lilja msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT; 202*3592b7f6SOla Lilja msp_config->tx_clk_sel = 0; 203*3592b7f6SOla Lilja msp_config->rx_clk_sel = 0; 204*3592b7f6SOla Lilja msp_config->srg_clk_sel = 0x2 << SCKSEL_SHIFT; 205*3592b7f6SOla Lilja 206*3592b7f6SOla Lilja break; 207*3592b7f6SOla Lilja 208*3592b7f6SOla Lilja case SND_SOC_DAIFMT_CBS_CFS: 209*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__); 210*3592b7f6SOla Lilja 211*3592b7f6SOla Lilja msp_config->tx_clk_sel = TX_CLK_SEL_SRG; 212*3592b7f6SOla Lilja msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG; 213*3592b7f6SOla Lilja msp_config->rx_clk_sel = RX_CLK_SEL_SRG; 214*3592b7f6SOla Lilja msp_config->rx_fsync_sel = RX_SYNC_SRG; 215*3592b7f6SOla Lilja msp_config->srg_clk_sel = 1 << SCKSEL_SHIFT; 216*3592b7f6SOla Lilja 217*3592b7f6SOla Lilja break; 218*3592b7f6SOla Lilja 219*3592b7f6SOla Lilja default: 220*3592b7f6SOla Lilja dev_err(dai->dev, "%s: Error: Unsopported master (fmt = 0x%x)!\n", 221*3592b7f6SOla Lilja __func__, fmt); 222*3592b7f6SOla Lilja 223*3592b7f6SOla Lilja return -EINVAL; 224*3592b7f6SOla Lilja } 225*3592b7f6SOla Lilja 226*3592b7f6SOla Lilja return 0; 227*3592b7f6SOla Lilja } 228*3592b7f6SOla Lilja 229*3592b7f6SOla Lilja static int setup_pcm_protdesc(struct snd_soc_dai *dai, 230*3592b7f6SOla Lilja unsigned int fmt, 231*3592b7f6SOla Lilja struct msp_protdesc *prot_desc) 232*3592b7f6SOla Lilja { 233*3592b7f6SOla Lilja prot_desc->rx_phase_mode = MSP_SINGLE_PHASE; 234*3592b7f6SOla Lilja prot_desc->tx_phase_mode = MSP_SINGLE_PHASE; 235*3592b7f6SOla Lilja prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE; 236*3592b7f6SOla Lilja prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE; 237*3592b7f6SOla Lilja prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST; 238*3592b7f6SOla Lilja prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST; 239*3592b7f6SOla Lilja prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_HI); 240*3592b7f6SOla Lilja prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_HI << RFSPOL_SHIFT; 241*3592b7f6SOla Lilja 242*3592b7f6SOla Lilja if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) { 243*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: DSP_A.\n", __func__); 244*3592b7f6SOla Lilja prot_desc->rx_clk_pol = MSP_RISING_EDGE; 245*3592b7f6SOla Lilja prot_desc->tx_clk_pol = MSP_FALLING_EDGE; 246*3592b7f6SOla Lilja 247*3592b7f6SOla Lilja prot_desc->rx_data_delay = MSP_DELAY_1; 248*3592b7f6SOla Lilja prot_desc->tx_data_delay = MSP_DELAY_1; 249*3592b7f6SOla Lilja } else { 250*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: DSP_B.\n", __func__); 251*3592b7f6SOla Lilja prot_desc->rx_clk_pol = MSP_FALLING_EDGE; 252*3592b7f6SOla Lilja prot_desc->tx_clk_pol = MSP_RISING_EDGE; 253*3592b7f6SOla Lilja 254*3592b7f6SOla Lilja prot_desc->rx_data_delay = MSP_DELAY_0; 255*3592b7f6SOla Lilja prot_desc->tx_data_delay = MSP_DELAY_0; 256*3592b7f6SOla Lilja } 257*3592b7f6SOla Lilja 258*3592b7f6SOla Lilja prot_desc->rx_half_word_swap = MSP_SWAP_NONE; 259*3592b7f6SOla Lilja prot_desc->tx_half_word_swap = MSP_SWAP_NONE; 260*3592b7f6SOla Lilja prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR; 261*3592b7f6SOla Lilja prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR; 262*3592b7f6SOla Lilja prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE; 263*3592b7f6SOla Lilja 264*3592b7f6SOla Lilja return 0; 265*3592b7f6SOla Lilja } 266*3592b7f6SOla Lilja 267*3592b7f6SOla Lilja static int setup_i2s_protdesc(struct msp_protdesc *prot_desc) 268*3592b7f6SOla Lilja { 269*3592b7f6SOla Lilja prot_desc->rx_phase_mode = MSP_DUAL_PHASE; 270*3592b7f6SOla Lilja prot_desc->tx_phase_mode = MSP_DUAL_PHASE; 271*3592b7f6SOla Lilja prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC; 272*3592b7f6SOla Lilja prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC; 273*3592b7f6SOla Lilja prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST; 274*3592b7f6SOla Lilja prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST; 275*3592b7f6SOla Lilja prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_LO); 276*3592b7f6SOla Lilja prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_LO << RFSPOL_SHIFT; 277*3592b7f6SOla Lilja 278*3592b7f6SOla Lilja prot_desc->rx_frame_len_1 = MSP_FRAME_LEN_1; 279*3592b7f6SOla Lilja prot_desc->rx_frame_len_2 = MSP_FRAME_LEN_1; 280*3592b7f6SOla Lilja prot_desc->tx_frame_len_1 = MSP_FRAME_LEN_1; 281*3592b7f6SOla Lilja prot_desc->tx_frame_len_2 = MSP_FRAME_LEN_1; 282*3592b7f6SOla Lilja prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16; 283*3592b7f6SOla Lilja prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16; 284*3592b7f6SOla Lilja prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16; 285*3592b7f6SOla Lilja prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16; 286*3592b7f6SOla Lilja 287*3592b7f6SOla Lilja prot_desc->rx_clk_pol = MSP_RISING_EDGE; 288*3592b7f6SOla Lilja prot_desc->tx_clk_pol = MSP_FALLING_EDGE; 289*3592b7f6SOla Lilja 290*3592b7f6SOla Lilja prot_desc->rx_data_delay = MSP_DELAY_0; 291*3592b7f6SOla Lilja prot_desc->tx_data_delay = MSP_DELAY_0; 292*3592b7f6SOla Lilja 293*3592b7f6SOla Lilja prot_desc->tx_half_word_swap = MSP_SWAP_NONE; 294*3592b7f6SOla Lilja prot_desc->rx_half_word_swap = MSP_SWAP_NONE; 295*3592b7f6SOla Lilja prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR; 296*3592b7f6SOla Lilja prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR; 297*3592b7f6SOla Lilja prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE; 298*3592b7f6SOla Lilja 299*3592b7f6SOla Lilja return 0; 300*3592b7f6SOla Lilja } 301*3592b7f6SOla Lilja 302*3592b7f6SOla Lilja static int setup_msp_config(struct snd_pcm_substream *substream, 303*3592b7f6SOla Lilja struct snd_soc_dai *dai, 304*3592b7f6SOla Lilja struct ux500_msp_config *msp_config) 305*3592b7f6SOla Lilja { 306*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 307*3592b7f6SOla Lilja struct msp_protdesc *prot_desc = &msp_config->protdesc; 308*3592b7f6SOla Lilja struct snd_pcm_runtime *runtime = substream->runtime; 309*3592b7f6SOla Lilja unsigned int fmt = drvdata->fmt; 310*3592b7f6SOla Lilja int ret; 311*3592b7f6SOla Lilja 312*3592b7f6SOla Lilja memset(msp_config, 0, sizeof(*msp_config)); 313*3592b7f6SOla Lilja 314*3592b7f6SOla Lilja msp_config->f_inputclk = drvdata->master_clk; 315*3592b7f6SOla Lilja 316*3592b7f6SOla Lilja msp_config->tx_fifo_config = TX_FIFO_ENABLE; 317*3592b7f6SOla Lilja msp_config->rx_fifo_config = RX_FIFO_ENABLE; 318*3592b7f6SOla Lilja msp_config->def_elem_len = 1; 319*3592b7f6SOla Lilja msp_config->direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 320*3592b7f6SOla Lilja MSP_DIR_TX : MSP_DIR_RX; 321*3592b7f6SOla Lilja msp_config->data_size = MSP_DATA_BITS_32; 322*3592b7f6SOla Lilja msp_config->frame_freq = runtime->rate; 323*3592b7f6SOla Lilja 324*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: f_inputclk = %u, frame_freq = %u.\n", 325*3592b7f6SOla Lilja __func__, msp_config->f_inputclk, msp_config->frame_freq); 326*3592b7f6SOla Lilja /* To avoid division by zero */ 327*3592b7f6SOla Lilja prot_desc->clocks_per_frame = 1; 328*3592b7f6SOla Lilja 329*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__, 330*3592b7f6SOla Lilja runtime->rate, runtime->channels); 331*3592b7f6SOla Lilja switch (fmt & 332*3592b7f6SOla Lilja (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { 333*3592b7f6SOla Lilja case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: 334*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__); 335*3592b7f6SOla Lilja 336*3592b7f6SOla Lilja msp_config->default_protdesc = 1; 337*3592b7f6SOla Lilja msp_config->protocol = MSP_I2S_PROTOCOL; 338*3592b7f6SOla Lilja break; 339*3592b7f6SOla Lilja 340*3592b7f6SOla Lilja case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: 341*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__); 342*3592b7f6SOla Lilja 343*3592b7f6SOla Lilja msp_config->data_size = MSP_DATA_BITS_16; 344*3592b7f6SOla Lilja msp_config->protocol = MSP_I2S_PROTOCOL; 345*3592b7f6SOla Lilja 346*3592b7f6SOla Lilja ret = setup_i2s_protdesc(prot_desc); 347*3592b7f6SOla Lilja if (ret < 0) 348*3592b7f6SOla Lilja return ret; 349*3592b7f6SOla Lilja 350*3592b7f6SOla Lilja break; 351*3592b7f6SOla Lilja 352*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: 353*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: 354*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: 355*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: 356*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: PCM format.\n", __func__); 357*3592b7f6SOla Lilja 358*3592b7f6SOla Lilja msp_config->data_size = MSP_DATA_BITS_16; 359*3592b7f6SOla Lilja msp_config->protocol = MSP_PCM_PROTOCOL; 360*3592b7f6SOla Lilja 361*3592b7f6SOla Lilja ret = setup_pcm_protdesc(dai, fmt, prot_desc); 362*3592b7f6SOla Lilja if (ret < 0) 363*3592b7f6SOla Lilja return ret; 364*3592b7f6SOla Lilja 365*3592b7f6SOla Lilja ret = setup_pcm_multichan(dai, msp_config); 366*3592b7f6SOla Lilja if (ret < 0) 367*3592b7f6SOla Lilja return ret; 368*3592b7f6SOla Lilja 369*3592b7f6SOla Lilja ret = setup_pcm_framing(dai, runtime->rate, prot_desc); 370*3592b7f6SOla Lilja if (ret < 0) 371*3592b7f6SOla Lilja return ret; 372*3592b7f6SOla Lilja 373*3592b7f6SOla Lilja break; 374*3592b7f6SOla Lilja 375*3592b7f6SOla Lilja default: 376*3592b7f6SOla Lilja dev_err(dai->dev, "%s: Error: Unsopported format (%d)!\n", 377*3592b7f6SOla Lilja __func__, fmt); 378*3592b7f6SOla Lilja return -EINVAL; 379*3592b7f6SOla Lilja } 380*3592b7f6SOla Lilja 381*3592b7f6SOla Lilja return setup_clocking(dai, fmt, msp_config); 382*3592b7f6SOla Lilja } 383*3592b7f6SOla Lilja 384*3592b7f6SOla Lilja static int ux500_msp_dai_startup(struct snd_pcm_substream *substream, 385*3592b7f6SOla Lilja struct snd_soc_dai *dai) 386*3592b7f6SOla Lilja { 387*3592b7f6SOla Lilja int ret = 0; 388*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 389*3592b7f6SOla Lilja 390*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, 391*3592b7f6SOla Lilja snd_pcm_stream_str(substream)); 392*3592b7f6SOla Lilja 393*3592b7f6SOla Lilja /* Enable regulator */ 394*3592b7f6SOla Lilja ret = regulator_enable(drvdata->reg_vape); 395*3592b7f6SOla Lilja if (ret != 0) { 396*3592b7f6SOla Lilja dev_err(drvdata->msp->dev, 397*3592b7f6SOla Lilja "%s: Failed to enable regulator!\n", __func__); 398*3592b7f6SOla Lilja return ret; 399*3592b7f6SOla Lilja } 400*3592b7f6SOla Lilja 401*3592b7f6SOla Lilja /* Enable clock */ 402*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: Enabling MSP-clock.\n", __func__); 403*3592b7f6SOla Lilja clk_enable(drvdata->clk); 404*3592b7f6SOla Lilja 405*3592b7f6SOla Lilja return 0; 406*3592b7f6SOla Lilja } 407*3592b7f6SOla Lilja 408*3592b7f6SOla Lilja static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, 409*3592b7f6SOla Lilja struct snd_soc_dai *dai) 410*3592b7f6SOla Lilja { 411*3592b7f6SOla Lilja int ret; 412*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 413*3592b7f6SOla Lilja bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 414*3592b7f6SOla Lilja 415*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, 416*3592b7f6SOla Lilja snd_pcm_stream_str(substream)); 417*3592b7f6SOla Lilja 418*3592b7f6SOla Lilja if (drvdata->vape_opp_constraint == 1) { 419*3592b7f6SOla Lilja prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, 420*3592b7f6SOla Lilja "ux500_msp_i2s", 50); 421*3592b7f6SOla Lilja drvdata->vape_opp_constraint = 0; 422*3592b7f6SOla Lilja } 423*3592b7f6SOla Lilja 424*3592b7f6SOla Lilja if (ux500_msp_i2s_close(drvdata->msp, 425*3592b7f6SOla Lilja is_playback ? MSP_DIR_TX : MSP_DIR_RX)) { 426*3592b7f6SOla Lilja dev_err(dai->dev, 427*3592b7f6SOla Lilja "%s: Error: MSP %d (%s): Unable to close i2s.\n", 428*3592b7f6SOla Lilja __func__, dai->id, snd_pcm_stream_str(substream)); 429*3592b7f6SOla Lilja } 430*3592b7f6SOla Lilja 431*3592b7f6SOla Lilja /* Disable clock */ 432*3592b7f6SOla Lilja clk_disable(drvdata->clk); 433*3592b7f6SOla Lilja 434*3592b7f6SOla Lilja /* Disable regulator */ 435*3592b7f6SOla Lilja ret = regulator_disable(drvdata->reg_vape); 436*3592b7f6SOla Lilja if (ret < 0) 437*3592b7f6SOla Lilja dev_err(dai->dev, 438*3592b7f6SOla Lilja "%s: ERROR: Failed to disable regulator (%d)!\n", 439*3592b7f6SOla Lilja __func__, ret); 440*3592b7f6SOla Lilja } 441*3592b7f6SOla Lilja 442*3592b7f6SOla Lilja static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, 443*3592b7f6SOla Lilja struct snd_soc_dai *dai) 444*3592b7f6SOla Lilja { 445*3592b7f6SOla Lilja int ret = 0; 446*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 447*3592b7f6SOla Lilja struct snd_pcm_runtime *runtime = substream->runtime; 448*3592b7f6SOla Lilja struct ux500_msp_config msp_config; 449*3592b7f6SOla Lilja 450*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__, 451*3592b7f6SOla Lilja dai->id, snd_pcm_stream_str(substream), runtime->rate); 452*3592b7f6SOla Lilja 453*3592b7f6SOla Lilja setup_msp_config(substream, dai, &msp_config); 454*3592b7f6SOla Lilja 455*3592b7f6SOla Lilja ret = ux500_msp_i2s_open(drvdata->msp, &msp_config); 456*3592b7f6SOla Lilja if (ret < 0) { 457*3592b7f6SOla Lilja dev_err(dai->dev, "%s: Error: msp_setup failed (ret = %d)!\n", 458*3592b7f6SOla Lilja __func__, ret); 459*3592b7f6SOla Lilja return ret; 460*3592b7f6SOla Lilja } 461*3592b7f6SOla Lilja 462*3592b7f6SOla Lilja /* Set OPP-level */ 463*3592b7f6SOla Lilja if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) && 464*3592b7f6SOla Lilja (drvdata->msp->f_bitclk > 19200000)) { 465*3592b7f6SOla Lilja /* If the bit-clock is higher than 19.2MHz, Vape should be 466*3592b7f6SOla Lilja * run in 100% OPP. Only when bit-clock is used (MSP master) */ 467*3592b7f6SOla Lilja prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, 468*3592b7f6SOla Lilja "ux500-msp-i2s", 100); 469*3592b7f6SOla Lilja drvdata->vape_opp_constraint = 1; 470*3592b7f6SOla Lilja } else { 471*3592b7f6SOla Lilja prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, 472*3592b7f6SOla Lilja "ux500-msp-i2s", 50); 473*3592b7f6SOla Lilja drvdata->vape_opp_constraint = 0; 474*3592b7f6SOla Lilja } 475*3592b7f6SOla Lilja 476*3592b7f6SOla Lilja return ret; 477*3592b7f6SOla Lilja } 478*3592b7f6SOla Lilja 479*3592b7f6SOla Lilja static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, 480*3592b7f6SOla Lilja struct snd_pcm_hw_params *params, 481*3592b7f6SOla Lilja struct snd_soc_dai *dai) 482*3592b7f6SOla Lilja { 483*3592b7f6SOla Lilja unsigned int mask, slots_active; 484*3592b7f6SOla Lilja struct snd_pcm_runtime *runtime = substream->runtime; 485*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 486*3592b7f6SOla Lilja 487*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", 488*3592b7f6SOla Lilja __func__, dai->id, snd_pcm_stream_str(substream)); 489*3592b7f6SOla Lilja 490*3592b7f6SOla Lilja switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 491*3592b7f6SOla Lilja case SND_SOC_DAIFMT_I2S: 492*3592b7f6SOla Lilja snd_pcm_hw_constraint_minmax(runtime, 493*3592b7f6SOla Lilja SNDRV_PCM_HW_PARAM_CHANNELS, 494*3592b7f6SOla Lilja 1, 2); 495*3592b7f6SOla Lilja break; 496*3592b7f6SOla Lilja 497*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_B: 498*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_A: 499*3592b7f6SOla Lilja mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 500*3592b7f6SOla Lilja drvdata->tx_mask : 501*3592b7f6SOla Lilja drvdata->rx_mask; 502*3592b7f6SOla Lilja 503*3592b7f6SOla Lilja slots_active = hweight32(mask); 504*3592b7f6SOla Lilja dev_dbg(dai->dev, "TDM-slots active: %d", slots_active); 505*3592b7f6SOla Lilja 506*3592b7f6SOla Lilja snd_pcm_hw_constraint_minmax(runtime, 507*3592b7f6SOla Lilja SNDRV_PCM_HW_PARAM_CHANNELS, 508*3592b7f6SOla Lilja slots_active, slots_active); 509*3592b7f6SOla Lilja break; 510*3592b7f6SOla Lilja 511*3592b7f6SOla Lilja default: 512*3592b7f6SOla Lilja dev_err(dai->dev, 513*3592b7f6SOla Lilja "%s: Error: Unsupported protocol (fmt = 0x%x)!\n", 514*3592b7f6SOla Lilja __func__, drvdata->fmt); 515*3592b7f6SOla Lilja return -EINVAL; 516*3592b7f6SOla Lilja } 517*3592b7f6SOla Lilja 518*3592b7f6SOla Lilja return 0; 519*3592b7f6SOla Lilja } 520*3592b7f6SOla Lilja 521*3592b7f6SOla Lilja static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai, 522*3592b7f6SOla Lilja unsigned int fmt) 523*3592b7f6SOla Lilja { 524*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 525*3592b7f6SOla Lilja 526*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id); 527*3592b7f6SOla Lilja 528*3592b7f6SOla Lilja switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | 529*3592b7f6SOla Lilja SND_SOC_DAIFMT_MASTER_MASK)) { 530*3592b7f6SOla Lilja case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: 531*3592b7f6SOla Lilja case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: 532*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: 533*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: 534*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: 535*3592b7f6SOla Lilja case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: 536*3592b7f6SOla Lilja break; 537*3592b7f6SOla Lilja 538*3592b7f6SOla Lilja default: 539*3592b7f6SOla Lilja dev_err(dai->dev, 540*3592b7f6SOla Lilja "%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n", 541*3592b7f6SOla Lilja __func__, drvdata->fmt); 542*3592b7f6SOla Lilja return -EINVAL; 543*3592b7f6SOla Lilja } 544*3592b7f6SOla Lilja 545*3592b7f6SOla Lilja switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 546*3592b7f6SOla Lilja case SND_SOC_DAIFMT_NB_NF: 547*3592b7f6SOla Lilja case SND_SOC_DAIFMT_NB_IF: 548*3592b7f6SOla Lilja case SND_SOC_DAIFMT_IB_IF: 549*3592b7f6SOla Lilja break; 550*3592b7f6SOla Lilja 551*3592b7f6SOla Lilja default: 552*3592b7f6SOla Lilja dev_err(dai->dev, 553*3592b7f6SOla Lilja "%s: Error: Unsupported inversion (fmt = 0x%x)!\n", 554*3592b7f6SOla Lilja __func__, drvdata->fmt); 555*3592b7f6SOla Lilja return -EINVAL; 556*3592b7f6SOla Lilja } 557*3592b7f6SOla Lilja 558*3592b7f6SOla Lilja drvdata->fmt = fmt; 559*3592b7f6SOla Lilja return 0; 560*3592b7f6SOla Lilja } 561*3592b7f6SOla Lilja 562*3592b7f6SOla Lilja static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai, 563*3592b7f6SOla Lilja unsigned int tx_mask, 564*3592b7f6SOla Lilja unsigned int rx_mask, 565*3592b7f6SOla Lilja int slots, int slot_width) 566*3592b7f6SOla Lilja { 567*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 568*3592b7f6SOla Lilja unsigned int cap; 569*3592b7f6SOla Lilja 570*3592b7f6SOla Lilja switch (slots) { 571*3592b7f6SOla Lilja case 1: 572*3592b7f6SOla Lilja cap = 0x01; 573*3592b7f6SOla Lilja break; 574*3592b7f6SOla Lilja case 2: 575*3592b7f6SOla Lilja cap = 0x03; 576*3592b7f6SOla Lilja break; 577*3592b7f6SOla Lilja case 8: 578*3592b7f6SOla Lilja cap = 0xFF; 579*3592b7f6SOla Lilja break; 580*3592b7f6SOla Lilja case 16: 581*3592b7f6SOla Lilja cap = 0xFFFF; 582*3592b7f6SOla Lilja break; 583*3592b7f6SOla Lilja default: 584*3592b7f6SOla Lilja dev_err(dai->dev, "%s: Error: Unsupported slot-count (%d)!\n", 585*3592b7f6SOla Lilja __func__, slots); 586*3592b7f6SOla Lilja return -EINVAL; 587*3592b7f6SOla Lilja } 588*3592b7f6SOla Lilja drvdata->slots = slots; 589*3592b7f6SOla Lilja 590*3592b7f6SOla Lilja if (!(slot_width == 16)) { 591*3592b7f6SOla Lilja dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n", 592*3592b7f6SOla Lilja __func__, slot_width); 593*3592b7f6SOla Lilja return -EINVAL; 594*3592b7f6SOla Lilja } 595*3592b7f6SOla Lilja drvdata->slot_width = slot_width; 596*3592b7f6SOla Lilja 597*3592b7f6SOla Lilja drvdata->tx_mask = tx_mask & cap; 598*3592b7f6SOla Lilja drvdata->rx_mask = rx_mask & cap; 599*3592b7f6SOla Lilja 600*3592b7f6SOla Lilja return 0; 601*3592b7f6SOla Lilja } 602*3592b7f6SOla Lilja 603*3592b7f6SOla Lilja static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai, 604*3592b7f6SOla Lilja int clk_id, unsigned int freq, int dir) 605*3592b7f6SOla Lilja { 606*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 607*3592b7f6SOla Lilja 608*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d: Enter. clk-id: %d, freq: %u.\n", 609*3592b7f6SOla Lilja __func__, dai->id, clk_id, freq); 610*3592b7f6SOla Lilja 611*3592b7f6SOla Lilja switch (clk_id) { 612*3592b7f6SOla Lilja case UX500_MSP_MASTER_CLOCK: 613*3592b7f6SOla Lilja drvdata->master_clk = freq; 614*3592b7f6SOla Lilja break; 615*3592b7f6SOla Lilja 616*3592b7f6SOla Lilja default: 617*3592b7f6SOla Lilja dev_err(dai->dev, "%s: MSP %d: Invalid clk-id (%d)!\n", 618*3592b7f6SOla Lilja __func__, dai->id, clk_id); 619*3592b7f6SOla Lilja return -EINVAL; 620*3592b7f6SOla Lilja } 621*3592b7f6SOla Lilja 622*3592b7f6SOla Lilja return 0; 623*3592b7f6SOla Lilja } 624*3592b7f6SOla Lilja 625*3592b7f6SOla Lilja static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream, 626*3592b7f6SOla Lilja int cmd, struct snd_soc_dai *dai) 627*3592b7f6SOla Lilja { 628*3592b7f6SOla Lilja int ret = 0; 629*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 630*3592b7f6SOla Lilja 631*3592b7f6SOla Lilja dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n", 632*3592b7f6SOla Lilja __func__, dai->id, snd_pcm_stream_str(substream), 633*3592b7f6SOla Lilja (int)drvdata->msp->id, cmd); 634*3592b7f6SOla Lilja 635*3592b7f6SOla Lilja ret = ux500_msp_i2s_trigger(drvdata->msp, cmd, substream->stream); 636*3592b7f6SOla Lilja 637*3592b7f6SOla Lilja return ret; 638*3592b7f6SOla Lilja } 639*3592b7f6SOla Lilja 640*3592b7f6SOla Lilja static int ux500_msp_dai_probe(struct snd_soc_dai *dai) 641*3592b7f6SOla Lilja { 642*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); 643*3592b7f6SOla Lilja 644*3592b7f6SOla Lilja drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx; 645*3592b7f6SOla Lilja drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx; 646*3592b7f6SOla Lilja 647*3592b7f6SOla Lilja dai->playback_dma_data = &drvdata->playback_dma_data; 648*3592b7f6SOla Lilja dai->capture_dma_data = &drvdata->capture_dma_data; 649*3592b7f6SOla Lilja 650*3592b7f6SOla Lilja drvdata->playback_dma_data.data_size = drvdata->slot_width; 651*3592b7f6SOla Lilja drvdata->capture_dma_data.data_size = drvdata->slot_width; 652*3592b7f6SOla Lilja 653*3592b7f6SOla Lilja return 0; 654*3592b7f6SOla Lilja } 655*3592b7f6SOla Lilja 656*3592b7f6SOla Lilja static struct snd_soc_dai_ops ux500_msp_dai_ops[] = { 657*3592b7f6SOla Lilja { 658*3592b7f6SOla Lilja .set_sysclk = ux500_msp_dai_set_dai_sysclk, 659*3592b7f6SOla Lilja .set_fmt = ux500_msp_dai_set_dai_fmt, 660*3592b7f6SOla Lilja .set_tdm_slot = ux500_msp_dai_set_tdm_slot, 661*3592b7f6SOla Lilja .startup = ux500_msp_dai_startup, 662*3592b7f6SOla Lilja .shutdown = ux500_msp_dai_shutdown, 663*3592b7f6SOla Lilja .prepare = ux500_msp_dai_prepare, 664*3592b7f6SOla Lilja .trigger = ux500_msp_dai_trigger, 665*3592b7f6SOla Lilja .hw_params = ux500_msp_dai_hw_params, 666*3592b7f6SOla Lilja } 667*3592b7f6SOla Lilja }; 668*3592b7f6SOla Lilja 669*3592b7f6SOla Lilja static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { 670*3592b7f6SOla Lilja { 671*3592b7f6SOla Lilja .name = "ux500-msp-i2s.0", 672*3592b7f6SOla Lilja .probe = ux500_msp_dai_probe, 673*3592b7f6SOla Lilja .id = 0, 674*3592b7f6SOla Lilja .suspend = NULL, 675*3592b7f6SOla Lilja .resume = NULL, 676*3592b7f6SOla Lilja .playback = { 677*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 678*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 679*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 680*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 681*3592b7f6SOla Lilja }, 682*3592b7f6SOla Lilja .capture = { 683*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 684*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 685*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 686*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 687*3592b7f6SOla Lilja }, 688*3592b7f6SOla Lilja .ops = ux500_msp_dai_ops, 689*3592b7f6SOla Lilja }, 690*3592b7f6SOla Lilja { 691*3592b7f6SOla Lilja .name = "ux500-msp-i2s.1", 692*3592b7f6SOla Lilja .probe = ux500_msp_dai_probe, 693*3592b7f6SOla Lilja .id = 1, 694*3592b7f6SOla Lilja .suspend = NULL, 695*3592b7f6SOla Lilja .resume = NULL, 696*3592b7f6SOla Lilja .playback = { 697*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 698*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 699*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 700*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 701*3592b7f6SOla Lilja }, 702*3592b7f6SOla Lilja .capture = { 703*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 704*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 705*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 706*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 707*3592b7f6SOla Lilja }, 708*3592b7f6SOla Lilja .ops = ux500_msp_dai_ops, 709*3592b7f6SOla Lilja }, 710*3592b7f6SOla Lilja { 711*3592b7f6SOla Lilja .name = "ux500-msp-i2s.2", 712*3592b7f6SOla Lilja .id = 2, 713*3592b7f6SOla Lilja .probe = ux500_msp_dai_probe, 714*3592b7f6SOla Lilja .suspend = NULL, 715*3592b7f6SOla Lilja .resume = NULL, 716*3592b7f6SOla Lilja .playback = { 717*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 718*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 719*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 720*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 721*3592b7f6SOla Lilja }, 722*3592b7f6SOla Lilja .capture = { 723*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 724*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 725*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 726*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 727*3592b7f6SOla Lilja }, 728*3592b7f6SOla Lilja .ops = ux500_msp_dai_ops, 729*3592b7f6SOla Lilja }, 730*3592b7f6SOla Lilja { 731*3592b7f6SOla Lilja .name = "ux500-msp-i2s.3", 732*3592b7f6SOla Lilja .probe = ux500_msp_dai_probe, 733*3592b7f6SOla Lilja .id = 3, 734*3592b7f6SOla Lilja .suspend = NULL, 735*3592b7f6SOla Lilja .resume = NULL, 736*3592b7f6SOla Lilja .playback = { 737*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 738*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 739*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 740*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 741*3592b7f6SOla Lilja }, 742*3592b7f6SOla Lilja .capture = { 743*3592b7f6SOla Lilja .channels_min = UX500_MSP_MIN_CHANNELS, 744*3592b7f6SOla Lilja .channels_max = UX500_MSP_MAX_CHANNELS, 745*3592b7f6SOla Lilja .rates = UX500_I2S_RATES, 746*3592b7f6SOla Lilja .formats = UX500_I2S_FORMATS, 747*3592b7f6SOla Lilja }, 748*3592b7f6SOla Lilja .ops = ux500_msp_dai_ops, 749*3592b7f6SOla Lilja }, 750*3592b7f6SOla Lilja }; 751*3592b7f6SOla Lilja 752*3592b7f6SOla Lilja static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) 753*3592b7f6SOla Lilja { 754*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata; 755*3592b7f6SOla Lilja int ret = 0; 756*3592b7f6SOla Lilja 757*3592b7f6SOla Lilja dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__, 758*3592b7f6SOla Lilja pdev->name); 759*3592b7f6SOla Lilja 760*3592b7f6SOla Lilja drvdata = devm_kzalloc(&pdev->dev, 761*3592b7f6SOla Lilja sizeof(struct ux500_msp_i2s_drvdata), 762*3592b7f6SOla Lilja GFP_KERNEL); 763*3592b7f6SOla Lilja drvdata->fmt = 0; 764*3592b7f6SOla Lilja drvdata->slots = 1; 765*3592b7f6SOla Lilja drvdata->tx_mask = 0x01; 766*3592b7f6SOla Lilja drvdata->rx_mask = 0x01; 767*3592b7f6SOla Lilja drvdata->slot_width = 16; 768*3592b7f6SOla Lilja drvdata->master_clk = MSP_INPUT_FREQ_APB; 769*3592b7f6SOla Lilja 770*3592b7f6SOla Lilja drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape"); 771*3592b7f6SOla Lilja if (IS_ERR(drvdata->reg_vape)) { 772*3592b7f6SOla Lilja ret = (int)PTR_ERR(drvdata->reg_vape); 773*3592b7f6SOla Lilja dev_err(&pdev->dev, 774*3592b7f6SOla Lilja "%s: ERROR: Failed to get Vape supply (%d)!\n", 775*3592b7f6SOla Lilja __func__, ret); 776*3592b7f6SOla Lilja return ret; 777*3592b7f6SOla Lilja } 778*3592b7f6SOla Lilja prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50); 779*3592b7f6SOla Lilja 780*3592b7f6SOla Lilja drvdata->clk = clk_get(&pdev->dev, NULL); 781*3592b7f6SOla Lilja if (IS_ERR(drvdata->clk)) { 782*3592b7f6SOla Lilja ret = (int)PTR_ERR(drvdata->clk); 783*3592b7f6SOla Lilja dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n", 784*3592b7f6SOla Lilja __func__, ret); 785*3592b7f6SOla Lilja goto err_clk; 786*3592b7f6SOla Lilja } 787*3592b7f6SOla Lilja 788*3592b7f6SOla Lilja ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp, 789*3592b7f6SOla Lilja pdev->dev.platform_data); 790*3592b7f6SOla Lilja if (!drvdata->msp) { 791*3592b7f6SOla Lilja dev_err(&pdev->dev, 792*3592b7f6SOla Lilja "%s: ERROR: Failed to init MSP-struct (%d)!", 793*3592b7f6SOla Lilja __func__, ret); 794*3592b7f6SOla Lilja goto err_init_msp; 795*3592b7f6SOla Lilja } 796*3592b7f6SOla Lilja dev_set_drvdata(&pdev->dev, drvdata); 797*3592b7f6SOla Lilja 798*3592b7f6SOla Lilja ret = snd_soc_register_dai(&pdev->dev, 799*3592b7f6SOla Lilja &ux500_msp_dai_drv[drvdata->msp->id]); 800*3592b7f6SOla Lilja if (ret < 0) { 801*3592b7f6SOla Lilja dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n", 802*3592b7f6SOla Lilja __func__, drvdata->msp->id); 803*3592b7f6SOla Lilja goto err_init_msp; 804*3592b7f6SOla Lilja } 805*3592b7f6SOla Lilja 806*3592b7f6SOla Lilja return 0; 807*3592b7f6SOla Lilja 808*3592b7f6SOla Lilja err_init_msp: 809*3592b7f6SOla Lilja clk_put(drvdata->clk); 810*3592b7f6SOla Lilja 811*3592b7f6SOla Lilja err_clk: 812*3592b7f6SOla Lilja devm_regulator_put(drvdata->reg_vape); 813*3592b7f6SOla Lilja 814*3592b7f6SOla Lilja return ret; 815*3592b7f6SOla Lilja } 816*3592b7f6SOla Lilja 817*3592b7f6SOla Lilja static int __devexit ux500_msp_drv_remove(struct platform_device *pdev) 818*3592b7f6SOla Lilja { 819*3592b7f6SOla Lilja struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev); 820*3592b7f6SOla Lilja 821*3592b7f6SOla Lilja snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); 822*3592b7f6SOla Lilja 823*3592b7f6SOla Lilja devm_regulator_put(drvdata->reg_vape); 824*3592b7f6SOla Lilja prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); 825*3592b7f6SOla Lilja 826*3592b7f6SOla Lilja clk_put(drvdata->clk); 827*3592b7f6SOla Lilja 828*3592b7f6SOla Lilja ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp); 829*3592b7f6SOla Lilja 830*3592b7f6SOla Lilja return 0; 831*3592b7f6SOla Lilja } 832*3592b7f6SOla Lilja 833*3592b7f6SOla Lilja static struct platform_driver msp_i2s_driver = { 834*3592b7f6SOla Lilja .driver = { 835*3592b7f6SOla Lilja .name = "ux500-msp-i2s", 836*3592b7f6SOla Lilja .owner = THIS_MODULE, 837*3592b7f6SOla Lilja }, 838*3592b7f6SOla Lilja .probe = ux500_msp_drv_probe, 839*3592b7f6SOla Lilja .remove = ux500_msp_drv_remove, 840*3592b7f6SOla Lilja }; 841*3592b7f6SOla Lilja module_platform_driver(msp_i2s_driver); 842*3592b7f6SOla Lilja 843*3592b7f6SOla Lilja MODULE_LICENSE("GPLv2"); 844