668 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) ST-Ericsson SA 20124 *5 * Author: Ola Lilja <ola.o.lilja@stericsson.com>,6 * Roger Nilsson <roger.xr.nilsson@stericsson.com>,7 * Sandeep Kaushik <sandeep.kaushik@st.com>8 * for ST-Ericsson.9 */10 11#include <linux/module.h>12#include <linux/platform_device.h>13#include <linux/delay.h>14#include <linux/slab.h>15#include <linux/io.h>16#include <linux/of.h>17 18#include <sound/soc.h>19 20#include "ux500_msp_i2s.h"21 22 /* Protocol desciptors */23static const struct msp_protdesc prot_descs[] = {24 { /* I2S */25 MSP_SINGLE_PHASE,26 MSP_SINGLE_PHASE,27 MSP_PHASE2_START_MODE_IMEDIATE,28 MSP_PHASE2_START_MODE_IMEDIATE,29 MSP_BTF_MS_BIT_FIRST,30 MSP_BTF_MS_BIT_FIRST,31 MSP_FRAME_LEN_1,32 MSP_FRAME_LEN_1,33 MSP_FRAME_LEN_1,34 MSP_FRAME_LEN_1,35 MSP_ELEM_LEN_32,36 MSP_ELEM_LEN_32,37 MSP_ELEM_LEN_32,38 MSP_ELEM_LEN_32,39 MSP_DELAY_1,40 MSP_DELAY_1,41 MSP_RISING_EDGE,42 MSP_FALLING_EDGE,43 MSP_FSYNC_POL_ACT_LO,44 MSP_FSYNC_POL_ACT_LO,45 MSP_SWAP_NONE,46 MSP_SWAP_NONE,47 MSP_COMPRESS_MODE_LINEAR,48 MSP_EXPAND_MODE_LINEAR,49 MSP_FSYNC_IGNORE,50 31,51 15,52 32,53 }, { /* PCM */54 MSP_DUAL_PHASE,55 MSP_DUAL_PHASE,56 MSP_PHASE2_START_MODE_FSYNC,57 MSP_PHASE2_START_MODE_FSYNC,58 MSP_BTF_MS_BIT_FIRST,59 MSP_BTF_MS_BIT_FIRST,60 MSP_FRAME_LEN_1,61 MSP_FRAME_LEN_1,62 MSP_FRAME_LEN_1,63 MSP_FRAME_LEN_1,64 MSP_ELEM_LEN_16,65 MSP_ELEM_LEN_16,66 MSP_ELEM_LEN_16,67 MSP_ELEM_LEN_16,68 MSP_DELAY_0,69 MSP_DELAY_0,70 MSP_RISING_EDGE,71 MSP_FALLING_EDGE,72 MSP_FSYNC_POL_ACT_HI,73 MSP_FSYNC_POL_ACT_HI,74 MSP_SWAP_NONE,75 MSP_SWAP_NONE,76 MSP_COMPRESS_MODE_LINEAR,77 MSP_EXPAND_MODE_LINEAR,78 MSP_FSYNC_IGNORE,79 255,80 0,81 256,82 }, { /* Companded PCM */83 MSP_SINGLE_PHASE,84 MSP_SINGLE_PHASE,85 MSP_PHASE2_START_MODE_FSYNC,86 MSP_PHASE2_START_MODE_FSYNC,87 MSP_BTF_MS_BIT_FIRST,88 MSP_BTF_MS_BIT_FIRST,89 MSP_FRAME_LEN_1,90 MSP_FRAME_LEN_1,91 MSP_FRAME_LEN_1,92 MSP_FRAME_LEN_1,93 MSP_ELEM_LEN_8,94 MSP_ELEM_LEN_8,95 MSP_ELEM_LEN_8,96 MSP_ELEM_LEN_8,97 MSP_DELAY_0,98 MSP_DELAY_0,99 MSP_RISING_EDGE,100 MSP_RISING_EDGE,101 MSP_FSYNC_POL_ACT_HI,102 MSP_FSYNC_POL_ACT_HI,103 MSP_SWAP_NONE,104 MSP_SWAP_NONE,105 MSP_COMPRESS_MODE_LINEAR,106 MSP_EXPAND_MODE_LINEAR,107 MSP_FSYNC_IGNORE,108 255,109 0,110 256,111 },112};113 114static void set_prot_desc_tx(struct ux500_msp *msp,115 struct msp_protdesc *protdesc,116 enum msp_data_size data_size)117{118 u32 temp_reg = 0;119 120 temp_reg |= MSP_P2_ENABLE_BIT(protdesc->tx_phase_mode);121 temp_reg |= MSP_P2_START_MODE_BIT(protdesc->tx_phase2_start_mode);122 temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->tx_frame_len_1);123 temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->tx_frame_len_2);124 if (msp->def_elem_len) {125 temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->tx_elem_len_1);126 temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->tx_elem_len_2);127 } else {128 temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);129 temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);130 }131 temp_reg |= MSP_DATA_DELAY_BITS(protdesc->tx_data_delay);132 temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->tx_byte_order);133 temp_reg |= MSP_FSYNC_POL(protdesc->tx_fsync_pol);134 temp_reg |= MSP_DATA_WORD_SWAP(protdesc->tx_half_word_swap);135 temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->compression_mode);136 temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);137 138 writel(temp_reg, msp->registers + MSP_TCF);139}140 141static void set_prot_desc_rx(struct ux500_msp *msp,142 struct msp_protdesc *protdesc,143 enum msp_data_size data_size)144{145 u32 temp_reg = 0;146 147 temp_reg |= MSP_P2_ENABLE_BIT(protdesc->rx_phase_mode);148 temp_reg |= MSP_P2_START_MODE_BIT(protdesc->rx_phase2_start_mode);149 temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->rx_frame_len_1);150 temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->rx_frame_len_2);151 if (msp->def_elem_len) {152 temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->rx_elem_len_1);153 temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->rx_elem_len_2);154 } else {155 temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);156 temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);157 }158 159 temp_reg |= MSP_DATA_DELAY_BITS(protdesc->rx_data_delay);160 temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->rx_byte_order);161 temp_reg |= MSP_FSYNC_POL(protdesc->rx_fsync_pol);162 temp_reg |= MSP_DATA_WORD_SWAP(protdesc->rx_half_word_swap);163 temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->expansion_mode);164 temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);165 166 writel(temp_reg, msp->registers + MSP_RCF);167}168 169static int configure_protocol(struct ux500_msp *msp,170 struct ux500_msp_config *config)171{172 struct msp_protdesc *protdesc;173 enum msp_data_size data_size;174 u32 temp_reg = 0;175 176 data_size = config->data_size;177 msp->def_elem_len = config->def_elem_len;178 if (config->default_protdesc == 1) {179 if (config->protocol >= MSP_INVALID_PROTOCOL) {180 dev_err(msp->dev, "%s: ERROR: Invalid protocol!\n",181 __func__);182 return -EINVAL;183 }184 protdesc =185 (struct msp_protdesc *)&prot_descs[config->protocol];186 } else {187 protdesc = (struct msp_protdesc *)&config->protdesc;188 }189 190 if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) {191 dev_err(msp->dev,192 "%s: ERROR: Invalid data-size requested (data_size = %d)!\n",193 __func__, data_size);194 return -EINVAL;195 }196 197 if (config->direction & MSP_DIR_TX)198 set_prot_desc_tx(msp, protdesc, data_size);199 if (config->direction & MSP_DIR_RX)200 set_prot_desc_rx(msp, protdesc, data_size);201 202 /* The code below should not be separated. */203 temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;204 temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);205 writel(temp_reg, msp->registers + MSP_GCR);206 temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;207 temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);208 writel(temp_reg, msp->registers + MSP_GCR);209 210 return 0;211}212 213static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)214{215 u32 reg_val_GCR;216 u32 frame_per = 0;217 u32 sck_div = 0;218 u32 frame_width = 0;219 u32 temp_reg = 0;220 struct msp_protdesc *protdesc = NULL;221 222 reg_val_GCR = readl(msp->registers + MSP_GCR);223 writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);224 225 if (config->default_protdesc)226 protdesc =227 (struct msp_protdesc *)&prot_descs[config->protocol];228 else229 protdesc = (struct msp_protdesc *)&config->protdesc;230 231 switch (config->protocol) {232 case MSP_PCM_PROTOCOL:233 case MSP_PCM_COMPAND_PROTOCOL:234 frame_width = protdesc->frame_width;235 sck_div = config->f_inputclk / (config->frame_freq *236 (protdesc->clocks_per_frame));237 frame_per = protdesc->frame_period;238 break;239 case MSP_I2S_PROTOCOL:240 frame_width = protdesc->frame_width;241 sck_div = config->f_inputclk / (config->frame_freq *242 (protdesc->clocks_per_frame));243 frame_per = protdesc->frame_period;244 break;245 default:246 dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",247 __func__,248 config->protocol);249 return -EINVAL;250 }251 252 temp_reg = (sck_div - 1) & SCK_DIV_MASK;253 temp_reg |= FRAME_WIDTH_BITS(frame_width);254 temp_reg |= FRAME_PERIOD_BITS(frame_per);255 writel(temp_reg, msp->registers + MSP_SRG);256 257 msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);258 259 /* Enable bit-clock */260 udelay(100);261 reg_val_GCR = readl(msp->registers + MSP_GCR);262 writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR);263 udelay(100);264 265 return 0;266}267 268static int configure_multichannel(struct ux500_msp *msp,269 struct ux500_msp_config *config)270{271 struct msp_protdesc *protdesc;272 struct msp_multichannel_config *mcfg;273 u32 reg_val_MCR;274 275 if (config->default_protdesc == 1) {276 if (config->protocol >= MSP_INVALID_PROTOCOL) {277 dev_err(msp->dev,278 "%s: ERROR: Invalid protocol (%d)!\n",279 __func__, config->protocol);280 return -EINVAL;281 }282 protdesc = (struct msp_protdesc *)283 &prot_descs[config->protocol];284 } else {285 protdesc = (struct msp_protdesc *)&config->protdesc;286 }287 288 mcfg = &config->multichannel_config;289 if (mcfg->tx_multichannel_enable) {290 if (protdesc->tx_phase_mode == MSP_SINGLE_PHASE) {291 reg_val_MCR = readl(msp->registers + MSP_MCR);292 writel(reg_val_MCR | (mcfg->tx_multichannel_enable ?293 1 << TMCEN_BIT : 0),294 msp->registers + MSP_MCR);295 writel(mcfg->tx_channel_0_enable,296 msp->registers + MSP_TCE0);297 writel(mcfg->tx_channel_1_enable,298 msp->registers + MSP_TCE1);299 writel(mcfg->tx_channel_2_enable,300 msp->registers + MSP_TCE2);301 writel(mcfg->tx_channel_3_enable,302 msp->registers + MSP_TCE3);303 } else {304 dev_err(msp->dev,305 "%s: ERROR: Only single-phase supported (TX-mode: %d)!\n",306 __func__, protdesc->tx_phase_mode);307 return -EINVAL;308 }309 }310 if (mcfg->rx_multichannel_enable) {311 if (protdesc->rx_phase_mode == MSP_SINGLE_PHASE) {312 reg_val_MCR = readl(msp->registers + MSP_MCR);313 writel(reg_val_MCR | (mcfg->rx_multichannel_enable ?314 1 << RMCEN_BIT : 0),315 msp->registers + MSP_MCR);316 writel(mcfg->rx_channel_0_enable,317 msp->registers + MSP_RCE0);318 writel(mcfg->rx_channel_1_enable,319 msp->registers + MSP_RCE1);320 writel(mcfg->rx_channel_2_enable,321 msp->registers + MSP_RCE2);322 writel(mcfg->rx_channel_3_enable,323 msp->registers + MSP_RCE3);324 } else {325 dev_err(msp->dev,326 "%s: ERROR: Only single-phase supported (RX-mode: %d)!\n",327 __func__, protdesc->rx_phase_mode);328 return -EINVAL;329 }330 if (mcfg->rx_comparison_enable_mode) {331 reg_val_MCR = readl(msp->registers + MSP_MCR);332 writel(reg_val_MCR |333 (mcfg->rx_comparison_enable_mode << RCMPM_BIT),334 msp->registers + MSP_MCR);335 336 writel(mcfg->comparison_mask,337 msp->registers + MSP_RCM);338 writel(mcfg->comparison_value,339 msp->registers + MSP_RCV);340 341 }342 }343 344 return 0;345}346 347static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)348{349 int status = 0;350 u32 reg_val_DMACR, reg_val_GCR;351 352 /* Configure msp with protocol dependent settings */353 configure_protocol(msp, config);354 setup_bitclk(msp, config);355 if (config->multichannel_configured == 1) {356 status = configure_multichannel(msp, config);357 if (status)358 dev_warn(msp->dev,359 "%s: WARN: configure_multichannel failed (%d)!\n",360 __func__, status);361 }362 363 reg_val_DMACR = readl(msp->registers + MSP_DMACR);364 if (config->direction & MSP_DIR_RX)365 reg_val_DMACR |= RX_DMA_ENABLE;366 if (config->direction & MSP_DIR_TX)367 reg_val_DMACR |= TX_DMA_ENABLE;368 writel(reg_val_DMACR, msp->registers + MSP_DMACR);369 370 writel(config->iodelay, msp->registers + MSP_IODLY);371 372 /* Enable frame generation logic */373 reg_val_GCR = readl(msp->registers + MSP_GCR);374 writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);375 376 return status;377}378 379static void flush_fifo_rx(struct ux500_msp *msp)380{381 u32 reg_val_GCR, reg_val_FLR;382 u32 limit = 32;383 384 reg_val_GCR = readl(msp->registers + MSP_GCR);385 writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR);386 387 reg_val_FLR = readl(msp->registers + MSP_FLR);388 while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) {389 readl(msp->registers + MSP_DR);390 reg_val_FLR = readl(msp->registers + MSP_FLR);391 }392 393 writel(reg_val_GCR, msp->registers + MSP_GCR);394}395 396static void flush_fifo_tx(struct ux500_msp *msp)397{398 u32 reg_val_GCR, reg_val_FLR;399 u32 limit = 32;400 401 reg_val_GCR = readl(msp->registers + MSP_GCR);402 writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR);403 writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR);404 405 reg_val_FLR = readl(msp->registers + MSP_FLR);406 while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) {407 readl(msp->registers + MSP_TSTDR);408 reg_val_FLR = readl(msp->registers + MSP_FLR);409 }410 writel(0x0, msp->registers + MSP_ITCR);411 writel(reg_val_GCR, msp->registers + MSP_GCR);412}413 414int ux500_msp_i2s_open(struct ux500_msp *msp,415 struct ux500_msp_config *config)416{417 u32 old_reg, new_reg, mask;418 int res;419 unsigned int tx_sel, rx_sel, tx_busy, rx_busy;420 421 if (in_interrupt()) {422 dev_err(msp->dev,423 "%s: ERROR: Open called in interrupt context!\n",424 __func__);425 return -1;426 }427 428 tx_sel = (config->direction & MSP_DIR_TX) > 0;429 rx_sel = (config->direction & MSP_DIR_RX) > 0;430 if (!tx_sel && !rx_sel) {431 dev_err(msp->dev, "%s: Error: No direction selected!\n",432 __func__);433 return -EINVAL;434 }435 436 tx_busy = (msp->dir_busy & MSP_DIR_TX) > 0;437 rx_busy = (msp->dir_busy & MSP_DIR_RX) > 0;438 if (tx_busy && tx_sel) {439 dev_err(msp->dev, "%s: Error: TX is in use!\n", __func__);440 return -EBUSY;441 }442 if (rx_busy && rx_sel) {443 dev_err(msp->dev, "%s: Error: RX is in use!\n", __func__);444 return -EBUSY;445 }446 447 msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);448 449 /* First do the global config register */450 mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |451 TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |452 RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |453 LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;454 455 new_reg = (config->tx_clk_sel | config->rx_clk_sel |456 config->rx_fsync_pol | config->tx_fsync_pol |457 config->rx_fsync_sel | config->tx_fsync_sel |458 config->rx_fifo_config | config->tx_fifo_config |459 config->srg_clk_sel | config->loopback_enable |460 config->tx_data_enable);461 462 old_reg = readl(msp->registers + MSP_GCR);463 old_reg &= ~mask;464 new_reg |= old_reg;465 writel(new_reg, msp->registers + MSP_GCR);466 467 res = enable_msp(msp, config);468 if (res < 0) {469 dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",470 __func__, res);471 return -EBUSY;472 }473 if (config->loopback_enable & 0x80)474 msp->loopback_enable = 1;475 476 /* Flush FIFOs */477 flush_fifo_tx(msp);478 flush_fifo_rx(msp);479 480 msp->msp_state = MSP_STATE_CONFIGURED;481 return 0;482}483 484static void disable_msp_rx(struct ux500_msp *msp)485{486 u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;487 488 reg_val_GCR = readl(msp->registers + MSP_GCR);489 writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR);490 reg_val_DMACR = readl(msp->registers + MSP_DMACR);491 writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR);492 reg_val_IMSC = readl(msp->registers + MSP_IMSC);493 writel(reg_val_IMSC &494 ~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),495 msp->registers + MSP_IMSC);496 497 msp->dir_busy &= ~MSP_DIR_RX;498}499 500static void disable_msp_tx(struct ux500_msp *msp)501{502 u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;503 504 reg_val_GCR = readl(msp->registers + MSP_GCR);505 writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR);506 reg_val_DMACR = readl(msp->registers + MSP_DMACR);507 writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR);508 reg_val_IMSC = readl(msp->registers + MSP_IMSC);509 writel(reg_val_IMSC &510 ~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),511 msp->registers + MSP_IMSC);512 513 msp->dir_busy &= ~MSP_DIR_TX;514}515 516static int disable_msp(struct ux500_msp *msp, unsigned int dir)517{518 u32 reg_val_GCR;519 unsigned int disable_tx, disable_rx;520 521 reg_val_GCR = readl(msp->registers + MSP_GCR);522 disable_tx = dir & MSP_DIR_TX;523 disable_rx = dir & MSP_DIR_TX;524 if (disable_tx && disable_rx) {525 reg_val_GCR = readl(msp->registers + MSP_GCR);526 writel(reg_val_GCR | LOOPBACK_MASK,527 msp->registers + MSP_GCR);528 529 /* Flush TX-FIFO */530 flush_fifo_tx(msp);531 532 /* Disable TX-channel */533 writel((readl(msp->registers + MSP_GCR) &534 (~TX_ENABLE)), msp->registers + MSP_GCR);535 536 /* Flush RX-FIFO */537 flush_fifo_rx(msp);538 539 /* Disable Loopback and Receive channel */540 writel((readl(msp->registers + MSP_GCR) &541 (~(RX_ENABLE | LOOPBACK_MASK))),542 msp->registers + MSP_GCR);543 544 disable_msp_tx(msp);545 disable_msp_rx(msp);546 } else if (disable_tx)547 disable_msp_tx(msp);548 else if (disable_rx)549 disable_msp_rx(msp);550 551 return 0;552}553 554int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)555{556 u32 reg_val_GCR, enable_bit;557 558 if (msp->msp_state == MSP_STATE_IDLE) {559 dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",560 __func__);561 return -EINVAL;562 }563 564 switch (cmd) {565 case SNDRV_PCM_TRIGGER_START:566 case SNDRV_PCM_TRIGGER_RESUME:567 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:568 if (direction == SNDRV_PCM_STREAM_PLAYBACK)569 enable_bit = TX_ENABLE;570 else571 enable_bit = RX_ENABLE;572 reg_val_GCR = readl(msp->registers + MSP_GCR);573 writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);574 break;575 576 case SNDRV_PCM_TRIGGER_STOP:577 case SNDRV_PCM_TRIGGER_SUSPEND:578 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:579 if (direction == SNDRV_PCM_STREAM_PLAYBACK)580 disable_msp_tx(msp);581 else582 disable_msp_rx(msp);583 break;584 default:585 return -EINVAL;586 }587 588 return 0;589}590 591int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)592{593 int status = 0;594 595 dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);596 597 status = disable_msp(msp, dir);598 if (msp->dir_busy == 0) {599 /* disable sample rate and frame generators */600 msp->msp_state = MSP_STATE_IDLE;601 writel((readl(msp->registers + MSP_GCR) &602 (~(FRAME_GEN_ENABLE | SRG_ENABLE))),603 msp->registers + MSP_GCR);604 605 writel(0, msp->registers + MSP_GCR);606 writel(0, msp->registers + MSP_TCF);607 writel(0, msp->registers + MSP_RCF);608 writel(0, msp->registers + MSP_DMACR);609 writel(0, msp->registers + MSP_SRG);610 writel(0, msp->registers + MSP_MCR);611 writel(0, msp->registers + MSP_RCM);612 writel(0, msp->registers + MSP_RCV);613 writel(0, msp->registers + MSP_TCE0);614 writel(0, msp->registers + MSP_TCE1);615 writel(0, msp->registers + MSP_TCE2);616 writel(0, msp->registers + MSP_TCE3);617 writel(0, msp->registers + MSP_RCE0);618 writel(0, msp->registers + MSP_RCE1);619 writel(0, msp->registers + MSP_RCE2);620 writel(0, msp->registers + MSP_RCE3);621 }622 623 return status;624 625}626 627int ux500_msp_i2s_init_msp(struct platform_device *pdev,628 struct ux500_msp **msp_p)629{630 struct resource *res = NULL;631 struct ux500_msp *msp;632 633 *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);634 msp = *msp_p;635 if (!msp)636 return -ENOMEM;637 638 msp->dev = &pdev->dev;639 640 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);641 if (res == NULL) {642 dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",643 __func__);644 return -ENOMEM;645 }646 647 msp->tx_rx_addr = res->start + MSP_DR;648 msp->registers = devm_ioremap(&pdev->dev, res->start,649 resource_size(res));650 if (msp->registers == NULL) {651 dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);652 return -ENOMEM;653 }654 655 msp->msp_state = MSP_STATE_IDLE;656 msp->loopback_enable = 0;657 658 return 0;659}660 661void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,662 struct ux500_msp *msp)663{664 dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);665}666 667MODULE_LICENSE("GPL v2");668