From e51cebf75ab45d9f680a15a120b605244b7ce5ea Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 2 May 2015 01:00:13 +0900 Subject: [PATCH 1/9] ASoC: fsl: Constify platform_device_id The platform_device_id is not modified by the driver and core uses it as const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index d9050d946ae7..fc57da341d61 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -184,7 +184,7 @@ static enum imx_audmux_type { IMX31_AUDMUX, } audmux_type; -static struct platform_device_id imx_audmux_ids[] = { +static const struct platform_device_id imx_audmux_ids[] = { { .name = "imx21-audmux", .driver_data = IMX21_AUDMUX, From ff9174d57a8239c5a21d2a0c7e00dddd54953f6c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 7 May 2015 23:24:16 -0300 Subject: [PATCH 2/9] ASoC: fsl_ssi: No need call of_device_is_available() The comment and the call to of_device_is_available() are not really needed. It is the expected behaviour to probe only the ssi nodes that are enabled in the device tree. Signed-off-by: Fabio Estevam Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e8bb8eef1d16..5199c0fb9edf 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1292,13 +1292,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) void __iomem *iomem; char name[64]; - /* SSIs that are not connected on the board should have a - * status = "disabled" - * property in their device tree nodes. - */ - if (!of_device_is_available(np)) - return -ENODEV; - of_id = of_match_device(fsl_ssi_ids, &pdev->dev); if (!of_id || !of_id->data) return -EINVAL; From d0657fe8c645e3963d2a134d2a110c0b8cf08a9d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 9 May 2015 12:45:52 -0300 Subject: [PATCH 3/9] ASoC: fsl: fsl_dma: Use true/false for boolean init Bool initializations should use true and false. Bool tests don't need comparisons. Based on contributions from Joe Perches, Rusty Russell and Bruce W Allan. The semantic patch that makes this change is available in scripts/coccinelle/misc/boolinit.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/ Signed-off-by: Fabio Estevam Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 93d7e56c6066..ccadefceeff2 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -445,7 +445,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) return ret; } - dma->assigned = 1; + dma->assigned = true; snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); @@ -814,7 +814,7 @@ static int fsl_dma_close(struct snd_pcm_substream *substream) substream->runtime->private_data = NULL; } - dma->assigned = 0; + dma->assigned = false; return 0; } From 0f9a7fecf2514cd5cb14be8e9aae3556c403ff1f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 9 May 2015 12:45:53 -0300 Subject: [PATCH 4/9] ASoC: fsl: imx-mc13783: Simplify trivial if-return sequence Simplify a trivial if-return sequence. Possibly combine with a preceding function call. The semantic patch that makes this change is available in scripts/coccinelle/misc/simple_return.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/ Signed-off-by: Fabio Estevam Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/imx-mc13783.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 9e6493d4e7ff..bb0459018b45 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -45,11 +45,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); - if (ret) - return ret; - - return 0; + return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); } static struct snd_soc_ops imx_mc13783_hifi_ops = { From c3ecef21c3f26bf4737fc0887964127accfa8a0e Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 11 May 2015 18:24:41 +0800 Subject: [PATCH 5/9] ASoC: fsl_sai: add sai master mode support When sai works on master mode, set its bit clock and frame clock. SAI has 4 MCLK source, bus clock, MCLK1, MCLK2 and MCLK3. fsl_sai_set_bclk will select proper MCLK source, then calculate and set the bit clock divider. After fsl_sai_set_bclk, enable the selected mclk in hw_params(), and add hw_free() to disable the mclk. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 117 ++++++++++++++++++++++++++++++++++++++-- sound/soc/fsl/fsl_sai.h | 9 +++- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ec79c3d5e65e..cca72b8287a9 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1,7 +1,7 @@ /* * Freescale ALSA SoC Digital Audio Interface (SAI) driver. * - * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2012-2015 Freescale Semiconductor, Inc. * * This program is free software, you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -251,12 +251,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, val_cr4 |= FSL_SAI_CR4_FSD_MSTR; break; case SND_SOC_DAIFMT_CBM_CFM: + sai->is_slave_mode = true; break; case SND_SOC_DAIFMT_CBS_CFM: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; break; case SND_SOC_DAIFMT_CBM_CFS: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; + sai->is_slave_mode = true; break; default: return -EINVAL; @@ -288,6 +290,79 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) return ret; } +static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); + unsigned long clk_rate; + u32 savediv = 0, ratio, savesub = freq; + u32 id; + int ret = 0; + + /* Don't apply to slave mode */ + if (sai->is_slave_mode) + return 0; + + for (id = 0; id < FSL_SAI_MCLK_MAX; id++) { + clk_rate = clk_get_rate(sai->mclk_clk[id]); + if (!clk_rate) + continue; + + ratio = clk_rate / freq; + + ret = clk_rate - ratio * freq; + + /* + * Drop the source that can not be + * divided into the required rate. + */ + if (ret != 0 && clk_rate / ret < 1000) + continue; + + dev_dbg(dai->dev, + "ratio %d for freq %dHz based on clock %ldHz\n", + ratio, freq, clk_rate); + + if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512) + ratio /= 2; + else + continue; + + if (ret < savesub) { + savediv = ratio; + sai->mclk_id[tx] = id; + savesub = ret; + } + + if (ret == 0) + break; + } + + if (savediv == 0) { + dev_err(dai->dev, "failed to derive required %cx rate: %d\n", + tx ? 'T' : 'R', freq); + return -EINVAL; + } + + if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) { + regmap_update_bits(sai->regmap, FSL_SAI_RCR2, + FSL_SAI_CR2_MSEL_MASK, + FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); + regmap_update_bits(sai->regmap, FSL_SAI_RCR2, + FSL_SAI_CR2_DIV_MASK, savediv - 1); + } else { + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, + FSL_SAI_CR2_MSEL_MASK, + FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, + FSL_SAI_CR2_DIV_MASK, savediv - 1); + } + + dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n", + sai->mclk_id[tx], savediv, savesub); + + return 0; +} + static int fsl_sai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) @@ -297,6 +372,24 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); u32 word_width = snd_pcm_format_width(params_format(params)); u32 val_cr4 = 0, val_cr5 = 0; + int ret; + + if (!sai->is_slave_mode) { + ret = fsl_sai_set_bclk(cpu_dai, tx, + 2 * word_width * params_rate(params)); + if (ret) + return ret; + + /* Do not enable the clock if it is already enabled */ + if (!(sai->mclk_streams & BIT(substream->stream))) { + ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[tx]]); + if (ret) + return ret; + + sai->mclk_streams |= BIT(substream->stream); + } + + } if (!sai->is_dsp_mode) val_cr4 |= FSL_SAI_CR4_SYWD(word_width); @@ -322,6 +415,22 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_sai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + + if (!sai->is_slave_mode && + sai->mclk_streams & BIT(substream->stream)) { + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); + sai->mclk_streams &= ~BIT(substream->stream); + } + + return 0; +} + + static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { @@ -428,6 +537,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt, .hw_params = fsl_sai_hw_params, + .hw_free = fsl_sai_hw_free, .trigger = fsl_sai_trigger, .startup = fsl_sai_startup, .shutdown = fsl_sai_shutdown, @@ -600,8 +710,9 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->bus_clk = NULL; } - for (i = 0; i < FSL_SAI_MCLK_MAX; i++) { - sprintf(tmp, "mclk%d", i + 1); + sai->mclk_clk[0] = sai->bus_clk; + for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { + sprintf(tmp, "mclk%d", i); sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 34667209b607..066280953c85 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -72,13 +72,15 @@ /* SAI Transmit and Recieve Configuration 2 Register */ #define FSL_SAI_CR2_SYNC BIT(30) -#define FSL_SAI_CR2_MSEL_MASK (0xff << 26) +#define FSL_SAI_CR2_MSEL_MASK (0x3 << 26) #define FSL_SAI_CR2_MSEL_BUS 0 #define FSL_SAI_CR2_MSEL_MCLK1 BIT(26) #define FSL_SAI_CR2_MSEL_MCLK2 BIT(27) #define FSL_SAI_CR2_MSEL_MCLK3 (BIT(26) | BIT(27)) +#define FSL_SAI_CR2_MSEL(ID) ((ID) << 26) #define FSL_SAI_CR2_BCP BIT(25) #define FSL_SAI_CR2_BCD_MSTR BIT(24) +#define FSL_SAI_CR2_DIV_MASK 0xff /* SAI Transmit and Recieve Configuration 3 Register */ #define FSL_SAI_CR3_TRCE BIT(16) @@ -120,7 +122,7 @@ #define FSL_SAI_CLK_MAST2 2 #define FSL_SAI_CLK_MAST3 3 -#define FSL_SAI_MCLK_MAX 3 +#define FSL_SAI_MCLK_MAX 4 /* SAI data transfer numbers per DMA request */ #define FSL_SAI_MAXBURST_TX 6 @@ -132,11 +134,14 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; + bool is_slave_mode; bool is_lsb_first; bool is_dsp_mode; bool sai_on_imx; bool synchronous[2]; + unsigned int mclk_id[2]; + unsigned int mclk_streams; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; From c5f4823babfd5e1b34494310e0a9f7cab44cadb9 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 11 May 2015 18:24:43 +0800 Subject: [PATCH 6/9] ASoC: fsl_sai: add 12kHz, 24kHz, 176.4kHz and 192kHz sample rate support Normally we don't support 12kHz, 24kHz in audio driver, alsa didn't have formal definition of 12kHz, 24kHz, but alsa supply a way to support these sample rates. And add 176.4kHz and 192kHz support. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cca72b8287a9..84ca28fdce7f 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -27,6 +27,17 @@ #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ FSL_SAI_CSR_FEIE) +static u32 fsl_sai_rates[] = { + 8000, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000 +}; + +static struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { + .count = ARRAY_SIZE(fsl_sai_rates), + .list = fsl_sai_rates, +}; + static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; @@ -519,7 +530,10 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, FSL_SAI_CR3_TRCE); - return 0; + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints); + + return ret; } static void fsl_sai_shutdown(struct snd_pcm_substream *substream, @@ -573,14 +587,18 @@ static struct snd_soc_dai_driver fsl_sai_dai = { .stream_name = "CPU-Playback", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, + .rate_min = 8000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_SAI_FORMATS, }, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, + .rate_min = 8000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_SAI_FORMATS, }, .ops = &fsl_sai_pcm_dai_ops, From f490f326178a6fec87a9bc3d35525bc9cb96ef0e Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 24 May 2015 01:12:41 -0700 Subject: [PATCH 7/9] ASoC: fsl_spdif: Don't try to round-up for clock divisor calculation As commit 6c8ca30eec7b ("ASoC: fsl_ssi: Don't try to round-up for PM divisor calculation") mentioned that there's no more need to use a round up work around to get a better divisor since the clk-divider driver has been refined a lot. So this patch applies the same modification to fsl_spdif driver. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 91eb3aef7f02..8e932219cb3a 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -417,11 +417,9 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, if (clk != STC_TXCLK_SPDIF_ROOT) goto clk_set_bypass; - /* - * The S/PDIF block needs a clock of 64 * fs * txclk_df. - * So request 64 * fs * (txclk_df + 1) to get rounded. - */ - ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (txclk_df + 1)); + /* The S/PDIF block needs a clock of 64 * fs * txclk_df */ + ret = clk_set_rate(spdif_priv->txclk[rate], + 64 * sample_rate * txclk_df); if (ret) { dev_err(&pdev->dev, "failed to set tx clock rate\n"); return ret; @@ -1060,7 +1058,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { for (txclk_df = 1; txclk_df <= 128; txclk_df++) { - rate_ideal = rate[index] * (txclk_df + 1) * 64; + rate_ideal = rate[index] * txclk_df * 64; if (round) rate_actual = clk_round_rate(clk, rate_ideal); else From 1fb1e0ec9a8ab87985448e8b82b20884a186ec31 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 22 May 2015 15:09:19 -0700 Subject: [PATCH 8/9] ASoC: Add jack types to dt-bindings Adding the jack type to the dt-bindings directory will allow for device tree files to specify the type of audio jacks that are present for a board. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- include/dt-bindings/sound/audio-jack-events.h | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 include/dt-bindings/sound/audio-jack-events.h diff --git a/include/dt-bindings/sound/audio-jack-events.h b/include/dt-bindings/sound/audio-jack-events.h new file mode 100644 index 000000000000..378349f28069 --- /dev/null +++ b/include/dt-bindings/sound/audio-jack-events.h @@ -0,0 +1,9 @@ +#ifndef __AUDIO_JACK_EVENTS_H +#define __AUDIO_JACK_EVENTS_H + +#define JACK_HEADPHONE 1 +#define JACK_MICROPHONE 2 +#define JACK_LINEOUT 3 +#define JACK_LINEIN 4 + +#endif /* __AUDIO_JACK_EVENTS_H */ From e616d2eba6d1ac8f3268cdf5d7b0424072c89a8d Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 22 May 2015 15:09:20 -0700 Subject: [PATCH 9/9] ASoC: jack - add_gpiods accepts filled descriptors Allow for the desc field to be pre-filled when adding gpios to a jack. This allows drivers to get the gpios and decide if they should be added to the list or not. Specifically this will allow the gpio jack driver to add gpios based on device property specifications. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 9f60c25c4568..171c4291ea21 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -315,8 +315,11 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, goto undo; } - if (gpios[i].gpiod_dev) { - /* GPIO descriptor */ + if (gpios[i].desc) { + /* Already have a GPIO descriptor. */ + goto got_gpio; + } else if (gpios[i].gpiod_dev) { + /* Get a GPIO descriptor */ gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, gpios[i].name, gpios[i].idx, GPIOD_IN); @@ -344,7 +347,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, gpios[i].desc = gpio_to_desc(gpios[i].gpio); } - +got_gpio: INIT_DELAYED_WORK(&gpios[i].work, gpio_work); gpios[i].jack = jack;