staticvoid mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
{ int i = 0;
mcasp_set_bits(mcasp, ctl_reg, val);
/* programming GBLCTL needs to read back from GBLCTL and verfiy */ /* loop count is to avoid the lock-up */ for (i = 0; i < 1000; i++) { if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val) break;
}
if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
printk(KERN_ERR "GBLCTL write error\n");
}
/* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); /* * When ASYNC == 0 the transmit and receive sections operate * synchronously from the transmit clock and frame sync. We need to make * sure that the TX signlas are enabled when starting reception.
*/ if (mcasp_is_synchronous(mcasp)) {
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
mcasp_set_clk_pdir(mcasp, true);
}
/* * In synchronous mode stop the TX clocks if no other stream is * running
*/ if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
mcasp_set_clk_pdir(mcasp, false);
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
}
/* * In synchronous mode keep TX clocks running if the capture stream is * still running.
*/ if (mcasp_is_synchronous(mcasp) && mcasp->streams)
val = TXHCLKRST | TXCLKRST | TXFSRST; else
mcasp_set_clk_pdir(mcasp, false);
pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); /* 1st data bit occur one ACLK cycle after the frame sync */
data_delay = 1; break; case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); /* No delay after FS */
data_delay = 0; break; case SND_SOC_DAIFMT_I2S: /* configure a full-word SYNC pulse (LRCLK) */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); /* 1st data bit occur one ACLK cycle after the frame sync */
data_delay = 1; /* FS need to be inverted */
inv_fs = true; break; case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_LEFT_J: /* configure a full-word SYNC pulse (LRCLK) */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); /* No delay after FS */
data_delay = 0; break; default:
ret = -EINVAL; goto out;
}
case MCASP_CLKDIV_BCLK_FS_RATIO: /* * BCLK/LRCLK ratio descries how many bit-clock cycles * fit into one frame. The clock ratio is given for a * full period of data (for I2S format both left and * right channels), so it has to be divided by number * of tdm-slots (for I2S - divided by 2). * Instead of storing this ratio, we calculate a new * tdm_slot width by dividing the ratio by the * number of configured tdm slots.
*/
mcasp->slot_width = div / mcasp->tdm_slots; if (div % mcasp->tdm_slots)
dev_warn(mcasp->dev, "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
__func__, div, mcasp->tdm_slots); break;
default: return -EINVAL;
}
pm_runtime_put(mcasp->dev); return 0;
}
staticint davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
{ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
staticint davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsignedint freq, int dir)
{ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
pm_runtime_get_sync(mcasp->dev);
if (dir == SND_SOC_CLOCK_IN) { switch (clk_id) { case MCASP_CLK_HCLK_AHCLK:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
AHCLKXE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKRE);
clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir); break; case MCASP_CLK_HCLK_AUXCLK:
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
AHCLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKRE);
set_bit(PIN_BIT_AHCLKX, &mcasp->pdir); break; default:
dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id); goto out;
}
} else { /* Select AUXCLK as HCLK */
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
} /* * When AHCLK X/R is selected to be output it means that the HCLK is * the same clock - coming via AUXCLK.
*/
mcasp->sysclk_freq = freq;
out:
pm_runtime_put(mcasp->dev); return 0;
}
/* All serializers must have equal number of channels */ staticint davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream, int serializers)
{ struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream]; unsignedint *list = (unsignedint *) cl->list; int slots = mcasp->tdm_slots; int i, count = 0;
if (mcasp->tdm_mask[stream])
slots = hweight32(mcasp->tdm_mask[stream]);
for (i = 1; i <= slots; i++)
list[count++] = i;
for (i = 2; i <= serializers; i++)
list[count++] = i*slots;
for (i = 0; i < mcasp->num_serializer; i++) if (mcasp->serial_dir[i] == TX_MODE)
tx_serializers++; elseif (mcasp->serial_dir[i] == RX_MODE)
rx_serializers++;
ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
tx_serializers); if (ret) return ret;
ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
rx_serializers);
return ret;
}
staticint davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, unsignedint tx_mask, unsignedint rx_mask, int slots, int slot_width)
{ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return 0;
/* mapping of the XSSZ bit-field as described in the datasheet */
fmt = (slot_width >> 1) - 1;
if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
RXSSZ(0x0F));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
TXSSZ(0x0F));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
TXROT(7));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
RXROT(7));
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
} else { /* * according to the TRM it should be TXROT=0, this one works: * 16 bit to 23-8 (TXROT=6, rotate 24 bits) * 24 bit to 23-0 (TXROT=0, rotate 0 bits) * * TXROT = 0 only works with 24bit samples
*/
tx_rotate = (sample_width / 4 + 2) & 0x7;
staticint mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, int period_words, int channels)
{ struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; int i;
u8 tx_ser = 0;
u8 rx_ser = 0;
u8 slots = mcasp->tdm_slots;
u8 max_active_serializers, max_rx_serializers, max_tx_serializers; int active_serializers, numevt;
u32 reg;
/* In DIT mode we only allow maximum of one serializers for now */ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
max_active_serializers = 1; else
max_active_serializers = DIV_ROUND_UP(channels, slots);
if (active_serializers < max_active_serializers) {
dev_warn(mcasp->dev, "stream has more channels (%d) than are " "enabled in mcasp (%d)\n", channels,
active_serializers * slots); return -EINVAL;
}
/* AFIFO is not in use */ if (!numevt) { /* Configure the burst size for platform drivers */ if (active_serializers > 1) { /* * If more than one serializers are in use we have one * DMA request to provide data for all serializers. * For example if three serializers are enabled the DMA * need to transfer three words per DMA request.
*/
dma_data->maxburst = active_serializers;
} else {
dma_data->maxburst = 0;
}
goto out;
}
if (period_words % active_serializers) {
dev_err(mcasp->dev, "Invalid combination of period words and " "active serializers: %d, %d\n", period_words,
active_serializers); return -EINVAL;
}
/* * Calculate the optimal AFIFO depth for platform side: * The number of words for numevt need to be in steps of active * serializers.
*/
numevt = (numevt / active_serializers) * active_serializers;
while (period_words % numevt && numevt > 0)
numevt -= active_serializers; if (numevt <= 0)
numevt = active_serializers;
staticint mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, int channels)
{ int i, active_slots; int total_slots; int active_serializers;
u32 mask = 0;
u32 busel = 0;
total_slots = mcasp->tdm_slots;
/* * If more than one serializer is needed, then use them with * all the specified tdm_slots. Otherwise, one serializer can * cope with the transaction using just as many slots as there * are channels in the stream.
*/ if (mcasp->tdm_mask[stream]) {
active_slots = hweight32(mcasp->tdm_mask[stream]);
active_serializers = DIV_ROUND_UP(channels, active_slots); if (active_serializers == 1)
active_slots = channels; for (i = 0; i < total_slots; i++) { if ((1 << i) & mcasp->tdm_mask[stream]) {
mask |= (1 << i); if (--active_slots <= 0) break;
}
}
} else {
active_serializers = DIV_ROUND_UP(channels, total_slots); if (active_serializers == 1)
active_slots = channels; else
active_slots = total_slots;
for (i = 0; i < active_slots; i++)
mask |= (1 << i);
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
FSXMOD(total_slots), FSXMOD(0x1FF));
} elseif (stream == SNDRV_PCM_STREAM_CAPTURE) {
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
FSRMOD(total_slots), FSRMOD(0x1FF)); /* * If McASP is set to be TX/RX synchronous and the playback is * not running already we need to configure the TX slots in * order to have correct FSX on the bus
*/ if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
FSXMOD(total_slots), FSXMOD(0x1FF));
}
/* * Divide the used locations with the channel count to get the * FIFO usage in samples (don't care about partial samples in the * buffer).
*/ return fifo_use / substream->runtime->channels;
}
staticint davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai)
{ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); int word_length; int channels = params_channels(params); int period_size = params_period_size(params); int ret;
switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8:
word_length = 8; break;
case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE:
word_length = 16; break;
case SNDRV_PCM_FORMAT_U24_3LE: case SNDRV_PCM_FORMAT_S24_3LE:
word_length = 24; break;
case SNDRV_PCM_FORMAT_U24_LE: case SNDRV_PCM_FORMAT_S24_LE:
word_length = 24; break;
case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE:
word_length = 32; break;
ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); if (ret) return ret;
/* * If mcasp is BCLK master, and a BCLK divider was not provided by * the machine driver, we need to calculate the ratio.
*/ if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { int slots = mcasp->tdm_slots; int rate = params_rate(params); int sbits = params_width(params); unsignedint bclk_target;
ret = mcasp_common_hw_param(mcasp, substream->stream,
period_size * channels, channels); if (ret) return ret;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
ret = mcasp_dit_hw_param(mcasp, params_rate(params)); else
ret = mcasp_i2s_hw_param(mcasp, substream->stream,
channels);
if (ret) return ret;
davinci_config_channel_size(mcasp, word_length);
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
mcasp->channels = channels; if (!mcasp->max_format_width)
mcasp->max_format_width = word_length;
}
return 0;
}
staticint davinci_mcasp_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai)
{ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); int ret = 0;
switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
davinci_mcasp_start(mcasp, substream->stream); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
davinci_mcasp_stop(mcasp, substream->stream); break;
if (rd->mcasp->slot_width)
sbits = rd->mcasp->slot_width;
snd_interval_any(&range);
range.empty = 1;
for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) { if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
uint bclk_freq = sbits * slots *
davinci_mcasp_dai_rates[i]; unsignedint sysclk_freq; int ppm;
/* Do not allow more then one stream per direction */ if (mcasp->substreams[substream->stream]) return -EBUSY;
mcasp->substreams[substream->stream] = substream;
if (mcasp->tdm_mask[substream->stream])
tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return 0;
/* * Limit the maximum allowed channels for the first stream: * number of serializers for the direction * tdm slots per serializer
*/ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = TX_MODE; else
dir = RX_MODE;
for (i = 0; i < mcasp->num_serializer; i++) { if (mcasp->serial_dir[i] == dir)
max_channels++;
}
ruledata->serializers = max_channels;
ruledata->mcasp = mcasp;
max_channels *= tdm_slots; /* * If the already active stream has less channels than the calculated * limit based on the seirializers * tdm_slots, and only one serializer * is in use we need to use that as a constraint for the second stream. * Otherwise (first stream or less allowed channels or more than one * serializer in use) we use the calculated constraint.
*/ if (mcasp->channels && mcasp->channels < max_channels &&
ruledata->serializers == 1)
max_channels = mcasp->channels; /* * But we can always allow channels upto the amount of * the available tdm_slots.
*/ if (max_channels < tdm_slots)
max_channels = tdm_slots;
if (mcasp->max_format_width) { /* * Only allow formats which require same amount of bits on the * bus as the currently running stream
*/
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
davinci_mcasp_hw_rule_format_width,
ruledata,
SNDRV_PCM_HW_PARAM_FORMAT, -1); if (ret) return ret;
} elseif (mcasp->slot_width) { /* Only allow formats require <= slot_width bits on the bus */
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
davinci_mcasp_hw_rule_slot_width,
ruledata,
SNDRV_PCM_HW_PARAM_FORMAT, -1); if (ret) return ret;
}
/* * If we rely on implicit BCLK divider setting we should * set constraints based on what we can provide.
*/ if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
davinci_mcasp_hw_rule_rate,
ruledata,
SNDRV_PCM_HW_PARAM_FORMAT, -1); if (ret) return ret;
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
davinci_mcasp_hw_rule_format,
ruledata,
SNDRV_PCM_HW_PARAM_RATE, -1); if (ret) return ret;
}
/* Some HW specific values and defaults. The rest is filled in from DT. */ staticstruct davinci_mcasp_pdata dm646x_mcasp_pdata = {
.tx_dma_offset = 0x400,
.rx_dma_offset = 0x400,
.version = MCASP_VERSION_1,
};
staticstruct davinci_mcasp_pdata dra7_mcasp_pdata = { /* The CFG port offset will be calculated if it is needed */
.tx_dma_offset = 0,
.rx_dma_offset = 0,
.version = MCASP_VERSION_4,
};
parent_name = of_get_property(node, "fck_parent", NULL); if (!parent_name) return 0;
dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n");
gfclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(gfclk)) {
dev_err(&pdev->dev, "failed to get fck\n"); return PTR_ERR(gfclk);
}
parent_clk = clk_get(NULL, parent_name); if (IS_ERR(parent_clk)) {
dev_err(&pdev->dev, "failed to get parent clock\n");
ret = PTR_ERR(parent_clk); goto err1;
}
ret = clk_set_parent(gfclk, parent_clk); if (ret) {
dev_err(&pdev->dev, "failed to reparent fck\n"); goto err2;
}
if (of_property_read_u32(np, "tdm-slots", &val) == 0) { if (val < 2 || val > 32) {
dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n"); return -EINVAL;
}
if (chan->device->dev->of_node)
ret = of_property_read_string(chan->device->dev->of_node, "compatible", &tmp); else
dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
if (pdata->version != MCASP_VERSION_4) return pdata->tx_dma_offset;
for (i = 0; i < pdata->num_serializer; i++) { if (pdata->serial_dir[i] == TX_MODE) { if (!offset) {
offset = DAVINCI_MCASP_TXBUF_REG(i);
} else {
pr_err("%s: Only one serializer allowed!\n",
__func__); break;
}
}
}
if (pdata->version != MCASP_VERSION_4) return pdata->rx_dma_offset;
for (i = 0; i < pdata->num_serializer; i++) { if (pdata->serial_dir[i] == RX_MODE) { if (!offset) {
offset = DAVINCI_MCASP_RXBUF_REG(i);
} else {
pr_err("%s: Only one serializer allowed!\n",
__func__); break;
}
}
}
if (value)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); else
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); if (!(val & BIT(offset))) { /* Set the pin as GPIO pin */
mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
/* Set the direction to output */
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
}
val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); if (!(val & BIT(offset))) { /* Set the direction to input */
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
/* Set the pin as GPIO pin */
mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
}
if (!pdev->dev.platform_data && !pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform data supplied\n"); return -EINVAL;
}
mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
GFP_KERNEL); if (!mcasp) return -ENOMEM;
mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!mem) {
dev_warn(&pdev->dev, "\"mpu\" mem resource not found, using index 0\n");
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n"); return -ENODEV;
}
}
mcasp->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(mcasp->base)) return PTR_ERR(mcasp->base);
dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); if (dat)
mcasp->dat_port = true;
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dma_data->filter_data = "tx"; if (dat) {
dma_data->addr = dat->start; /* * According to the TRM there should be 0x200 offset added to * the DAT port address
*/ if (mcasp->version == MCASP_VERSION_OMAP)
dma_data->addr += davinci_mcasp_txdma_offset(mcasp->pdata);
} else {
dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
}
/* RX is not valid in DIT mode */ if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
dma_data->filter_data = "rx"; if (dat)
dma_data->addr = dat->start; else
dma_data->addr =
mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
}
if (mcasp->version < MCASP_VERSION_3) {
mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; /* dma_params->dma_addr is pointing to the data port address */
mcasp->dat_port = true;
} else {
mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
}
/* Allocate memory for long enough list for all possible * scenarios. Maximum number tdm slots is 32 and there cannot * be more serializers than given in the configuration. The * serializer directions could be taken into account, but it * would make code much more complex and save only couple of * bytes.
*/
mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
devm_kcalloc(mcasp->dev,
32 + mcasp->num_serializer - 1, sizeof(unsignedint),
GFP_KERNEL);
if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
!mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
ret = -ENOMEM; goto err;
}
ret = davinci_mcasp_set_ch_constraints(mcasp); if (ret) goto err;
mcasp_reparent_fck(pdev);
ret = davinci_mcasp_get_dma_type(mcasp); switch (ret) { case PCM_EDMA:
ret = edma_pcm_platform_register(&pdev->dev); break; case PCM_SDMA: if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx"); else
ret = sdma_pcm_platform_register(&pdev->dev, "tx", NULL); break; case PCM_UDMA:
ret = udma_pcm_platform_register(&pdev->dev); break; default:
dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
fallthrough; case -EPROBE_DEFER: goto err;
}
if (ret) {
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.