diff options
Diffstat (limited to 'sound/soc/ux500/ux500_msp_dai.c')
| -rw-r--r-- | sound/soc/ux500/ux500_msp_dai.c | 233 |
1 files changed, 82 insertions, 151 deletions
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index c6fb5cce980e..7798957c6504 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2012 * * Author: Ola Lilja <ola.o.lilja@stericsson.com>, * Roger Nilsson <roger.xr.nilsson@stericsson.com> * for ST-Ericsson. - * - * 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 <linux/module.h> @@ -17,12 +12,13 @@ #include <linux/bitops.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/mfd/dbx500-prcmu.h> -#include <linux/platform_data/asoc-ux500-msp.h> #include <sound/soc.h> #include <sound/soc-dai.h> +#include <sound/dmaengine_pcm.h> #include "ux500_msp_i2s.h" #include "ux500_msp_dai.h" @@ -131,6 +127,7 @@ static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate, struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); u32 frame_length = MSP_FRAME_LEN_1; + prot_desc->frame_width = 0; switch (drvdata->slots) { @@ -185,14 +182,14 @@ static int setup_clocking(struct snd_soc_dai *dai, default: dev_err(dai->dev, - "%s: Error: Unsopported inversion (fmt = 0x%x)!\n", + "%s: Error: Unsupported inversion (fmt = 0x%x)!\n", __func__, fmt); return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: dev_dbg(dai->dev, "%s: Codec is master.\n", __func__); msp_config->iodelay = 0x20; @@ -204,7 +201,7 @@ static int setup_clocking(struct snd_soc_dai *dai, break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__); msp_config->tx_clk_sel = TX_CLK_SEL_SRG; @@ -216,7 +213,7 @@ static int setup_clocking(struct snd_soc_dai *dai, break; default: - dev_err(dai->dev, "%s: Error: Unsopported master (fmt = 0x%x)!\n", + dev_err(dai->dev, "%s: Error: Unsupported master (fmt = 0x%x)!\n", __func__, fmt); return -EINVAL; @@ -328,15 +325,15 @@ static int setup_msp_config(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__, runtime->rate, runtime->channels); switch (fmt & - (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP: dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__); msp_config->default_protdesc = 1; msp_config->protocol = MSP_I2S_PROTOCOL; break; - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC: dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__); msp_config->data_size = MSP_DATA_BITS_16; @@ -348,10 +345,10 @@ static int setup_msp_config(struct snd_pcm_substream *substream, break; - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC: dev_dbg(dai->dev, "%s: PCM format.\n", __func__); msp_config->data_size = MSP_DATA_BITS_16; @@ -372,7 +369,7 @@ static int setup_msp_config(struct snd_pcm_substream *substream, break; default: - dev_err(dai->dev, "%s: Error: Unsopported format (%d)!\n", + dev_err(dai->dev, "%s: Error: Unsupported format (%d)!\n", __func__, fmt); return -EINVAL; } @@ -477,10 +474,11 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, } /* Set OPP-level */ - if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) && + if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) && (drvdata->msp->f_bitclk > 19200000)) { /* If the bit-clock is higher than 19.2MHz, Vape should be - * run in 100% OPP. Only when bit-clock is used (MSP master) */ + * run in 100% OPP. Only when bit-clock is used (MSP master) + */ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "ux500-msp-i2s", 100); drvdata->vape_opp_constraint = 1; @@ -520,9 +518,9 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream, slots_active = hweight32(mask); dev_dbg(dai->dev, "TDM-slots active: %d", slots_active); - snd_pcm_hw_constraint_minmax(runtime, + snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, - slots_active, slots_active); + slots_active); break; default: @@ -543,13 +541,13 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai, dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id); switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | - SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC: break; default: @@ -654,21 +652,38 @@ static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream, return ret; } -static int ux500_msp_dai_probe(struct snd_soc_dai *dai) +static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai) { struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); + struct snd_dmaengine_dai_dma_data *playback_dma_data; + struct snd_dmaengine_dai_dma_data *capture_dma_data; + + playback_dma_data = devm_kzalloc(dai->dev, + sizeof(*playback_dma_data), + GFP_KERNEL); + if (!playback_dma_data) + return -ENOMEM; + + capture_dma_data = devm_kzalloc(dai->dev, + sizeof(*capture_dma_data), + GFP_KERNEL); + if (!capture_dma_data) + return -ENOMEM; - dai->playback_dma_data = &drvdata->msp->playback_dma_data; - dai->capture_dma_data = &drvdata->msp->capture_dma_data; + playback_dma_data->addr = drvdata->msp->tx_rx_addr; + capture_dma_data->addr = drvdata->msp->tx_rx_addr; - drvdata->msp->playback_dma_data.data_size = drvdata->slot_width; - drvdata->msp->capture_dma_data.data_size = drvdata->slot_width; + playback_dma_data->maxburst = 4; + capture_dma_data->maxburst = 4; + + snd_soc_dai_init_dma_data(dai, playback_dma_data, capture_dma_data); return 0; } -static struct snd_soc_dai_ops ux500_msp_dai_ops[] = { +static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { { + .probe = ux500_msp_dai_of_probe, .set_sysclk = ux500_msp_dai_set_dai_sysclk, .set_fmt = ux500_msp_dai_set_dai_fmt, .set_tdm_slot = ux500_msp_dai_set_tdm_slot, @@ -680,91 +695,21 @@ static struct snd_soc_dai_ops ux500_msp_dai_ops[] = { } }; -static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { - { - .name = "ux500-msp-i2s.0", - .probe = ux500_msp_dai_probe, - .id = 0, - .suspend = NULL, - .resume = NULL, - .playback = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .capture = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .ops = ux500_msp_dai_ops, - }, - { - .name = "ux500-msp-i2s.1", - .probe = ux500_msp_dai_probe, - .id = 1, - .suspend = NULL, - .resume = NULL, - .playback = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .capture = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .ops = ux500_msp_dai_ops, - }, - { - .name = "ux500-msp-i2s.2", - .id = 2, - .probe = ux500_msp_dai_probe, - .suspend = NULL, - .resume = NULL, - .playback = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .capture = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .ops = ux500_msp_dai_ops, - }, - { - .name = "ux500-msp-i2s.3", - .probe = ux500_msp_dai_probe, - .id = 3, - .suspend = NULL, - .resume = NULL, - .playback = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .capture = { - .channels_min = UX500_MSP_MIN_CHANNELS, - .channels_max = UX500_MSP_MAX_CHANNELS, - .rates = UX500_I2S_RATES, - .formats = UX500_I2S_FORMATS, - }, - .ops = ux500_msp_dai_ops, - }, +static struct snd_soc_dai_driver ux500_msp_dai_drv = { + .playback.channels_min = UX500_MSP_MIN_CHANNELS, + .playback.channels_max = UX500_MSP_MAX_CHANNELS, + .playback.rates = UX500_I2S_RATES, + .playback.formats = UX500_I2S_FORMATS, + .capture.channels_min = UX500_MSP_MIN_CHANNELS, + .capture.channels_max = UX500_MSP_MAX_CHANNELS, + .capture.rates = UX500_I2S_RATES, + .capture.formats = UX500_I2S_FORMATS, + .ops = ux500_msp_dai_ops, }; static const struct snd_soc_component_driver ux500_msp_component = { - .name = "ux500-msp", + .name = "ux500-msp", + .legacy_dai_naming = 1, }; @@ -773,9 +718,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) struct ux500_msp_i2s_drvdata *drvdata; int ret = 0; - dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__, - pdev->name); - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp_i2s_drvdata), GFP_KERNEL); @@ -791,7 +733,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape"); if (IS_ERR(drvdata->reg_vape)) { - ret = (int)PTR_ERR(drvdata->reg_vape); + ret = PTR_ERR(drvdata->reg_vape); dev_err(&pdev->dev, "%s: ERROR: Failed to get Vape supply (%d)!\n", __func__, ret); @@ -799,38 +741,39 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) } prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50); - drvdata->pclk = clk_get(&pdev->dev, "apb_pclk"); + drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(drvdata->pclk)) { - ret = (int)PTR_ERR(drvdata->pclk); - dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n", + ret = PTR_ERR(drvdata->pclk); + dev_err(&pdev->dev, + "%s: ERROR: devm_clk_get of pclk failed (%d)!\n", __func__, ret); - goto err_pclk; + return ret; } - drvdata->clk = clk_get(&pdev->dev, NULL); + drvdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { - ret = (int)PTR_ERR(drvdata->clk); - dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n", + ret = PTR_ERR(drvdata->clk); + dev_err(&pdev->dev, + "%s: ERROR: devm_clk_get failed (%d)!\n", __func__, ret); - goto err_clk; + return ret; } - ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp, - pdev->dev.platform_data); + ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp); if (!drvdata->msp) { dev_err(&pdev->dev, "%s: ERROR: Failed to init MSP-struct (%d)!", __func__, ret); - goto err_init_msp; + return ret; } dev_set_drvdata(&pdev->dev, drvdata); ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component, - &ux500_msp_dai_drv[drvdata->msp->id], 1); + &ux500_msp_dai_drv, 1); if (ret < 0) { dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n", __func__, drvdata->msp->id); - goto err_init_msp; + return ret; } ret = ux500_pcm_register_platform(pdev); @@ -845,17 +788,10 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) err_reg_plat: snd_soc_unregister_component(&pdev->dev); -err_init_msp: - clk_put(drvdata->clk); -err_clk: - clk_put(drvdata->pclk); -err_pclk: - devm_regulator_put(drvdata->reg_vape); - return ret; } -static int ux500_msp_drv_remove(struct platform_device *pdev) +static void ux500_msp_drv_remove(struct platform_device *pdev) { struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev); @@ -863,26 +799,20 @@ static int ux500_msp_drv_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); - clk_put(drvdata->clk); - clk_put(drvdata->pclk); - ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp); - - return 0; } static const struct of_device_id ux500_msp_i2s_match[] = { { .compatible = "stericsson,ux500-msp-i2s", }, {}, }; +MODULE_DEVICE_TABLE(of, ux500_msp_i2s_match); static struct platform_driver msp_i2s_driver = { .driver = { .name = "ux500-msp-i2s", - .owner = THIS_MODULE, .of_match_table = ux500_msp_i2s_match, }, .probe = ux500_msp_drv_probe, @@ -890,4 +820,5 @@ static struct platform_driver msp_i2s_driver = { }; module_platform_driver(msp_i2s_driver); +MODULE_DESCRIPTION("ASoC Ux500 I2S driver"); MODULE_LICENSE("GPL v2"); |
