/* * Setup FDMA transfer. Add 'oob' to list, if present. Assumes FDMA channel * has been initialised, and data areas are suitably aligned. */ static int nand_write_dma(struct mtd_info *mtd, const uint8_t *buf, int buf_len, uint8_t *oob, int oob_len) { struct nand_chip *chip = mtd->priv; struct stm_nand_emi *data = chip->priv; unsigned long nand_dma; dma_addr_t buf_dma; dma_addr_t oob_dma; unsigned long res = 0; /* Check channel is ready for use */ if (dma_get_status(data->dma_chan) != DMA_CHANNEL_STATUS_IDLE) { printk(KERN_ERR NAME ": requested channel not idle\n"); return 1; } /* Set up and map DMA addresses */ nand_dma = data->nand_phys_addr; buf_dma = dma_map_single(NULL, buf, buf_len, DMA_TO_DEVICE); dma_params_addrs(&data->dma_params[0], buf_dma, nand_dma, buf_len); /* Are we doing data+oob linked transfer? */ if (oob) { oob_dma = dma_map_single(NULL, oob, oob_len, DMA_TO_DEVICE); dma_params_link(&data->dma_params[0], &data->dma_params[1]); dma_params_addrs(&data->dma_params[1], oob_dma, nand_dma, oob_len); } else { data->dma_params[0].next = NULL; } /* Compile transfer list */ res = dma_compile_list(data->dma_chan, &data->dma_params[0], GFP_ATOMIC); if (res != 0) { printk(KERN_ERR NAME ": DMA compile list failed (err_code = %ld)\n", res); return 1; } /* Initiate transfer */ res = dma_xfer_list(data->dma_chan, &data->dma_params[0]); if (res != 0) { printk(KERN_ERR NAME ": transfer failed (err_code = %ld)\n", res); return 1; } /* Wait for completion... */ dma_wait_for_completion(data->dma_chan); /* Unmap DMA memory */ dma_unmap_single(NULL, buf_dma, buf_len, DMA_TO_DEVICE); if (oob) dma_unmap_single(NULL, oob_dma, oob_len, DMA_TO_DEVICE); return 0; }
static int snd_stm_pcm_player_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { int result; struct snd_stm_pcm_player *pcm_player = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int buffer_bytes, frame_bytes, transfer_bytes; unsigned int transfer_size; struct stm_dma_req_config fdma_req_config = { .rw = REQ_CONFIG_WRITE, .opcode = REQ_CONFIG_OPCODE_4, .increment = 0, .hold_off = 0, .initiator = pcm_player->info->fdma_initiator, }; snd_stm_printd(1, "snd_stm_pcm_player_hw_params(substream=0x%p," " hw_params=0x%p)\n", substream, hw_params); BUG_ON(!pcm_player); BUG_ON(!snd_stm_magic_valid(pcm_player)); BUG_ON(!runtime); /* This function may be called many times, so let's be prepared... */ if (snd_stm_buffer_is_allocated(pcm_player->buffer)) snd_stm_pcm_player_hw_free(substream); /* Allocate buffer */ buffer_bytes = params_buffer_bytes(hw_params); result = snd_stm_buffer_alloc(pcm_player->buffer, substream, buffer_bytes); if (result != 0) { snd_stm_printe("Can't allocate %d bytes buffer for '%s'!\n", buffer_bytes, dev_name(pcm_player->device)); result = -ENOMEM; goto error_buf_alloc; } /* Set FDMA transfer size (number of opcodes generated * after request line assertion) */ frame_bytes = snd_pcm_format_physical_width(params_format(hw_params)) * params_channels(hw_params) / 8; transfer_bytes = snd_stm_pcm_transfer_bytes(frame_bytes, pcm_player->fdma_max_transfer_size * 4); transfer_size = transfer_bytes / 4; snd_stm_printd(1, "FDMA request trigger limit and transfer size set " "to %d.\n", transfer_size); BUG_ON(buffer_bytes % transfer_bytes != 0); BUG_ON(transfer_size > pcm_player->fdma_max_transfer_size); fdma_req_config.count = transfer_size; BUG_ON(transfer_size != 1 && transfer_size % 2 != 0); BUG_ON(transfer_size > mask__AUD_PCMOUT_FMT__DMA_REQ_TRIG_LMT(pcm_player)); set__AUD_PCMOUT_FMT__DMA_REQ_TRIG_LMT(pcm_player, transfer_size); /* Configure FDMA transfer */ pcm_player->fdma_request = dma_req_config(pcm_player->fdma_channel, pcm_player->info->fdma_request_line, &fdma_req_config); if (!pcm_player->fdma_request) { snd_stm_printe("Can't configure FDMA pacing channel for player" " '%s'!\n", dev_name(pcm_player->device)); result = -EINVAL; goto error_req_config; } dma_params_init(&pcm_player->fdma_params, MODE_PACED, STM_DMA_LIST_CIRC); dma_params_DIM_1_x_0(&pcm_player->fdma_params); dma_params_req(&pcm_player->fdma_params, pcm_player->fdma_request); dma_params_addrs(&pcm_player->fdma_params, runtime->dma_addr, pcm_player->fifo_phys_address, buffer_bytes); result = dma_compile_list(pcm_player->fdma_channel, &pcm_player->fdma_params, GFP_KERNEL); if (result < 0) { snd_stm_printe("Can't compile FDMA parameters for player" " '%s'!\n", dev_name(pcm_player->device)); goto error_compile_list; } return 0; error_compile_list: dma_req_free(pcm_player->fdma_channel, pcm_player->fdma_request); error_req_config: snd_stm_buffer_free(pcm_player->buffer); error_buf_alloc: return result; } static int snd_stm_pcm_player_prepare(struct snd_pcm_substream *substream) { struct snd_stm_pcm_player *pcm_player = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int format, lr_pol; int oversampling, bits_in_output_frame; int result; snd_stm_printd(1, "snd_stm_pcm_player_prepare(substream=0x%p)\n", substream); BUG_ON(!pcm_player); BUG_ON(!snd_stm_magic_valid(pcm_player)); BUG_ON(!runtime); BUG_ON(runtime->period_size * runtime->channels >= MAX_SAMPLES_PER_PERIOD); /* Configure SPDIF synchronisation */ /* TODO */ /* Get format & oversampling value from connected converter */ if (pcm_player->conv_group) { format = snd_stm_conv_get_format(pcm_player->conv_group); oversampling = snd_stm_conv_get_oversampling( pcm_player->conv_group); if (oversampling == 0) oversampling = DEFAULT_OVERSAMPLING; } else { format = DEFAULT_FORMAT; oversampling = DEFAULT_OVERSAMPLING; } snd_stm_printd(1, "Player %s: sampling frequency %d, oversampling %d\n", dev_name(pcm_player->device), runtime->rate, oversampling); BUG_ON(oversampling < 0); /* For 32 bits subframe oversampling must be a multiple of 128, * for 16 bits - of 64 */ BUG_ON((format & SND_STM_FORMAT__SUBFRAME_32_BITS) && (oversampling % 128 != 0)); BUG_ON(!(format & SND_STM_FORMAT__SUBFRAME_16_BITS) && (oversampling % 64 != 0)); /* Set up frequency synthesizer */ result = clk_enable(pcm_player->clock); if (result != 0) { snd_stm_printe("Can't enable clock for player '%s'!\n", dev_name(pcm_player->device)); return result; } result = clk_set_rate(pcm_player->clock, runtime->rate * oversampling); if (result != 0) { snd_stm_printe("Can't configure clock for player '%s'!\n", dev_name(pcm_player->device)); clk_disable(pcm_player->clock); return result; } /* Set up player hardware */ snd_stm_printd(1, "Player %s format configuration:\n", dev_name(pcm_player->device)); /* Number of bits per subframe (which is one channel sample) * on output - it determines serial clock frequency, which is * 64 times sampling rate for 32 bits subframe (2 channels 32 * bits each means 64 bits per frame) and 32 times sampling * rate for 16 bits subframe * (you know why, don't you? :-) */ switch (format & SND_STM_FORMAT__SUBFRAME_MASK) { case SND_STM_FORMAT__SUBFRAME_32_BITS: snd_stm_printd(1, "- 32 bits per subframe\n"); set__AUD_PCMOUT_FMT__NBIT__32_BITS(pcm_player); if (pcm_player->ver > 5) set__AUD_PCMOUT_FMT__DATA_SIZE__32_BITS(pcm_player); else set__AUD_PCMOUT_FMT__DATA_SIZE__24_BITS(pcm_player); bits_in_output_frame = 64; /* frame = 2 * subframe */ break; case SND_STM_FORMAT__SUBFRAME_16_BITS: snd_stm_printd(1, "- 16 bits per subframe\n"); set__AUD_PCMOUT_FMT__NBIT__16_BITS(pcm_player); set__AUD_PCMOUT_FMT__DATA_SIZE__16_BITS(pcm_player); bits_in_output_frame = 32; /* frame = 2 * subframe */ break; default: snd_BUG(); return -EINVAL; } /* Serial audio interface format - for detailed explanation * see ie.: * http://www.cirrus.com/en/pubs/appNote/AN282REV1.pdf */ set__AUD_PCMOUT_FMT__ORDER__MSB_FIRST(pcm_player); /* Value FALLING of SCLK_EDGE bit in AUD_PCMOUT_FMT register that * actually means "data clocking (changing) on the falling edge" * (and we usually want this...) - STx7100 and cuts < 3.0 of * STx7109 have this bit inverted comparing to what their * datasheets claim... (specs say 1) */ set__AUD_PCMOUT_FMT__SCLK_EDGE__FALLING(pcm_player); switch (format & SND_STM_FORMAT__MASK) { case SND_STM_FORMAT__I2S: snd_stm_printd(1, "- I2S\n"); set__AUD_PCMOUT_FMT__ALIGN__LEFT(pcm_player); set__AUD_PCMOUT_FMT__PADDING__1_CYCLE_DELAY(pcm_player); lr_pol = value__AUD_PCMOUT_FMT__LR_POL__LEFT_LOW(pcm_player); break; case SND_STM_FORMAT__LEFT_JUSTIFIED: snd_stm_printd(1, "- left justified\n"); set__AUD_PCMOUT_FMT__ALIGN__LEFT(pcm_player); set__AUD_PCMOUT_FMT__PADDING__NO_DELAY(pcm_player); lr_pol = value__AUD_PCMOUT_FMT__LR_POL__LEFT_HIGH(pcm_player); break; case SND_STM_FORMAT__RIGHT_JUSTIFIED: snd_stm_printd(1, "- right justified\n"); set__AUD_PCMOUT_FMT__ALIGN__RIGHT(pcm_player); set__AUD_PCMOUT_FMT__PADDING__NO_DELAY(pcm_player); lr_pol = value__AUD_PCMOUT_FMT__LR_POL__LEFT_HIGH(pcm_player); break; default: snd_BUG(); return -EINVAL; } /* Configure PCM player frequency divider * * Fdacclk Fs * oversampling * divider = ----------- = ------------------------------- = * 2 * Fsclk 2 * Fs * bits_in_output_frame * * oversampling * = -------------------------- * 2 * bits_in_output_frame * where: * - Fdacclk - frequency of DAC clock signal, known also as PCMCLK, * MCLK (master clock), "system clock" etc. * - Fsclk - frequency of SCLK (serial clock) aka BICK (bit clock) * - Fs - sampling rate (frequency) * - bits_in_output_frame - number of bits in output signal _frame_ * (32 or 64, depending on NBIT field of FMT register) */ set__AUD_PCMOUT_CTRL__CLK_DIV(pcm_player, oversampling / (2 * bits_in_output_frame)); /* Configure data memory format & NSAMPLE interrupt */ switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: /* One data word contains two samples */ set__AUD_PCMOUT_CTRL__MEM_FMT__16_BITS_16_BITS(pcm_player); /* Workaround for a problem with L/R channels swap in case of * 16/16 memory model: PCM player expects left channel data in * word's upper two bytes, but due to little endianess * character of our memory there is right channel data there; * the workaround is to invert L/R signal, however it is * cheating, because in such case channel phases are shifted * by one sample... * (ask me for more details if above is not clear ;-) * TODO this somehow better... */ set__AUD_PCMOUT_FMT__LR_POL(pcm_player, !lr_pol); /* One word of data is two samples (two channels...) */ set__AUD_PCMOUT_CTRL__NSAMPLE(pcm_player, runtime->period_size * runtime->channels / 2); break; case SNDRV_PCM_FORMAT_S32_LE: /* Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits * on the left than zeros (if less than 32 bites)"... ;-) */ set__AUD_PCMOUT_CTRL__MEM_FMT__16_BITS_0_BITS(pcm_player); /* In x/0 bits memory mode there is no problem with * L/R polarity */ set__AUD_PCMOUT_FMT__LR_POL(pcm_player, lr_pol); /* One word of data is one sample, so period size * times channels */ set__AUD_PCMOUT_CTRL__NSAMPLE(pcm_player, runtime->period_size * runtime->channels); break; default: snd_BUG(); return -EINVAL; } /* Number of channels... */ BUG_ON(runtime->channels % 2 != 0); BUG_ON(runtime->channels < 2); BUG_ON(runtime->channels > 10); set__AUD_PCMOUT_FMT__NUM_CH(pcm_player, runtime->channels / 2); return 0; } static int snd_stm_pcm_player_start(struct snd_pcm_substream *substream) { int result; struct snd_stm_pcm_player *pcm_player = snd_pcm_substream_chip(substream); snd_stm_printd(1, "snd_stm_pcm_player_start(substream=0x%p)\n", substream); BUG_ON(!pcm_player); BUG_ON(!snd_stm_magic_valid(pcm_player)); /* Un-reset PCM player */ set__AUD_PCMOUT_RST__SRSTP__RUNNING(pcm_player); /* Launch FDMA transfer */ result = dma_xfer_list(pcm_player->fdma_channel, &pcm_player->fdma_params); if (result != 0) { snd_stm_printe("Can't launch FDMA transfer for player '%s'!\n", dev_name(pcm_player->device)); clk_disable(pcm_player->clock); return -EINVAL; } while (dma_get_status(pcm_player->fdma_channel) != DMA_CHANNEL_STATUS_RUNNING) udelay(5); /* Enable player interrupts (and clear possible stalled ones) */ enable_irq(pcm_player->irq); set__AUD_PCMOUT_ITS_CLR__NSAMPLE__CLEAR(pcm_player); set__AUD_PCMOUT_IT_EN_SET__NSAMPLE__SET(pcm_player); set__AUD_PCMOUT_ITS_CLR__UNF__CLEAR(pcm_player); set__AUD_PCMOUT_IT_EN_SET__UNF__SET(pcm_player); /* Launch the player */ set__AUD_PCMOUT_CTRL__MODE__PCM(pcm_player); /* Wake up & unmute DAC */ if (pcm_player->conv_group) { snd_stm_conv_enable(pcm_player->conv_group, 0, substream->runtime->channels - 1); snd_stm_conv_unmute(pcm_player->conv_group); } return 0; }