/* * Copyright (C) ST-Ericsson SA 2010 * * License terms: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct regulator *msp_vape_supply; #define STM_MSP_NAME "STM_MSP" #define MSP_NAME "msp" #define DRIVER_DEBUG_PFX "MSP" #define DRIVER_DEBUG CONFIG_STM_MSP_DEBUG #define DRIVER_DBG "MSP" #define NMDK_DBG /* message level */ extern struct driver_debug_st DBG_ST; /* Protocol desciptors */ static const struct msp_protocol_desc protocol_desc_tab[] = { I2S_PROTOCOL_DESC, PCM_PROTOCOL_DESC, PCM_COMPAND_PROTOCOL_DESC, AC97_PROTOCOL_DESC, SPI_MASTER_PROTOCOL_DESC, SPI_SLAVE_PROTOCOL_DESC, }; /* Local static functions */ static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg); static int msp_polling_xfer(struct msp *msp, struct i2s_message *msg); static int msp_interrupt_xfer(struct msp *msp, struct i2s_message *msg); static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data, size_t bytes); static int configure_protocol(struct msp *msp, struct msp_config *config); static int configure_clock(struct msp *msp, struct msp_config *config); static int configure_multichannel(struct msp *msp, struct msp_config *config); static int stm_msp_configure_enable(struct i2s_controller *i2s_cont, void *configuration); static int stm_msp_transceive_data(struct i2s_controller *i2s_cont, struct i2s_message *message); static int stm_msp_disable(struct msp *msp, int direction, i2s_flag flag); static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag); static int stm_msp_hw_status(struct i2s_controller *i2s_cont); #define I2S_DEVICE "i2s_device" static struct i2s_algorithm i2s_algo = { .cont_setup = stm_msp_configure_enable, .cont_transfer = stm_msp_transceive_data, .cont_cleanup = stm_msp_close, .cont_hw_status = stm_msp_hw_status, }; /** * stm_msp_write - writel a value to specified register * @value: value * @reg: pointer to register' address * Context: atomic(can be both process and interrupt) * Returns void. */ static inline void stm_msp_write(u32 value, void __iomem *reg) { writel(value, reg); } /** * stm_msp_read - readl a value to specified register * @reg: pointer to register' address * Context: atomic(can be both process and interrupt) * Returns u32 register's value. */ static inline u32 stm_msp_read(void __iomem *reg) { return readl(reg); } static void u8_msp_read(struct trans_data *xfer_data) { struct i2s_message *message = &xfer_data->message; while ((message->rx_offset < message->rxbytes) && !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) & RX_FIFO_EMPTY)) { message->rx_offset += 1; *(u8 *) message->rxdata = (u8) stm_msp_read(xfer_data->msp->registers + MSP_DR); message->rxdata += 1; } } static void u16_msp_read(struct trans_data *xfer_data) { struct i2s_message *message = &xfer_data->message; while ((message->rx_offset < message->rxbytes) && !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) & RX_FIFO_EMPTY)) { message->rx_offset += 2; *(u16 *) message->rxdata = (u16) stm_msp_read(xfer_data->msp->registers + MSP_DR); message->rxdata += 2; } } /** * u32_msp_read - Msp 32bit read function. * @xfer_data: transfer data structure. * * It reads 32bit data from msp receive fifo until it gets empty. * * Returns void. */ static void u32_msp_read(struct trans_data *xfer_data) { struct i2s_message *message = &xfer_data->message; while ((message->rx_offset < message->rxbytes) && !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) & RX_FIFO_EMPTY)) { *(u32 *) message->rxdata = (u32) stm_msp_read(xfer_data->msp->registers + MSP_DR); message->rx_offset += 4; message->rxdata += 4; } } static void u8_msp_write(struct trans_data *xfer_data) { struct i2s_message *message = &xfer_data->message; while ((message->tx_offset < message->txbytes) && !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) & TX_FIFO_FULL)) { message->tx_offset += 1; stm_msp_write(*(u8 *) message->txdata, xfer_data->msp->registers + MSP_DR); message->txdata += 1; } } static void u16_msp_write(struct trans_data *xfer_data) { struct i2s_message *message = &xfer_data->message; while ((message->tx_offset < message->txbytes) && !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) & TX_FIFO_FULL)) { message->tx_offset += 2; stm_msp_write(*(u16 *) message->txdata, xfer_data->msp->registers + MSP_DR); message->txdata += 2; } } /** * u32_msp_write - Msp 32bit write function. * @xfer_data: transfer data structure. * * It writes 32bit data to msp transmit fifo until it gets full. * * Returns void. */ static void u32_msp_write(struct trans_data *xfer_data) { struct i2s_message *message = &xfer_data->message; while ((message->tx_offset < message->txbytes) && !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) & TX_FIFO_FULL)) { message->tx_offset += 4; stm_msp_write(*(u32 *) message->txdata, xfer_data->msp->registers + MSP_DR); message->txdata += 4; } } /** * set_transmit_protocol_descriptor - Set the Transmit Configuration register. * @msp: main msp controller structure. * @protocol_desc: pointer to protocol descriptor structure. * @data_size: Run time configurable element length. * * It will setup transmit configuration register of msp. * Various values related to a particular protocol can be set like, elemnet * length, frame length, endianess etc. * * Returns void. */ static void set_transmit_protocol_descriptor(struct msp *msp, struct msp_protocol_desc *protocol_desc, enum msp_data_size data_size) { u32 temp_reg = 0; temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->tx_phase_mode); temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->tx_phase2_start_mode); temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->tx_frame_length_1); temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->tx_frame_length_2); if (msp->def_elem_len) { temp_reg |= MSP_P1_ELEM_LEN_BITS(protocol_desc->tx_element_length_1); temp_reg |= MSP_P2_ELEM_LEN_BITS(protocol_desc->tx_element_length_2); if (protocol_desc->tx_element_length_1 == protocol_desc->tx_element_length_2) { msp->actual_data_size = protocol_desc->tx_element_length_1; } else { msp->actual_data_size = data_size; } } else { temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size); temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size); msp->actual_data_size = data_size; } temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->tx_data_delay); temp_reg |= MSP_SET_ENDIANNES_BIT(protocol_desc->tx_bit_transfer_format); temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->tx_frame_sync_pol); temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->tx_half_word_swap); temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->compression_mode); temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore); stm_msp_write(temp_reg, msp->registers + MSP_TCF); } /** * set_receive_protocol_descriptor - Set the Receive Configuration register. * @msp: main msp controller structure. * @protocol_desc: pointer to protocol descriptor structure. * @data_size: Run time configurable element length. * * It will setup receive configuration register of msp. * Various values related to a particular protocol can be set like, elemnet * length, frame length, endianess etc. * * Returns void. */ static void set_receive_protocol_descriptor(struct msp *msp, struct msp_protocol_desc *protocol_desc, enum msp_data_size data_size) { u32 temp_reg = 0; temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->rx_phase_mode); temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->rx_phase2_start_mode); temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->rx_frame_length_1); temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->rx_frame_length_2); if (msp->def_elem_len) { temp_reg |= MSP_P1_ELEM_LEN_BITS(protocol_desc->rx_element_length_1); temp_reg |= MSP_P2_ELEM_LEN_BITS(protocol_desc->rx_element_length_2); if (protocol_desc->rx_element_length_1 == protocol_desc->rx_element_length_2) { msp->actual_data_size = protocol_desc->rx_element_length_1; } else { msp->actual_data_size = data_size; } } else { temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size); temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size); msp->actual_data_size = data_size; } temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->rx_data_delay); temp_reg |= MSP_SET_ENDIANNES_BIT(protocol_desc->rx_bit_transfer_format); temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->rx_frame_sync_pol); temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->rx_half_word_swap); temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->expansion_mode); temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore); stm_msp_write(temp_reg, msp->registers + MSP_RCF); } /** * configure_protocol - Configures transmit and receive protocol. * @msp: main msp controller structure. * @config: configuration structure passed by client driver * * This will configure transmit and receive protocol decriptors. * * Returns error(-1) on failure else success(0). */ static int configure_protocol(struct msp *msp, struct msp_config *config) { int direction; struct msp_protocol_desc *protocol_desc; enum msp_data_size data_size; u32 temp_reg = 0; data_size = config->data_size; msp->def_elem_len = config->def_elem_len; direction = config->direction; if (config->default_protocol_desc == 1) { if (config->protocol >= MSP_INVALID_PROTOCOL) { printk(KERN_ERR "invalid protocol in configure_protocol()\n"); return -EINVAL; } protocol_desc = (struct msp_protocol_desc *)&protocol_desc_tab[config-> protocol]; } else { protocol_desc = (struct msp_protocol_desc *)&config->protocol_desc; } if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) { printk(KERN_ERR "invalid data size requested in configure_protocol()\n"); return -EINVAL; } switch (direction) { case MSP_TRANSMIT_MODE: set_transmit_protocol_descriptor(msp, protocol_desc, data_size); break; case MSP_RECEIVE_MODE: set_receive_protocol_descriptor(msp, protocol_desc, data_size); break; case MSP_BOTH_T_R_MODE: set_transmit_protocol_descriptor(msp, protocol_desc, data_size); set_receive_protocol_descriptor(msp, protocol_desc, data_size); break; default: printk(KERN_ERR "Invalid direction given\n"); return -EINVAL; } /* The below code is needed for both Rx and Tx path can't separate * them. */ temp_reg = stm_msp_read(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING; temp_reg |= MSP_TX_CLKPOL_BIT(protocol_desc->tx_clock_pol); stm_msp_write(temp_reg, msp->registers + MSP_GCR); temp_reg = stm_msp_read(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING; temp_reg |= MSP_RX_CLKPOL_BIT(protocol_desc->rx_clock_pol); stm_msp_write(temp_reg, msp->registers + MSP_GCR); return 0; } /** * configure_clock - Set clock in sample rate generator. * @msp: main msp controller structure. * @config: configuration structure passed by client driver * * This will set the frame width and period. Also enable sample rate generator * * Returns error(-1) on failure else success(0). */ static int configure_clock(struct msp *msp, struct msp_config *config) { u32 dummy; u32 frame_per = 0; u32 sck_div = 0; u32 frame_width = 0; u32 temp_reg = 0; u32 bit_clock = 0; struct msp_protocol_desc *protocol_desc = NULL; stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) & (~(SRG_ENABLE))), msp->registers + MSP_GCR); if (config->default_protocol_desc) { protocol_desc = (struct msp_protocol_desc *)&protocol_desc_tab[config-> protocol]; } else { protocol_desc = (struct msp_protocol_desc *)&config->protocol_desc; } switch (config->protocol) { case MSP_PCM_PROTOCOL: case MSP_PCM_COMPAND_PROTOCOL: frame_width = protocol_desc->frame_width; sck_div = config->input_clock_freq / (config->frame_freq * (protocol_desc-> total_clocks_for_one_frame)); frame_per = protocol_desc->frame_period; break; case MSP_I2S_PROTOCOL: frame_width = protocol_desc->frame_width; sck_div = config->input_clock_freq / (config->frame_freq * (protocol_desc-> total_clocks_for_one_frame)); frame_per = protocol_desc->frame_period; break; case MSP_AC97_PROTOCOL: /* Not supported */ printk(KERN_WARNING "AC97 protocol not supported\n"); return -ENOSYS; default: printk(KERN_ERR "Invalid mode attempted for setting clocks\n"); return -EINVAL; } temp_reg = (sck_div - 1) & SCK_DIV_MASK; temp_reg |= FRAME_WIDTH_BITS(frame_width); temp_reg |= FRAME_PERIOD_BITS(frame_per); stm_msp_write(temp_reg, msp->registers + MSP_SRG); /* Input clock frequency value configured is in MHz/1000 */ bit_clock = (config->input_clock_freq * 1000)/(sck_div + 1); /* If the bit clock is higher than 19.2MHz, Vape should be run in 100% OPP */ /* Only consider OPP 100% when bit-clock is used, i.e. MSP master mode */ if ((bit_clock > 19200000) && ((config->tx_clock_sel != 0) || (config->rx_clock_sel != 0))) { prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 100); msp->vape_opp_constraint = 1; } else { prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 50); msp->vape_opp_constraint = 0; } /* Wait a bit */ dummy = ((stm_msp_read(msp->registers + MSP_SRG)) >> FRWID_SHIFT) & 0x0000003F; /* Enable clock */ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | ((SRG_ENABLE))), msp->registers + MSP_GCR); /* Another wait */ dummy = ((stm_msp_read(msp->registers + MSP_SRG)) >> FRWID_SHIFT) & 0x0000003F; return 0; } /** * configure_multichannel - Enable multichannel support for transmit & receive. * @msp: main msp controller structure. * @config: configuration structure passed by client driver * * This will enable multichannel support for transmit and receive. * It will set Receive comparator also if configured. * * Returns error(-1) on failure else success(0). */ static int configure_multichannel(struct msp *msp, struct msp_config *config) { struct msp_protocol_desc *protocol_desc; struct msp_multichannel_config *mult_config; if (config->default_protocol_desc == 1) { if (config->protocol >= MSP_INVALID_PROTOCOL) { printk(KERN_ERR "invalid protocol in configure_protocol()\n"); return -EINVAL; } protocol_desc = (struct msp_protocol_desc *)&protocol_desc_tab[config-> protocol]; } else { protocol_desc = (struct msp_protocol_desc *)&config->protocol_desc; } mult_config = &config->multichannel_config; if (true == mult_config->tx_multichannel_enable) { if (MSP_SINGLE_PHASE == protocol_desc->tx_phase_mode) { stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) | ((mult_config-> tx_multichannel_enable << TMCEN_BIT) & (0x0000020))), msp->registers + MSP_MCR); stm_msp_write(mult_config->tx_channel_0_enable, msp->registers + MSP_TCE0); stm_msp_write(mult_config->tx_channel_1_enable, msp->registers + MSP_TCE1); stm_msp_write(mult_config->tx_channel_2_enable, msp->registers + MSP_TCE2); stm_msp_write(mult_config->tx_channel_3_enable, msp->registers + MSP_TCE3); } else { printk(KERN_ERR "Not in authorised mode\n"); return -1; } } if (true == mult_config->rx_multichannel_enable) { if (MSP_SINGLE_PHASE == protocol_desc->rx_phase_mode) { stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) | ((mult_config-> rx_multichannel_enable << RMCEN_BIT) & (0x0000001))), msp->registers + MSP_MCR); stm_msp_write(mult_config->rx_channel_0_enable, msp->registers + MSP_RCE0); stm_msp_write(mult_config->rx_channel_1_enable, msp->registers + MSP_RCE1); stm_msp_write(mult_config->rx_channel_2_enable, msp->registers + MSP_RCE2); stm_msp_write(mult_config->rx_channel_3_enable, msp->registers + MSP_RCE3); } else { printk(KERN_ERR "Not in authorised mode\n"); return -1; } if (mult_config->rx_comparison_enable_mode) { stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) | ((mult_config-> rx_comparison_enable_mode << RCMPM_BIT) & (0x0000018))), msp->registers + MSP_MCR); stm_msp_write(mult_config->comparison_mask, msp->registers + MSP_RCM); stm_msp_write(mult_config->comparison_value, msp->registers + MSP_RCV); } } return 0; } /** * configure_dma - configure dma channel for transmit or receive. * @msp: msp structure * @config: configuration structure. * Context: process * * It will configure dma channels and request them in Logical mode for both * transmit and recevie modes.It also register the respective callback handlers * for DMA. * * Returns void. */ void configure_dma(struct msp *msp, struct msp_config *config) { struct stedma40_chan_cfg *rx_dma_info = msp->dma_cfg_rx; struct stedma40_chan_cfg *tx_dma_info = msp->dma_cfg_tx; dma_cap_mask_t mask; if (config->direction == MSP_TRANSMIT_MODE || config->direction == MSP_BOTH_T_R_MODE) { if (msp->tx_pipeid != NULL) { dma_release_channel(msp->tx_pipeid); msp->tx_pipeid = NULL; } if (config->data_size == MSP_DATA_BITS_32) tx_dma_info->src_info.data_width = STEDMA40_WORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_16) tx_dma_info->src_info.data_width = STEDMA40_HALFWORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_8) tx_dma_info->src_info.data_width = STEDMA40_BYTE_WIDTH; else printk(KERN_ERR "Wrong data size\n"); if (config->data_size == MSP_DATA_BITS_32) tx_dma_info->dst_info.data_width = STEDMA40_WORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_16) tx_dma_info->dst_info.data_width = STEDMA40_HALFWORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_8) tx_dma_info->dst_info.data_width = STEDMA40_BYTE_WIDTH; else printk(KERN_ERR "Wrong data size\n"); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); msp->tx_pipeid = dma_request_channel(mask, stedma40_filter, tx_dma_info); } if (config->direction == MSP_RECEIVE_MODE || config->direction == MSP_BOTH_T_R_MODE) { if (msp->rx_pipeid != NULL) { dma_release_channel(msp->rx_pipeid); msp->rx_pipeid = NULL; } if (config->data_size == MSP_DATA_BITS_32) rx_dma_info->src_info.data_width = STEDMA40_WORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_16) rx_dma_info->src_info.data_width = STEDMA40_HALFWORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_8) rx_dma_info->src_info.data_width = STEDMA40_BYTE_WIDTH; else printk(KERN_ERR "Wrong data size\n"); if (config->data_size == MSP_DATA_BITS_32) rx_dma_info->dst_info.data_width = STEDMA40_WORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_16) rx_dma_info->dst_info.data_width = STEDMA40_HALFWORD_WIDTH; else if (config->data_size == MSP_DATA_BITS_8) rx_dma_info->dst_info.data_width = STEDMA40_BYTE_WIDTH; else printk(KERN_ERR "Wrong data size\n"); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); msp->rx_pipeid = dma_request_channel(mask, stedma40_filter, rx_dma_info); } } /** * msp_enable - Setup the msp configuration. * @msp: msp data contains main msp structure. * @config: configuration structure sent by i2s client driver. * Context: process * * Main msp configuring functions to configure msp in accordance with msp * protocol descriptor, configuring msp clock,setup transfer mode selected by * user like DMA, interrupt or polling and in the end enable RX and Tx path. * * Returns error(-1) in case of failure or success(0). */ static int msp_enable(struct msp *msp, struct msp_config *config) { int status = 0; int state; /* Check msp state whether in RUN or CONFIGURED Mode */ state = msp->msp_state; if (state == MSP_STATE_IDLE) { if (msp->plat_init) { status = msp->plat_init(); if (status) { printk(KERN_ERR "Error in msp_i2s_init," " status is %d\n", status); return status; } } } /* Configure msp with protocol dependent settings */ configure_protocol(msp, config); configure_clock(msp, config); if (config->multichannel_configured == 1) { status = configure_multichannel(msp, config); if (status) printk(KERN_ERR "multichannel can't be configured\n"); } msp->work_mode = config->work_mode; if (msp->work_mode == MSP_DMA_MODE && !msp->dma_cfg_rx) { switch (config->direction) { case MSP_RECEIVE_MODE: case MSP_BOTH_T_R_MODE: dev_err(&msp->i2s_cont->dev, "RX DMA not available"); return -EINVAL; } } if (msp->work_mode == MSP_DMA_MODE && !msp->dma_cfg_tx) { switch (config->direction) { case MSP_TRANSMIT_MODE: case MSP_BOTH_T_R_MODE: dev_err(&msp->i2s_cont->dev, "TX DMA not available"); return -EINVAL; } } switch (config->direction) { case MSP_TRANSMIT_MODE: /*Currently they are ignored stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) | TRANSMIT_UNDERRUN_ERR_INT | TRANSMIT_FRAME_SYNC_ERR_INT), msp->registers + MSP_IMSC); */ if (config->work_mode == MSP_DMA_MODE) { stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) | TX_DMA_ENABLE, msp->registers + MSP_DMACR); msp->xfer_data.tx_handler = config->handler; msp->xfer_data.tx_callback_data = config->tx_callback_data; configure_dma(msp, config); } if (config->work_mode == MSP_POLLING_MODE) { stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); } if (msp->work_mode != MSP_DMA_MODE) { switch (msp->actual_data_size) { case MSP_DATA_BITS_8: msp->write = u8_msp_write; break; case MSP_DATA_BITS_10: case MSP_DATA_BITS_12: case MSP_DATA_BITS_14: case MSP_DATA_BITS_16: msp->write = u16_msp_write; break; case MSP_DATA_BITS_20: case MSP_DATA_BITS_24: case MSP_DATA_BITS_32: default: msp->write = u32_msp_write; break; } msp->xfer_data.tx_handler = config->handler; msp->xfer_data.tx_callback_data = config->tx_callback_data; msp->xfer_data.rx_callback_data = config->rx_callback_data; msp->xfer_data.msp = msp; } break; case MSP_RECEIVE_MODE: /*Currently they are ignored stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) | RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT, msp->registers + MSP_IMSC); */ if (config->work_mode == MSP_DMA_MODE) { stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) | RX_DMA_ENABLE, msp->registers + MSP_DMACR); msp->xfer_data.rx_handler = config->handler; msp->xfer_data.rx_callback_data = config->rx_callback_data; configure_dma(msp, config); } if (config->work_mode == MSP_POLLING_MODE) { stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), msp->registers + MSP_GCR); } if (msp->work_mode != MSP_DMA_MODE) { switch (msp->actual_data_size) { case MSP_DATA_BITS_8: msp->read = u8_msp_read; break; case MSP_DATA_BITS_10: case MSP_DATA_BITS_12: case MSP_DATA_BITS_14: case MSP_DATA_BITS_16: msp->read = u16_msp_read; break; case MSP_DATA_BITS_20: case MSP_DATA_BITS_24: case MSP_DATA_BITS_32: default: msp->read = u32_msp_read; break; } msp->xfer_data.rx_handler = config->handler; msp->xfer_data.tx_callback_data = config->tx_callback_data; msp->xfer_data.rx_callback_data = config->rx_callback_data; msp->xfer_data.msp = msp; } break; case MSP_BOTH_T_R_MODE: /*Currently they are ignored stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) | RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT | TRANSMIT_UNDERRUN_ERR_INT | TRANSMIT_FRAME_SYNC_ERR_INT , msp->registers + MSP_IMSC); */ if (config->work_mode == MSP_DMA_MODE) { stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) | RX_DMA_ENABLE | TX_DMA_ENABLE, msp->registers + MSP_DMACR); msp->xfer_data.tx_handler = config->handler; msp->xfer_data.rx_handler = config->handler; msp->xfer_data.tx_callback_data = config->tx_callback_data; msp->xfer_data.rx_callback_data = config->rx_callback_data; configure_dma(msp, config); } if (config->work_mode == MSP_POLLING_MODE) { stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), msp->registers + MSP_GCR); } if (msp->work_mode != MSP_DMA_MODE) { switch (msp->actual_data_size) { case MSP_DATA_BITS_8: msp->read = u8_msp_read; msp->write = u8_msp_write; break; case MSP_DATA_BITS_10: case MSP_DATA_BITS_12: case MSP_DATA_BITS_14: case MSP_DATA_BITS_16: msp->read = u16_msp_read; msp->write = u16_msp_write; break; case MSP_DATA_BITS_20: case MSP_DATA_BITS_24: case MSP_DATA_BITS_32: default: msp->read = u32_msp_read; msp->write = u32_msp_write; break; } msp->xfer_data.tx_handler = config->handler; msp->xfer_data.rx_handler = config->handler; msp->xfer_data.tx_callback_data = config->tx_callback_data; msp->xfer_data.rx_callback_data = config->rx_callback_data; msp->xfer_data.msp = msp; } break; default: printk(KERN_ERR "Invalid direction parameter\n"); if (msp->plat_exit) msp->plat_exit(); status = -EINVAL; return status; } switch (config->work_mode) { case MSP_DMA_MODE: msp->transfer = msp_dma_xfer; break; case MSP_POLLING_MODE: msp->transfer = msp_polling_xfer; break; case MSP_INTERRUPT_MODE: msp->transfer = msp_interrupt_xfer; break; default: msp->transfer = NULL; } stm_msp_write(config->iodelay, msp->registers + MSP_IODLY); /* enable frame generation logic */ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (FRAME_GEN_ENABLE)), msp->registers + MSP_GCR); return status; } /** * flush_rx_fifo - Flush Rx fifo MSP controller. * @msp: msp structure. * * This function flush the rx fifo of msp controller. * * Returns error(-1) in case of failure else success(0) */ static void flush_rx_fifo(struct msp *msp) { u32 dummy = 0; u32 limit = 32; u32 cur = stm_msp_read(msp->registers + MSP_GCR); stm_msp_write(cur | RX_ENABLE, msp->registers + MSP_GCR); while (!(stm_msp_read(msp->registers + MSP_FLR) & RX_FIFO_EMPTY) && limit--) { dummy = stm_msp_read(msp->registers + MSP_DR); } stm_msp_write(cur, msp->registers + MSP_GCR); } /** * flush_tx_fifo - Flush Tx fifo MSP controller. * @msp: msp structure. * * This function flush the tx fifo using test intergration register to read data * from tx fifo directly. * * Returns error(-1) in case of failure else success(0) */ static void flush_tx_fifo(struct msp *msp) { u32 dummy = 0; u32 limit = 32; u32 cur = stm_msp_read(msp->registers + MSP_GCR); stm_msp_write(cur | TX_ENABLE, msp->registers + MSP_GCR); stm_msp_write(0x3, msp->registers + MSP_ITCR); while (!(stm_msp_read(msp->registers + MSP_FLR) & TX_FIFO_EMPTY) && limit--) { dummy = stm_msp_read(msp->registers + MSP_TSTDR); } stm_msp_write(0x0, msp->registers + MSP_ITCR); stm_msp_write(cur, msp->registers + MSP_GCR); } /** * stm_msp_configure_enable - configures and enables the MSP controller. * @i2s_cont: i2s controller sent by i2s device. * @configuration: specifies the configuration parameters. * * This function configures the msp controller with the client configuration. * * Returns error(-1) in case of failure else success(0) */ static int stm_msp_configure_enable(struct i2s_controller *i2s_cont, void *configuration) { u32 old_reg; u32 new_reg; u32 mask; int res; struct msp_config *config = (struct msp_config *)configuration; struct msp *msp = (struct msp *)i2s_cont->data; if (in_interrupt()) { printk(KERN_ERR "can't call configure_enable in interrupt context\n"); return -1; } /* Two simultanous configuring msp is avoidable */ down(&msp->lock); /* Don't enable regulator if its msp1 or msp3 */ if (!(msp->reg_enabled) && msp->id != MSP_1_I2S_CONTROLLER && msp->id != MSP_3_I2S_CONTROLLER) { res = regulator_enable(msp_vape_supply); if (res != 0) { dev_err(&msp->i2s_cont->dev, "Failed to enable regulator\n"); up(&msp->lock); return res; } msp->reg_enabled = 1; } switch (msp->users) { case 0: clk_enable(msp->clk); msp->direction = config->direction; break; case 1: if (msp->direction == MSP_BOTH_T_R_MODE || config->direction == msp->direction || config->direction == MSP_BOTH_T_R_MODE) { dev_notice(&i2s_cont->dev, "%s: MSP in use in the " "desired direction.\n", __func__); up(&msp->lock); return -EBUSY; } msp->direction = MSP_BOTH_T_R_MODE; break; default: dev_notice(&i2s_cont->dev, "%s: MSP in use in both " "directions.\n", __func__); up(&msp->lock); return -EBUSY; } msp->users++; /* First do the global config register */ mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FRAME_SYNC_MASK | TX_FRAME_SYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK | RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK | LOOPBACK_MASK | TX_EXTRA_DELAY_MASK; new_reg = (config->tx_clock_sel | config->rx_clock_sel | config-> rx_frame_sync_pol | config->tx_frame_sync_pol | config-> rx_frame_sync_sel | config->tx_frame_sync_sel | config-> rx_fifo_config | config->tx_fifo_config | config-> srg_clock_sel | config->loopback_enable | config->tx_data_enable); old_reg = stm_msp_read(msp->registers + MSP_GCR); old_reg &= ~mask; new_reg |= old_reg; stm_msp_write(new_reg, msp->registers + MSP_GCR); if (msp_enable(msp, config) != 0) { printk(KERN_ERR "error enabling MSP\n"); return -EBUSY; } if (config->loopback_enable & 0x80) msp->loopback_enable = 1; /*Sometimes FIFO doesn't gets empty hence limit is provided */ flush_tx_fifo(msp); /*This has been added in order to fix fifo flush problem When last xfer occurs some data remains in fifo. In order to flush that data delay is needed */ msleep(10); /* wait for fifo to flush */ flush_rx_fifo(msp); /* RX_BUSY take a while to clear */ msleep(10); msp->msp_state = MSP_STATE_CONFIGURED; up(&msp->lock); return 0; } static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data, size_t bytes) { struct dma_async_tx_descriptor *desc; struct scatterlist sg; sg_init_table(&sg, 1); sg_set_page(&sg, pfn_to_page(PFN_DOWN(data)), bytes, offset_in_page(data)); sg_dma_address(&sg) = data; sg_dma_len(&sg) = bytes; if (transmit) { if (!msp->tx_pipeid) return -EINVAL; desc = msp->tx_pipeid->device-> device_prep_slave_sg(msp->tx_pipeid, &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) return -ENOMEM; desc->callback = msp->xfer_data.tx_handler; desc->callback_param = msp->xfer_data.tx_callback_data; desc->tx_submit(desc); dma_async_issue_pending(msp->tx_pipeid); } else { if (!msp->rx_pipeid) return -EINVAL; desc = msp->rx_pipeid->device-> device_prep_slave_sg(msp->rx_pipeid, &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) return -EBUSY; desc->callback = msp->xfer_data.rx_handler; desc->callback_param = msp->xfer_data.rx_callback_data; desc->tx_submit(desc); dma_async_issue_pending(msp->rx_pipeid); } return 0; } static int msp_single_dma_tx(struct msp *msp, dma_addr_t data, size_t bytes) { int status; status = msp_start_dma(msp, 1, data, bytes); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); return status; } static int msp_single_dma_rx(struct msp *msp, dma_addr_t data, size_t bytes) { int status; status = msp_start_dma(msp, 0, data, bytes); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), msp->registers + MSP_GCR); return status; } static void msp_cyclic_dma_start(struct msp *msp, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction) { int ret; struct dma_async_tx_descriptor *cdesc; struct dma_chan *pipeid = (direction == DMA_TO_DEVICE) ? msp->tx_pipeid : msp->rx_pipeid; pr_debug("%s: buf_addr = %p\n", __func__, (void *) buf_addr); pr_debug("%s: buf_len = %d\n", __func__, buf_len); pr_debug("%s: perios_len = %d\n", __func__, period_len); /* setup the cyclic description */ cdesc = pipeid->device->device_prep_dma_cyclic(pipeid, buf_addr, /* reuse the sq list for the moment */ buf_len, period_len, direction); if (IS_ERR(cdesc)) { pr_err("%s: Error: device_prep_dma_cyclic failed (%ld)!\n", __func__, PTR_ERR(cdesc)); return; } cdesc->callback = (direction == DMA_TO_DEVICE) ? msp->xfer_data.tx_handler : msp->xfer_data.rx_handler; cdesc->callback_param = (direction == DMA_TO_DEVICE) ? msp->xfer_data.tx_callback_data : msp->xfer_data.rx_callback_data; /* submit to the dma */ ret = dmaengine_submit(cdesc); /* start the dma */ dma_async_issue_pending(pipeid); return; } /* Legacy function. Used by HATS driver. */ static void msp_loopback_inf_start_dma(struct msp *msp, dma_addr_t data, size_t bytes) { #if 0 struct stedma40_cyclic_desc *rxcdesc; struct stedma40_cyclic_desc *txcdesc; struct scatterlist rxsg[2]; struct scatterlist txsg[2]; size_t len = bytes >> 1; int ret; sg_init_table(rxsg, ARRAY_SIZE(rxsg)); sg_init_table(txsg, ARRAY_SIZE(txsg)); sg_dma_len(&rxsg[0]) = len; sg_dma_len(&rxsg[1]) = len; sg_dma_len(&txsg[0]) = len; sg_dma_len(&txsg[1]) = len; sg_dma_address(&rxsg[0]) = data; sg_dma_address(&rxsg[1]) = data + len; sg_dma_address(&txsg[0]) = data + len; sg_dma_address(&txsg[1]) = data; rxcdesc = stedma40_cyclic_prep_sg(msp->rx_pipeid, rxsg, ARRAY_SIZE(rxsg), DMA_FROM_DEVICE, 0); if (IS_ERR(rxcdesc)) return; txcdesc = stedma40_cyclic_prep_sg(msp->tx_pipeid, txsg, ARRAY_SIZE(txsg), DMA_TO_DEVICE, 0); if (IS_ERR(txcdesc)) goto free_rx; ret = stedma40_cyclic_start(msp->rx_pipeid); if (ret) goto free_tx; ret = stedma40_cyclic_start(msp->tx_pipeid); if (ret) goto stop_rx; msp->infinite = true; return; stop_rx: stedma40_cyclic_stop(msp->rx_pipeid); free_tx: stedma40_cyclic_free(msp->tx_pipeid); free_rx: stedma40_cyclic_free(msp->rx_pipeid); #endif return; } /** * msp_dma_xfer - Handles DMA transfers over i2s bus. * @msp: main msp structure. * @msg: i2s_message contains info about transmit and receive data. * Context: process * * This will first check whether data buffer is dmaable or not. * Call dma_map_single apis etc to make it dmaable dma. Starts the dma transfer * for TX and RX parallely and wait for it to get completed. * * Returns error(-1) in case of failure or success(0). */ static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg) { int status = 0; switch (msg->i2s_transfer_mode) { default: case I2S_TRANSFER_MODE_SINGLE_DMA: if (msg->i2s_direction == I2S_DIRECTION_RX || msg->i2s_direction == I2S_DIRECTION_BOTH) if (msg->rxdata && (msg->rxbytes > 0)) { if (!msg->dma_flag) msg->rxdata = (void *)dma_map_single(NULL, msg->rxdata, msg->rxbytes, DMA_FROM_DEVICE ); status = msp_single_dma_rx(msp, (dma_addr_t)msg->rxdata, msg->rxbytes); } if (msg->i2s_direction == I2S_DIRECTION_TX || msg->i2s_direction == I2S_DIRECTION_BOTH) if (msg->txdata && (msg->txbytes > 0)) { if (!msg->dma_flag) msg->txdata = (void *)dma_map_single(NULL, msg->txdata, msg->txbytes, DMA_TO_DEVICE); status = msp_single_dma_tx(msp, (dma_addr_t)msg->txdata, msg->txbytes); } break; case I2S_TRANSFER_MODE_CYCLIC_DMA: if (msg->i2s_direction == I2S_DIRECTION_TX) { msp_cyclic_dma_start(msp, msg->buf_addr, msg->buf_len, msg->period_len, DMA_TO_DEVICE); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); } else { msp_cyclic_dma_start(msp, msg->buf_addr, msg->buf_len, msg->period_len, DMA_FROM_DEVICE); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), msp->registers + MSP_GCR); } break; case I2S_TRANSFER_MODE_INF_LOOPBACK: msp_loopback_inf_start_dma(msp, (dma_addr_t)msg->rxdata, msg->rxbytes); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), msp->registers + MSP_GCR); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); break; } return status; } #if 0 /** * msp_handle_irq - Interrupt handler routine. * @irq: irq no. * @dev_id: device structure registered in request irq. * * Returns error(-1) on failure else success(0). */ static irqreturn_t msp_handle_irq(int irq, void *dev_id) { u32 irq_status; struct msp *msp = (struct msp *)dev_id; struct i2s_message *message = &msp->xfer_data.message; u32 irq_mask = 0; irq_status = stm_msp_read(msp->registers + MSP_MIS); irq_mask = stm_msp_read(msp->registers + MSP_IMSC); /* Disable the interrupt to prevent immediate recurrence */ stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) & ~irq_status, msp->registers + MSP_IMSC); /* Clear the interrupt */ stm_msp_write(irq_status, msp->registers + MSP_ICR); /* Check for an error condition */ msp->msp_io_error = irq_status & (RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT | TRANSMIT_UNDERRUN_ERR_INT | TRANSMIT_FRAME_SYNC_ERR_INT); /*Currently they are ignored */ if (irq_status & RECEIVE_OVERRUN_ERROR_INT) ; if (irq_status & TRANSMIT_UNDERRUN_ERR_INT) ; /* This code has been added basically to support loopback mode * Basically Transmit interrupt is not disabled even after its * completion so that receive fifo gets an additional interrupt */ if (irq_mask & (RECEIVE_SERVICE_INT) && (irq_mask & (TRANSMIT_SERVICE_INT)) && (msp->loopback_enable)) { if (msp->read) msp->read(&msp->xfer_data); if (msp->write) msp->write(&msp->xfer_data); if (message->rx_offset >= message->rxbytes) { if (msp->xfer_data.rx_handler) msp->xfer_data.rx_handler(msp-> xfer_data. rx_callback_data, message->rx_offset); msp->xfer_data.rx_handler = NULL; return IRQ_HANDLED; } if (message->tx_offset >= message->txbytes) { if (msp->xfer_data.tx_handler) msp->xfer_data.tx_handler(msp->xfer_data. tx_callback_data, message->tx_offset); msp->xfer_data.tx_handler = NULL; } stm_msp_write(irq_mask, msp->registers + MSP_IMSC); return IRQ_HANDLED; } if (irq_status & RECEIVE_SERVICE_INT) { if (msp->read) msp->read(&msp->xfer_data); if (message->rx_offset >= message->rxbytes) { irq_mask &= ~RECEIVE_SERVICE_INT; stm_msp_write(irq_mask, msp->registers + MSP_IMSC); if (msp->xfer_data.rx_handler) msp->xfer_data.rx_handler(msp-> xfer_data. rx_callback_data, message->rx_offset); if (!(irq_status & TRANSMIT_SERVICE_INT)) return IRQ_HANDLED; } } if (irq_status & TRANSMIT_SERVICE_INT) { if (msp->write) msp->write(&msp->xfer_data); if (message->tx_offset >= message->txbytes) { irq_mask &= ~TRANSMIT_SERVICE_INT; stm_msp_write(irq_mask, msp->registers + MSP_IMSC); if (msp->xfer_data.tx_handler) msp->xfer_data.tx_handler(msp->xfer_data. tx_callback_data, message->tx_offset); return IRQ_HANDLED; } } stm_msp_write(irq_mask, msp->registers + MSP_IMSC); return IRQ_HANDLED; } #endif /** * msp_interrupt_xfer - Handles Interrupt transfers over i2s bus. * @msp: main msp structure. * @msg: i2s_message contains info about transmit and receive data. * Context: Process or interrupt. * * This implements transfer and receive functions used in interrupt mode. * This can be used in interrupt context if a callback handler is registered * by client driver. This has been to improve performance in interrupt mode. * Hence can't use sleep in this function. * * Returns error(-1) in case of failure or success(0). */ static int msp_interrupt_xfer(struct msp *msp, struct i2s_message *msg) { struct i2s_message *message; u32 irq_mask = 0; if (msg->i2s_transfer_mode != I2S_TRANSFER_MODE_NON_DMA) return -EINVAL; if (msg->txbytes) { msp->xfer_data.message.txbytes = msg->txbytes; msp->xfer_data.message.txdata = msg->txdata; msp->xfer_data.message.tx_offset = 0; } if (msg->rxbytes) { msp->xfer_data.message.rxbytes = msg->rxbytes; msp->xfer_data.message.rxdata = msg->rxdata; msp->xfer_data.message.rx_offset = 0; } message = &msp->xfer_data.message; if ((message->txdata == NULL || message->txbytes == 0) && (message->rxdata == NULL || message->rxbytes == 0)) { printk(KERN_ERR "transmit_receive_data is NULL with bytes > 0\n"); return -EINVAL; } msp->msp_io_error = 0; if (message->tx_offset < message->txbytes) { irq_mask |= TRANSMIT_SERVICE_INT; stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); } if (message->rx_offset < message->rxbytes) { irq_mask |= RECEIVE_SERVICE_INT; stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), msp->registers + MSP_GCR); } stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) | irq_mask), msp->registers + MSP_IMSC); return 0; } /** * func_notify_timer - Handles Polling hang issue over i2s bus. * @data: main msp data address * Context: Interrupt. * * This is used to handle error condition in transfer and receive function used * in polling mode. * Sometimes due to passing wrong protocol desc , polling transfer may hang. * To prevent this, timer is added. * * Returns void. */ static void func_notify_timer(unsigned long data) { struct msp *msp = (struct msp *)data; if (msp->polling_flag) { msp->msp_io_error = 1; printk(KERN_ERR "Polling is taking two much time, may be it got hang\n"); del_timer(&msp->notify_timer); } } /** * msp_polling_xfer - Handles Polling transfers over i2s bus. * @msp: main msp structure. * @msg: i2s_message contains info about transmit and receive data. * Context: Process. * * This implements transfer and receive functions used in polling mode. This is * blocking fucntion. * It is recommended to use interrupt or dma mode for better performance rather * than the polling mode. * * Returns error(-1) in case of failure or success(0). */ static int msp_polling_xfer(struct msp *msp, struct i2s_message *msg) { struct i2s_message *message; u32 time_expire = 0; u32 tr_ex = 0, rr_ex = 0; u32 msec_jiffies = 0; if (msg->i2s_transfer_mode != I2S_TRANSFER_MODE_NON_DMA) return -EINVAL; if (msg->txbytes) { msp->xfer_data.message.txbytes = msg->txbytes; msp->xfer_data.message.txdata = msg->txdata; msp->xfer_data.message.tx_offset = 0; tr_ex = msg->txbytes; } if (msg->rxbytes) { msp->xfer_data.message.rxbytes = msg->rxbytes; msp->xfer_data.message.rxdata = msg->rxdata; msp->xfer_data.message.rx_offset = 0; rr_ex = msg->rxbytes; } message = &msp->xfer_data.message; time_expire = (tr_ex + rr_ex) / 1024; if (!time_expire) msec_jiffies = 500; else msec_jiffies = time_expire * 500; msp->notify_timer.expires = jiffies + msecs_to_jiffies(msec_jiffies); down(&msp->lock); if (message->txdata == NULL && message->txbytes > 0) { printk(KERN_ERR "transmit_receive_data is NULL with bytes > 0\n"); return -EINVAL; } if (message->rxdata == NULL && message->rxbytes > 0) { printk(KERN_ERR "transmit_receive_data is NULL with bytes > 0\n"); return -EINVAL; } msp->msp_io_error = 0; msp->polling_flag = 1; add_timer(&msp->notify_timer); while (message->tx_offset < message->txbytes || message->rx_offset < message->rxbytes) { if (msp->msp_io_error) break; if (msp->read) msp->read(&msp->xfer_data); if (msp->write) msp->write(&msp->xfer_data); } msp->polling_flag = 0; del_timer(&msp->notify_timer); up(&msp->lock); return message->txbytes + message->rxbytes; } /** * stm_msp_transceive_data - Main i2s transfer function. * @i2s_cont: i2s controller structure passed by client driver. * @message: i2s message structure contains transceive info. * Context: process or interrupt. * * This function is registered over i2s_xfer funtions. It will handle main i2s * transfer over i2s bus in various modes.It call msp transfer function on which * suitable transfer function is already registered i.e dma ,interrupt or * polling function. * * Returns error(-1) in case of failure or success(0). */ static int stm_msp_transceive_data(struct i2s_controller *i2s_cont, struct i2s_message *message) { int status = 0; struct msp *msp = (struct msp *)i2s_cont->data; if (!message || (msp->msp_state == MSP_STATE_IDLE)) { printk(KERN_ERR "Message is NULL\n"); return -EPERM; } msp->msp_state = MSP_STATE_RUN; if (msp->transfer) status = msp->transfer(msp, message); if (msp->msp_state == MSP_STATE_RUN) msp->msp_state = MSP_STATE_CONFIGURED; return status; } /** * msp_disable_receive - Disable receive functionality. * @msp: main msp structure. * Context: process. * * This function will disable msp controller's receive functionality like dma, * interrupt receive data buffer all are disabled. * * Returns void. */ static void msp_disable_receive(struct msp *msp) { stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) & (~RX_ENABLE)), msp->registers + MSP_GCR); stm_msp_write((stm_msp_read(msp->registers + MSP_DMACR) & (~RX_DMA_ENABLE)), msp->registers + MSP_DMACR); stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) & (~ (RECEIVE_SERVICE_INT | RECEIVE_OVERRUN_ERROR_INT))), msp->registers + MSP_IMSC); msp->xfer_data.message.rxbytes = 0; msp->xfer_data.message.rx_offset = 0; msp->xfer_data.message.rxdata = NULL; msp->read = NULL; } /** * msp_disable_transmit - Disable transmit functionality. * @msp: main msp structure. * Context: process. * * This function will disable msp controller's transmit functionality like dma, * interrupt transmit data buffer all are disabled. * * Returns void. */ static void msp_disable_transmit(struct msp *msp) { stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) & (~TX_ENABLE)), msp->registers + MSP_GCR); stm_msp_write((stm_msp_read(msp->registers + MSP_DMACR) & (~TX_DMA_ENABLE)), msp->registers + MSP_DMACR); stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) & (~ (TRANSMIT_SERVICE_INT | TRANSMIT_UNDERRUN_ERR_INT))), msp->registers + MSP_IMSC); msp->xfer_data.message.txbytes = 0; msp->xfer_data.message.tx_offset = 0; msp->xfer_data.message.txdata = NULL; msp->write = NULL; } /** * stm_msp_disable - disable the given msp controller * @msp: specifies the msp contoller data * @direction: specifies the transmit/receive direction * @flag: It indicates the functionality that needs to be disabled. * * Returns error(-1) in case of failure else success(0) */ static int stm_msp_disable(struct msp *msp, int direction, i2s_flag flag) { int limit = 32; u32 dummy = 0; int status = 0; if (! (stm_msp_read(msp->registers + MSP_GCR) & ((TX_ENABLE | RX_ENABLE)))) { return 0; } if (msp->work_mode == MSP_DMA_MODE) { if (flag == DISABLE_ALL || flag == DISABLE_TRANSMIT) { if (msp->tx_pipeid != NULL) { dmaengine_terminate_all(msp->tx_pipeid); dma_release_channel(msp->tx_pipeid); msp->tx_pipeid = NULL; } } if ((flag == DISABLE_ALL || flag == DISABLE_RECEIVE)) { if (msp->rx_pipeid != NULL) { dmaengine_terminate_all(msp->rx_pipeid); dma_release_channel(msp->rx_pipeid); msp->rx_pipeid = NULL; } } } if (flag == DISABLE_TRANSMIT) msp_disable_transmit(msp); else if (flag == DISABLE_RECEIVE) msp_disable_receive(msp); else { stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (LOOPBACK_MASK)), msp->registers + MSP_GCR); /* Flush Tx fifo */ while ((! (stm_msp_read(msp->registers + MSP_FLR) & TX_FIFO_EMPTY)) && limit--) dummy = stm_msp_read(msp->registers + MSP_DR); /* Disable Transmit channel */ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) & (~TX_ENABLE)), msp->registers + MSP_GCR); limit = 32; /* Flush Rx Fifo */ while ((! (stm_msp_read(msp->registers + MSP_FLR) & RX_FIFO_EMPTY)) && limit--) dummy = stm_msp_read(msp->registers + MSP_DR); /* Disable Loopback and Receive channel */ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) & (~(RX_ENABLE | LOOPBACK_MASK))), msp->registers + MSP_GCR); /*This has been added in order to fix fifo flush problem When last xfer occurs some data remains in fifo. In order to flush that data delay is needed */ msleep(10); msp_disable_transmit(msp); msp_disable_receive(msp); } /* disable sample rate and frame generators */ if (flag == DISABLE_ALL) { msp->msp_state = MSP_STATE_IDLE; stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) & (~(FRAME_GEN_ENABLE | SRG_ENABLE))), msp->registers + MSP_GCR); memset(&msp->xfer_data, 0, sizeof(struct trans_data)); if (msp->plat_exit) status = msp->plat_exit(); if (status) printk(KERN_ERR "Error in msp_i2s_exit\n"); if (msp->work_mode == MSP_POLLING_MODE && msp->msp_state == MSP_STATE_RUN) { up(&msp->lock); } msp->transfer = NULL; stm_msp_write(0, msp->registers + MSP_GCR); stm_msp_write(0, msp->registers + MSP_TCF); stm_msp_write(0, msp->registers + MSP_RCF); stm_msp_write(0, msp->registers + MSP_DMACR); stm_msp_write(0, msp->registers + MSP_SRG); stm_msp_write(0, msp->registers + MSP_MCR); stm_msp_write(0, msp->registers + MSP_RCM); stm_msp_write(0, msp->registers + MSP_RCV); stm_msp_write(0, msp->registers + MSP_TCE0); stm_msp_write(0, msp->registers + MSP_TCE1); stm_msp_write(0, msp->registers + MSP_TCE2); stm_msp_write(0, msp->registers + MSP_TCE3); stm_msp_write(0, msp->registers + MSP_RCE0); stm_msp_write(0, msp->registers + MSP_RCE1); stm_msp_write(0, msp->registers + MSP_RCE2); stm_msp_write(0, msp->registers + MSP_RCE3); } return status; } /** * stm_msp_close - Close the current i2s connection btw controller and client. * @i2s_cont: i2s controller structure * @flag: It indicates the functionality that needs to be disabled. * Context: process * * It will call msp_disable and reset the msp configuration. Disables Rx and Tx * channels, free gpio irqs and interrupt pins. * Called by i2s client driver to indicate the completion of use of i2s bus. * It is registered on i2s_close function. * * Returns error(-1) in case of failure or success(0). */ static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag) { int status = 0; struct msp *msp = (struct msp *)i2s_cont->data; down(&msp->lock); if (msp->users == 0) { pr_err("MSP already closed!\n"); status = -EINVAL; goto end; } dev_dbg(&i2s_cont->dev, "%s: users = %d, flag = %d.\n", __func__, msp->users, flag); /* We need to call it twice for DISABLE_ALL*/ msp->users = flag == DISABLE_ALL ? 0 : msp->users - 1; if (msp->users) status = stm_msp_disable(msp, MSP_BOTH_T_R_MODE, flag); else { status = stm_msp_disable(msp, MSP_BOTH_T_R_MODE, DISABLE_ALL); clk_disable(msp->clk); if (msp->reg_enabled) { status = regulator_disable(msp_vape_supply); msp->reg_enabled = 0; } if (status != 0) { dev_err(&msp->i2s_cont->dev, "Failed to disable regulator\n"); clk_enable(msp->clk); goto end; } } if (status) goto end; if (msp->users) msp->direction = flag == DISABLE_TRANSMIT ? MSP_RECEIVE_MODE : MSP_TRANSMIT_MODE; if (msp->vape_opp_constraint == 1) { prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 50); msp->vape_opp_constraint = 0; } end: up(&msp->lock); return status; } static int stm_msp_hw_status(struct i2s_controller *i2s_cont) { struct msp *msp = (struct msp *)i2s_cont->data; int status = stm_msp_read(msp->registers + MSP_RIS) & 0xee; if (status) stm_msp_write(status, msp->registers + MSP_ICR); return status; } /*Platform driver's functions */ /** * msp_probe - Probe function * @pdev: platform device structure. * Context: process * * Probe function of msp platform driver.Handles allocation of memory and irq * resource. It creates i2s_controller and one i2s_device per msp controller. * * Returns error(-1) in case of failure or success(0). */ int msp_probe(struct platform_device *pdev) { int status = 0; struct device *dev; s16 platform_num = 0; struct resource *res = NULL; int irq; struct i2s_controller *i2s_cont; struct msp_i2s_platform_data *platform_data; struct msp *msp; if (!pdev) return -EPERM; msp = kzalloc(sizeof(*msp), GFP_KERNEL); platform_data = (struct msp_i2s_platform_data *)pdev->dev.platform_data; msp->id = platform_data->id; msp->plat_init = platform_data->msp_i2s_init; msp->plat_exit = platform_data->msp_i2s_exit; msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx; msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx; dev = &pdev->dev; platform_num = msp->id - 1; sema_init(&msp->lock, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "probe - MEM resources not defined\n"); status = -EINVAL; goto free_msp; } irq = platform_get_irq(pdev, 0); if (irq < 0) { status = -EINVAL; goto free_msp; } msp->irq = irq; msp->registers = ioremap(res->start, (res->end - res->start + 1)); if (msp->registers == NULL) { status = -EINVAL; goto free_msp; } msp_vape_supply = regulator_get(NULL, "v-ape"); if (IS_ERR(msp_vape_supply)) { status = PTR_ERR(msp_vape_supply); printk(KERN_WARNING "msp i2s : failed to get v-ape supply\n"); goto free_irq; } prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 50); msp->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(msp->clk)) { status = PTR_ERR(msp->clk); goto free_irq; } init_timer(&msp->notify_timer); msp->notify_timer.expires = jiffies + msecs_to_jiffies(1000); msp->notify_timer.function = func_notify_timer; msp->notify_timer.data = (unsigned long)msp; msp->rx_pipeid = NULL; msp->tx_pipeid = NULL; msp->read = NULL; msp->write = NULL; msp->transfer = NULL; msp->msp_state = MSP_STATE_IDLE; msp->loopback_enable = 0; dev_set_drvdata(&pdev->dev, msp); /* I2S Controller is allocated and added in I2S controller class. */ i2s_cont = (struct i2s_controller *)kzalloc(sizeof(*i2s_cont), GFP_KERNEL); if (!i2s_cont) { dev_err(&pdev->dev, "i2s controller alloc failed \n"); status = -EINVAL; goto del_timer; } i2s_cont->dev.parent = dev; i2s_cont->algo = &i2s_algo; i2s_cont->data = (void *)msp; i2s_cont->id = platform_num; snprintf(i2s_cont->name, sizeof(i2s_cont->name), "MSP_I2S.%04x", platform_num); status = i2s_add_controller(i2s_cont); if (status) { dev_err(&pdev->dev, "i2s add controller failed (%d)\n", status); goto free_cont; } msp->i2s_cont = i2s_cont; return status; free_cont: kfree(msp->i2s_cont); del_timer: del_timer_sync(&msp->notify_timer); clk_put(msp->clk); free_irq: iounmap(msp->registers); free_msp: kfree(msp); return status; } /** * msp_remove - remove function * @pdev: platform device structure. * Context: process * * remove function of msp platform driver.Handles dellocation of memory and irq * resource. It deletes i2s_controller and one i2s_device per msp controller * created in msp_probe. * * Returns error(-1) in case of failure or success(0). */ static int msp_remove(struct platform_device *pdev) { struct msp *msp = (struct msp *)dev_get_drvdata(&pdev->dev); int status = 0; i2s_del_controller(msp->i2s_cont); del_timer_sync(&msp->notify_timer); clk_put(msp->clk); iounmap(msp->registers); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "msp_i2s"); regulator_put(msp_vape_supply); kfree(msp); return status; } #ifdef CONFIG_PM /** * msp_suspend - MSP suspend function registered with PM framework. * @pdev: Reference to platform device structure of the device * @state: power mgmt state. * * This function is invoked when the system is going into sleep, called * by the power management framework of the linux kernel. * Nothing is required as controller is configured with every transfer. * It is assumed that no active tranfer is in progress at this time. * Client driver should make sure of this. * */ int msp_suspend(struct platform_device *pdev, pm_message_t state) { struct msp *msp = (struct msp *)dev_get_drvdata(&pdev->dev); down(&msp->lock); if (msp->users > 0) { up(&msp->lock); return -EBUSY; } up(&msp->lock); return 0; } /** * msp_resume - MSP Resume function registered with PM framework. * @pdev: Reference to platform device structure of the device * * This function is invoked when the system is coming out of sleep, called * by the power management framework of the linux kernel. * Nothing is required. * */ int msp_resume(struct platform_device *pdev) { return 0; } #else #define msp_suspend NULL #define msp_resume NULL #endif static struct platform_driver msp_i2s_driver = { .probe = msp_probe, .remove = msp_remove, .suspend = msp_suspend, .resume = msp_resume, .driver = { .owner = THIS_MODULE, .name = "MSP_I2S", }, }; static int __init stm_msp_mod_init(void) { return platform_driver_register(&msp_i2s_driver); } static void __exit stm_msp_exit(void) { platform_driver_unregister(&msp_i2s_driver); return; } module_init(stm_msp_mod_init); module_exit(stm_msp_exit); MODULE_AUTHOR("Sandeep Kaushik"); MODULE_DESCRIPTION("STM MSP driver"); MODULE_LICENSE("GPL");