Loading sound/soc/codecs/tlv320dac33.c +26 −10 Original line number Diff line number Diff line Loading @@ -58,7 +58,7 @@ (1000000000 / ((rate * 1000) / samples)) #define US_TO_SAMPLES(rate, us) \ (rate / (1000000 / us)) (rate / (1000000 / (us < 1000000 ? us : 1000000))) #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \ ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate))) Loading Loading @@ -200,7 +200,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); int val; int val, ret = 0; *value = reg & 0xff; Loading @@ -210,6 +210,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, if (val < 0) { dev_err(codec->dev, "Read failed (%d)\n", val); value[0] = dac33_read_reg_cache(codec, reg); ret = val; } else { value[0] = val; dac33_write_reg_cache(codec, reg, val); Loading @@ -218,7 +219,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, value[0] = dac33_read_reg_cache(codec, reg); } return 0; return ret; } static int dac33_write(struct snd_soc_codec *codec, unsigned int reg, Loading Loading @@ -329,13 +330,18 @@ static void dac33_init_chip(struct snd_soc_codec *codec) dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL)); } static inline void dac33_read_id(struct snd_soc_codec *codec) static inline int dac33_read_id(struct snd_soc_codec *codec) { int i, ret = 0; u8 reg; dac33_read(codec, DAC33_DEVICE_ID_MSB, ®); dac33_read(codec, DAC33_DEVICE_ID_LSB, ®); dac33_read(codec, DAC33_DEVICE_REV_ID, ®); for (i = 0; i < 3; i++) { ret = dac33_read(codec, DAC33_DEVICE_ID_MSB + i, ®); if (ret < 0) break; } return ret; } static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) Loading Loading @@ -1076,6 +1082,9 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) /* Number of samples under i2c latency */ dac33->alarm_threshold = US_TO_SAMPLES(rate, dac33->mode1_latency); nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; if (dac33->auto_fifo_config) { if (period_size <= dac33->alarm_threshold) /* Loading @@ -1086,6 +1095,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) ((dac33->alarm_threshold / period_size) + (dac33->alarm_threshold % period_size ? 1 : 0)); else if (period_size > nsample_limit) dac33->nsample = nsample_limit; else dac33->nsample = period_size; } else { Loading @@ -1097,8 +1108,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) */ dac33->nsample_max = substream->runtime->buffer_size - period_size; nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; if (dac33->nsample_max > nsample_limit) dac33->nsample_max = nsample_limit; Loading Loading @@ -1414,9 +1424,15 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) dev_err(codec->dev, "Failed to power up codec: %d\n", ret); goto err_power; } dac33_read_id(codec); ret = dac33_read_id(codec); dac33_hard_power(codec, 0); if (ret < 0) { dev_err(codec->dev, "Failed to read chip ID: %d\n", ret); ret = -ENODEV; goto err_power; } /* Check if the IRQ number is valid and request it */ if (dac33->irq >= 0) { ret = request_irq(dac33->irq, dac33_interrupt_handler, Loading sound/soc/codecs/tpa6130a2.c +3 −3 Original line number Diff line number Diff line Loading @@ -119,13 +119,13 @@ static int tpa6130a2_power(int power) { struct tpa6130a2_data *data; u8 val; int ret; int ret = 0; BUG_ON(tpa6130a2_client == NULL); data = i2c_get_clientdata(tpa6130a2_client); mutex_lock(&data->mutex); if (power) { if (power && !data->power_state) { /* Power on */ if (data->power_gpio >= 0) gpio_set_value(data->power_gpio, 1); Loading Loading @@ -153,7 +153,7 @@ static int tpa6130a2_power(int power) val = tpa6130a2_read(TPA6130A2_REG_CONTROL); val &= ~TPA6130A2_SWS; tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); } else { } else if (!power && data->power_state) { /* set SWS */ val = tpa6130a2_read(TPA6130A2_REG_CONTROL); val |= TPA6130A2_SWS; Loading sound/soc/codecs/wm8962.c +4 −1 Original line number Diff line number Diff line Loading @@ -3502,8 +3502,11 @@ static ssize_t wm8962_beep_set(struct device *dev, { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); long int time; int ret; strict_strtol(buf, 10, &time); ret = strict_strtol(buf, 10, &time); if (ret != 0) return ret; input_event(wm8962->beep, EV_SND, SND_TONE, time); Loading sound/soc/imx/eukrea-tlv320.c +4 −4 Original line number Diff line number Diff line Loading @@ -34,8 +34,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | Loading Loading @@ -79,10 +79,10 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = { static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", .codec_dai = "tlv320aic23-hifi", .codec_dai_name = "tlv320aic23-hifi", .platform_name = "imx-pcm-audio.0", .codec_name = "tlv320aic23-codec.0-001a", .cpu_dai = "imx-ssi.0", .cpu_dai_name = "imx-ssi.0", .ops = &eukrea_tlv320_snd_ops, }; Loading sound/soc/imx/imx-pcm-dma-mx2.c +98 −123 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/dmaengine.h> #include <sound/core.h> #include <sound/initval.h> Loading @@ -27,165 +28,146 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <mach/dma-mx1-mx2.h> #include <mach/dma.h> #include "imx-ssi.h" struct imx_pcm_runtime_data { int sg_count; struct scatterlist *sg_list; int period; int period_bytes; int periods; unsigned long dma_addr; int dma; struct snd_pcm_substream *substream; unsigned long offset; unsigned long size; unsigned long period_cnt; void *buf; int period_time; struct dma_async_tx_descriptor *desc; struct dma_chan *dma_chan; struct imx_dma_data dma_data; }; /* Called by the DMA framework when a period has elapsed */ static void imx_ssi_dma_progression(int channel, void *data, struct scatterlist *sg) static void audio_dma_irq(void *data) { struct snd_pcm_substream *substream = data; struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; if (!sg) return; runtime = iprtd->substream->runtime; iprtd->offset += iprtd->period_bytes; iprtd->offset %= iprtd->period_bytes * iprtd->periods; iprtd->offset = sg->dma_address - runtime->dma_addr; snd_pcm_period_elapsed(iprtd->substream); snd_pcm_period_elapsed(substream); } static void imx_ssi_dma_callback(int channel, void *data) static bool filter(struct dma_chan *chan, void *param) { pr_err("%s shouldn't be called\n", __func__); } struct imx_pcm_runtime_data *iprtd = param; static void snd_imx_dma_err_callback(int channel, void *data, int err) { struct snd_pcm_substream *substream = data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; int ret; if (!imx_dma_is_general_purpose(chan)) return false; pr_err("DMA timeout on channel %d -%s%s%s%s\n", channel, err & IMX_DMA_ERR_BURST ? " burst" : "", err & IMX_DMA_ERR_REQUEST ? " request" : "", err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); chan->private = &iprtd->dma_data; imx_dma_disable(iprtd->dma); ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MODE_WRITE : DMA_MODE_READ); if (!ret) imx_dma_enable(iprtd->dma); return true; } static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; struct dma_slave_config slave_config; dma_cap_mask_t mask; enum dma_slave_buswidth buswidth; int ret; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); if (iprtd->dma < 0) { pr_err("Failed to claim the audio DMA\n"); return -ENODEV; } iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI; iprtd->dma_data.priority = DMA_PRIO_HIGH; iprtd->dma_data.dma_request = dma_params->dma; ret = imx_dma_setup_handlers(iprtd->dma, imx_ssi_dma_callback, snd_imx_dma_err_callback, substream); if (ret) goto out; /* Try to grab a DMA channel */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); if (!iprtd->dma_chan) return -EINVAL; ret = imx_dma_setup_progression_handler(iprtd->dma, imx_ssi_dma_progression); if (ret) { pr_err("Failed to setup the DMA handler\n"); goto out; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; break; case SNDRV_PCM_FORMAT_S20_3LE: case SNDRV_PCM_FORMAT_S24_LE: buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; break; default: return 0; } ret = imx_dma_config_channel(iprtd->dma, IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, dma_params->dma, 1); if (ret < 0) { pr_err("Cannot configure DMA channel: %d\n", ret); goto out; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { slave_config.direction = DMA_TO_DEVICE; slave_config.dst_addr = dma_params->dma_addr; slave_config.dst_addr_width = buswidth; slave_config.dst_maxburst = dma_params->burstsize; } else { slave_config.direction = DMA_FROM_DEVICE; slave_config.src_addr = dma_params->dma_addr; slave_config.src_addr_width = buswidth; slave_config.src_maxburst = dma_params->burstsize; } imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2); ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config); if (ret) return ret; return 0; out: imx_dma_free(iprtd->dma); return ret; } static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; int i; unsigned long dma_addr; struct dma_chan *chan; struct imx_pcm_dma_params *dma_params; int ret; imx_ssi_dma_alloc(substream); dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ret = imx_ssi_dma_alloc(substream, params); if (ret) return ret; chan = iprtd->dma_chan; iprtd->size = params_buffer_bytes(params); iprtd->periods = params_periods(params); iprtd->period = params_period_bytes(params); iprtd->period_bytes = params_period_bytes(params); iprtd->offset = 0; iprtd->period_time = HZ / (params_rate(params) / params_period_size(params)); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); if (iprtd->sg_count != iprtd->periods) { kfree(iprtd->sg_list); iprtd->sg_list = kcalloc(iprtd->periods + 1, sizeof(struct scatterlist), GFP_KERNEL); if (!iprtd->sg_list) return -ENOMEM; iprtd->sg_count = iprtd->periods + 1; } sg_init_table(iprtd->sg_list, iprtd->sg_count); dma_addr = runtime->dma_addr; for (i = 0; i < iprtd->periods; i++) { iprtd->sg_list[i].page_link = 0; iprtd->sg_list[i].offset = 0; iprtd->sg_list[i].dma_address = dma_addr; iprtd->sg_list[i].length = iprtd->period; dma_addr += iprtd->period; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, iprtd->period_bytes * iprtd->periods, iprtd->period_bytes, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (!iprtd->desc) { dev_err(&chan->dev->device, "cannot prepare slave dma\n"); return -EINVAL; } /* close the loop */ iprtd->sg_list[iprtd->sg_count - 1].offset = 0; iprtd->sg_list[iprtd->sg_count - 1].length = 0; iprtd->sg_list[iprtd->sg_count - 1].page_link = ((unsigned long) iprtd->sg_list | 0x01) & ~0x02; iprtd->desc->callback = audio_dma_irq; iprtd->desc->callback_param = substream; return 0; } Loading @@ -194,41 +176,21 @@ static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; if (iprtd->dma >= 0) { imx_dma_free(iprtd->dma); iprtd->dma = -EINVAL; if (iprtd->dma_chan) { dma_release_channel(iprtd->dma_chan); iprtd->dma_chan = NULL; } kfree(iprtd->sg_list); iprtd->sg_list = NULL; return 0; } static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; struct imx_pcm_runtime_data *iprtd = runtime->private_data; int err; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); iprtd->substream = substream; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->period_cnt = 0; pr_debug("%s: buf: %p period: %d periods: %d\n", __func__, iprtd->buf, iprtd->period, iprtd->periods); err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MODE_WRITE : DMA_MODE_READ); if (err) return err; return 0; } Loading @@ -241,14 +203,14 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: imx_dma_enable(iprtd->dma); dmaengine_submit(iprtd->desc); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: imx_dma_disable(iprtd->dma); dmaengine_terminate_all(iprtd->dma_chan); break; default: Loading @@ -263,6 +225,9 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; pr_debug("%s: %ld %ld\n", __func__, iprtd->offset, bytes_to_frames(substream->runtime, iprtd->offset)); return bytes_to_frames(substream->runtime, iprtd->offset); } Loading @@ -279,7 +244,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { .channels_max = 2, .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 16 * 1024, .period_bytes_max = 65535, /* Limited by SDMA engine */ .periods_min = 2, .periods_max = 255, .fifo_size = 0, Loading @@ -304,11 +269,23 @@ static int snd_imx_open(struct snd_pcm_substream *substream) } snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); return 0; } static int snd_imx_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; kfree(iprtd); return 0; } static struct snd_pcm_ops imx_pcm_ops = { .open = snd_imx_open, .close = snd_imx_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, .hw_free = snd_imx_pcm_hw_free, Loading Loading @@ -340,7 +317,6 @@ static struct platform_driver imx_pcm_driver = { .name = "imx-pcm-audio", .owner = THIS_MODULE, }, .probe = imx_soc_platform_probe, .remove = __devexit_p(imx_soc_platform_remove), }; Loading @@ -356,4 +332,3 @@ static void __exit snd_imx_pcm_exit(void) platform_driver_unregister(&imx_pcm_driver); } module_exit(snd_imx_pcm_exit); Loading
sound/soc/codecs/tlv320dac33.c +26 −10 Original line number Diff line number Diff line Loading @@ -58,7 +58,7 @@ (1000000000 / ((rate * 1000) / samples)) #define US_TO_SAMPLES(rate, us) \ (rate / (1000000 / us)) (rate / (1000000 / (us < 1000000 ? us : 1000000))) #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \ ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate))) Loading Loading @@ -200,7 +200,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); int val; int val, ret = 0; *value = reg & 0xff; Loading @@ -210,6 +210,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, if (val < 0) { dev_err(codec->dev, "Read failed (%d)\n", val); value[0] = dac33_read_reg_cache(codec, reg); ret = val; } else { value[0] = val; dac33_write_reg_cache(codec, reg, val); Loading @@ -218,7 +219,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, value[0] = dac33_read_reg_cache(codec, reg); } return 0; return ret; } static int dac33_write(struct snd_soc_codec *codec, unsigned int reg, Loading Loading @@ -329,13 +330,18 @@ static void dac33_init_chip(struct snd_soc_codec *codec) dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL)); } static inline void dac33_read_id(struct snd_soc_codec *codec) static inline int dac33_read_id(struct snd_soc_codec *codec) { int i, ret = 0; u8 reg; dac33_read(codec, DAC33_DEVICE_ID_MSB, ®); dac33_read(codec, DAC33_DEVICE_ID_LSB, ®); dac33_read(codec, DAC33_DEVICE_REV_ID, ®); for (i = 0; i < 3; i++) { ret = dac33_read(codec, DAC33_DEVICE_ID_MSB + i, ®); if (ret < 0) break; } return ret; } static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) Loading Loading @@ -1076,6 +1082,9 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) /* Number of samples under i2c latency */ dac33->alarm_threshold = US_TO_SAMPLES(rate, dac33->mode1_latency); nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; if (dac33->auto_fifo_config) { if (period_size <= dac33->alarm_threshold) /* Loading @@ -1086,6 +1095,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) ((dac33->alarm_threshold / period_size) + (dac33->alarm_threshold % period_size ? 1 : 0)); else if (period_size > nsample_limit) dac33->nsample = nsample_limit; else dac33->nsample = period_size; } else { Loading @@ -1097,8 +1108,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) */ dac33->nsample_max = substream->runtime->buffer_size - period_size; nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; if (dac33->nsample_max > nsample_limit) dac33->nsample_max = nsample_limit; Loading Loading @@ -1414,9 +1424,15 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) dev_err(codec->dev, "Failed to power up codec: %d\n", ret); goto err_power; } dac33_read_id(codec); ret = dac33_read_id(codec); dac33_hard_power(codec, 0); if (ret < 0) { dev_err(codec->dev, "Failed to read chip ID: %d\n", ret); ret = -ENODEV; goto err_power; } /* Check if the IRQ number is valid and request it */ if (dac33->irq >= 0) { ret = request_irq(dac33->irq, dac33_interrupt_handler, Loading
sound/soc/codecs/tpa6130a2.c +3 −3 Original line number Diff line number Diff line Loading @@ -119,13 +119,13 @@ static int tpa6130a2_power(int power) { struct tpa6130a2_data *data; u8 val; int ret; int ret = 0; BUG_ON(tpa6130a2_client == NULL); data = i2c_get_clientdata(tpa6130a2_client); mutex_lock(&data->mutex); if (power) { if (power && !data->power_state) { /* Power on */ if (data->power_gpio >= 0) gpio_set_value(data->power_gpio, 1); Loading Loading @@ -153,7 +153,7 @@ static int tpa6130a2_power(int power) val = tpa6130a2_read(TPA6130A2_REG_CONTROL); val &= ~TPA6130A2_SWS; tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); } else { } else if (!power && data->power_state) { /* set SWS */ val = tpa6130a2_read(TPA6130A2_REG_CONTROL); val |= TPA6130A2_SWS; Loading
sound/soc/codecs/wm8962.c +4 −1 Original line number Diff line number Diff line Loading @@ -3502,8 +3502,11 @@ static ssize_t wm8962_beep_set(struct device *dev, { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); long int time; int ret; strict_strtol(buf, 10, &time); ret = strict_strtol(buf, 10, &time); if (ret != 0) return ret; input_event(wm8962->beep, EV_SND, SND_TONE, time); Loading
sound/soc/imx/eukrea-tlv320.c +4 −4 Original line number Diff line number Diff line Loading @@ -34,8 +34,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | Loading Loading @@ -79,10 +79,10 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = { static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", .codec_dai = "tlv320aic23-hifi", .codec_dai_name = "tlv320aic23-hifi", .platform_name = "imx-pcm-audio.0", .codec_name = "tlv320aic23-codec.0-001a", .cpu_dai = "imx-ssi.0", .cpu_dai_name = "imx-ssi.0", .ops = &eukrea_tlv320_snd_ops, }; Loading
sound/soc/imx/imx-pcm-dma-mx2.c +98 −123 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/dmaengine.h> #include <sound/core.h> #include <sound/initval.h> Loading @@ -27,165 +28,146 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <mach/dma-mx1-mx2.h> #include <mach/dma.h> #include "imx-ssi.h" struct imx_pcm_runtime_data { int sg_count; struct scatterlist *sg_list; int period; int period_bytes; int periods; unsigned long dma_addr; int dma; struct snd_pcm_substream *substream; unsigned long offset; unsigned long size; unsigned long period_cnt; void *buf; int period_time; struct dma_async_tx_descriptor *desc; struct dma_chan *dma_chan; struct imx_dma_data dma_data; }; /* Called by the DMA framework when a period has elapsed */ static void imx_ssi_dma_progression(int channel, void *data, struct scatterlist *sg) static void audio_dma_irq(void *data) { struct snd_pcm_substream *substream = data; struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; if (!sg) return; runtime = iprtd->substream->runtime; iprtd->offset += iprtd->period_bytes; iprtd->offset %= iprtd->period_bytes * iprtd->periods; iprtd->offset = sg->dma_address - runtime->dma_addr; snd_pcm_period_elapsed(iprtd->substream); snd_pcm_period_elapsed(substream); } static void imx_ssi_dma_callback(int channel, void *data) static bool filter(struct dma_chan *chan, void *param) { pr_err("%s shouldn't be called\n", __func__); } struct imx_pcm_runtime_data *iprtd = param; static void snd_imx_dma_err_callback(int channel, void *data, int err) { struct snd_pcm_substream *substream = data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; int ret; if (!imx_dma_is_general_purpose(chan)) return false; pr_err("DMA timeout on channel %d -%s%s%s%s\n", channel, err & IMX_DMA_ERR_BURST ? " burst" : "", err & IMX_DMA_ERR_REQUEST ? " request" : "", err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); chan->private = &iprtd->dma_data; imx_dma_disable(iprtd->dma); ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MODE_WRITE : DMA_MODE_READ); if (!ret) imx_dma_enable(iprtd->dma); return true; } static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; struct dma_slave_config slave_config; dma_cap_mask_t mask; enum dma_slave_buswidth buswidth; int ret; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); if (iprtd->dma < 0) { pr_err("Failed to claim the audio DMA\n"); return -ENODEV; } iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI; iprtd->dma_data.priority = DMA_PRIO_HIGH; iprtd->dma_data.dma_request = dma_params->dma; ret = imx_dma_setup_handlers(iprtd->dma, imx_ssi_dma_callback, snd_imx_dma_err_callback, substream); if (ret) goto out; /* Try to grab a DMA channel */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); if (!iprtd->dma_chan) return -EINVAL; ret = imx_dma_setup_progression_handler(iprtd->dma, imx_ssi_dma_progression); if (ret) { pr_err("Failed to setup the DMA handler\n"); goto out; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; break; case SNDRV_PCM_FORMAT_S20_3LE: case SNDRV_PCM_FORMAT_S24_LE: buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; break; default: return 0; } ret = imx_dma_config_channel(iprtd->dma, IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, dma_params->dma, 1); if (ret < 0) { pr_err("Cannot configure DMA channel: %d\n", ret); goto out; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { slave_config.direction = DMA_TO_DEVICE; slave_config.dst_addr = dma_params->dma_addr; slave_config.dst_addr_width = buswidth; slave_config.dst_maxburst = dma_params->burstsize; } else { slave_config.direction = DMA_FROM_DEVICE; slave_config.src_addr = dma_params->dma_addr; slave_config.src_addr_width = buswidth; slave_config.src_maxburst = dma_params->burstsize; } imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2); ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config); if (ret) return ret; return 0; out: imx_dma_free(iprtd->dma); return ret; } static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; int i; unsigned long dma_addr; struct dma_chan *chan; struct imx_pcm_dma_params *dma_params; int ret; imx_ssi_dma_alloc(substream); dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ret = imx_ssi_dma_alloc(substream, params); if (ret) return ret; chan = iprtd->dma_chan; iprtd->size = params_buffer_bytes(params); iprtd->periods = params_periods(params); iprtd->period = params_period_bytes(params); iprtd->period_bytes = params_period_bytes(params); iprtd->offset = 0; iprtd->period_time = HZ / (params_rate(params) / params_period_size(params)); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); if (iprtd->sg_count != iprtd->periods) { kfree(iprtd->sg_list); iprtd->sg_list = kcalloc(iprtd->periods + 1, sizeof(struct scatterlist), GFP_KERNEL); if (!iprtd->sg_list) return -ENOMEM; iprtd->sg_count = iprtd->periods + 1; } sg_init_table(iprtd->sg_list, iprtd->sg_count); dma_addr = runtime->dma_addr; for (i = 0; i < iprtd->periods; i++) { iprtd->sg_list[i].page_link = 0; iprtd->sg_list[i].offset = 0; iprtd->sg_list[i].dma_address = dma_addr; iprtd->sg_list[i].length = iprtd->period; dma_addr += iprtd->period; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, iprtd->period_bytes * iprtd->periods, iprtd->period_bytes, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (!iprtd->desc) { dev_err(&chan->dev->device, "cannot prepare slave dma\n"); return -EINVAL; } /* close the loop */ iprtd->sg_list[iprtd->sg_count - 1].offset = 0; iprtd->sg_list[iprtd->sg_count - 1].length = 0; iprtd->sg_list[iprtd->sg_count - 1].page_link = ((unsigned long) iprtd->sg_list | 0x01) & ~0x02; iprtd->desc->callback = audio_dma_irq; iprtd->desc->callback_param = substream; return 0; } Loading @@ -194,41 +176,21 @@ static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; if (iprtd->dma >= 0) { imx_dma_free(iprtd->dma); iprtd->dma = -EINVAL; if (iprtd->dma_chan) { dma_release_channel(iprtd->dma_chan); iprtd->dma_chan = NULL; } kfree(iprtd->sg_list); iprtd->sg_list = NULL; return 0; } static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; struct imx_pcm_runtime_data *iprtd = runtime->private_data; int err; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); iprtd->substream = substream; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->period_cnt = 0; pr_debug("%s: buf: %p period: %d periods: %d\n", __func__, iprtd->buf, iprtd->period, iprtd->periods); err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MODE_WRITE : DMA_MODE_READ); if (err) return err; return 0; } Loading @@ -241,14 +203,14 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: imx_dma_enable(iprtd->dma); dmaengine_submit(iprtd->desc); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: imx_dma_disable(iprtd->dma); dmaengine_terminate_all(iprtd->dma_chan); break; default: Loading @@ -263,6 +225,9 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; pr_debug("%s: %ld %ld\n", __func__, iprtd->offset, bytes_to_frames(substream->runtime, iprtd->offset)); return bytes_to_frames(substream->runtime, iprtd->offset); } Loading @@ -279,7 +244,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { .channels_max = 2, .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 16 * 1024, .period_bytes_max = 65535, /* Limited by SDMA engine */ .periods_min = 2, .periods_max = 255, .fifo_size = 0, Loading @@ -304,11 +269,23 @@ static int snd_imx_open(struct snd_pcm_substream *substream) } snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); return 0; } static int snd_imx_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; kfree(iprtd); return 0; } static struct snd_pcm_ops imx_pcm_ops = { .open = snd_imx_open, .close = snd_imx_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, .hw_free = snd_imx_pcm_hw_free, Loading Loading @@ -340,7 +317,6 @@ static struct platform_driver imx_pcm_driver = { .name = "imx-pcm-audio", .owner = THIS_MODULE, }, .probe = imx_soc_platform_probe, .remove = __devexit_p(imx_soc_platform_remove), }; Loading @@ -356,4 +332,3 @@ static void __exit snd_imx_pcm_exit(void) platform_driver_unregister(&imx_pcm_driver); } module_exit(snd_imx_pcm_exit);