[alsa-devel] [PATCH v3 0/2] Add Freescale ASRC driver
This series of patches add Freescale ASRC module driver support along with the extra request in imx-sdma structure required by SDMA Device to Device script.
The previous version has been in the maillist for nearly six months without any comment and reply. So I decide to drop the SDMA part's change since this series focus on ASRC support (Later, we can send SDMA part separately.) so that ASRC driver may get upstream first.
Changelog v3: * PATCH-1: Added an Acked-by from Shawn Guo * PATCH-2: Dropped THIS_MODULE as Tobias suggests * PATCH-2: Use dma_coerce_mask_and_coherent() in fsl_asrc_dma_pcm_new() * PATCH-2: Added substream check in fsl_asrc_dma_pcm_new() v2: * PATCH-1: Dropped the change to SDMA driver. * PATCH-2: Dropped useless member in private data structures. * PATCH-2: Refined some comments in fsl_asrc_dma.c driver. * PATCH-2: Refined commit comments.
Nicolin Chen (2): ARM: imx: Add the secondary request into the structure for imx-sdma ASoC: fsl_asrc: Add ASRC ASoC CPU DAI and platform drivers
.../devicetree/bindings/sound/fsl,asrc.txt | 62 ++ include/linux/platform_data/dma-imx.h | 1 + sound/soc/fsl/Kconfig | 9 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_asrc.c | 1030 ++++++++++++++++++++ sound/soc/fsl/fsl_asrc.h | 461 +++++++++ sound/soc/fsl/fsl_asrc_dma.c | 386 ++++++++ 7 files changed, 1951 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,asrc.txt create mode 100644 sound/soc/fsl/fsl_asrc.c create mode 100644 sound/soc/fsl/fsl_asrc.h create mode 100644 sound/soc/fsl/fsl_asrc_dma.c
SDMA supports device to device (per_2_per) scripts to handle DMA transfering between two peripheral devices. The per_2_per script, however, needs two dma requests from two sides while the current structure only defined one request.
So this patch just simply adds the secondary request so as to let SDMA and its user to add its implementation later.
[ Both change in the SDMA driver and its users like Freescale ASRC ASoC driver should be taken along with this change in order to truly support per_2_per sciprts. However, we here make an expediency by adding this first so that we can add either side later since this patch won't break any function and meanwhile it can make merge window more smoothly: we don't need to apply the change inside dmaengine branch via ASoC tree any more. -- Nicolin ]
Signed-off-by: Nicolin Chen nicoleotsuka@gmail.com Acked-by: Shawn Guo shawn.guo@linaro.org --- include/linux/platform_data/dma-imx.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index 7aa0e89..6a1357d 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -51,6 +51,7 @@ enum imx_dma_prio {
struct imx_dma_data { int dma_request; /* DMA request line */ + int dma_request2; /* secondary DMA request line */ enum sdma_peripheral_type peripheral_type; int priority; };
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a signal associated with an input clock into a signal associated with a different output clock. The driver currently works as a Front End of DPCM with other Back Ends DAI links such as ESAI<->CS42888 and SSI<->WM8962 and SAI. It converts the original sample rate to a common rate supported by Back Ends for playback while converts the common rate of Back Ends to a desired rate for capture. It has 3 pairs to support three different substreams within totally 10 channels.
Signed-off-by: Nicolin Chen nicoleotsuka@gmail.com --- .../devicetree/bindings/sound/fsl,asrc.txt | 62 ++ sound/soc/fsl/Kconfig | 9 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_asrc.c | 1030 ++++++++++++++++++++ sound/soc/fsl/fsl_asrc.h | 461 +++++++++ sound/soc/fsl/fsl_asrc_dma.c | 386 ++++++++ 6 files changed, 1950 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,asrc.txt create mode 100644 sound/soc/fsl/fsl_asrc.c create mode 100644 sound/soc/fsl/fsl_asrc.h create mode 100644 sound/soc/fsl/fsl_asrc_dma.c
diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt new file mode 100644 index 0000000..637028c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt @@ -0,0 +1,62 @@ +Freescale Asynchronous Sample Rate Converter (ASRC) Controller + +The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a +signal associated with an input clock into a signal associated with a different +output clock. The driver currently works as a Front End of DPCM with other Back +Ends Audio controller such as ESAI, SSI and SAI. It has three pairs to support +three substreams within totally 10 channels. + +Required properties: + + - compatible : Compatible list, must contain "fsl,imx35-asrc" or + "fsl,imx53-asrc". + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the spdif interrupt. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Six dmas have to be defined: "rxa", "rxb", "rxc", "txa", "txb", + and "txc". + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "mem" Peripheral access clock to access registers. + "ipg" Peripheral clock to driver module. + "asrck_<0-f>" Clock sources for input and output clock. + + - big-endian : If this property is absent, the native endian mode will + be in use as default, or the big endian mode will be in use + for all the device registers. + + - fsl,asrc-rate : Defines a mutual sample rate used by Back End DAI link. + + - fsl,asrc-width : Defines a mutual sample width used by Back End DAI link. + +Example: + +asrc: asrc@02034000 { + compatible = "fsl,imx53-asrc"; + reg = <0x02034000 0x4000>; + interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 107>, <&clks 107>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 107>, <&clks 0>, <&clks 0>; + clock-names = "mem", "ipg", "asrck0", + "asrck_1", "asrck_2", "asrck_3", "asrck_4", + "asrck_5", "asrck_6", "asrck_7", "asrck_8", + "asrck_9", "asrck_a", "asrck_b", "asrck_c", + "asrck_d", "asrck_e", "asrck_f"; + dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, + <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; + dma-names = "rxa", "rxb", "rxc", + "txa", "txb", "txc"; + fsl,asrc-rate = <48000>; + fsl,asrc-width = <16>; + status = "okay"; +}; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 2d60e37..e06fbfe 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -2,6 +2,15 @@ menu "SoC Audio for Freescale CPUs"
comment "Common SoC Audio options for Freescale CPUs:"
+config SND_SOC_FSL_ASRC + tristate "Asynchronous Sample Rate Converter (ASRC) module support" + select REGMAP_MMIO + help + Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) + support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + config SND_SOC_FSL_SAI tristate "Synchronous Audio Interface (SAI) module support" select REGMAP_MMIO diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ce49570..ff7ee2c 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
# Freescale SSI/DMA/SAI/SPDIF Support +snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o snd-soc-fsl-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o @@ -18,6 +19,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o snd-soc-fsl-esai-objs := fsl_esai.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o +obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c new file mode 100644 index 0000000..800e88e --- /dev/null +++ b/sound/soc/fsl/fsl_asrc.c @@ -0,0 +1,1030 @@ +/* + * Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen nicoleotsuka@gmail.com + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_data/dma-imx.h> +#include <linux/pm_runtime.h> +#include <sound/dmaengine_pcm.h> +#include <sound/pcm_params.h> + +#include "fsl_asrc.h" + +#define IDEAL_RATIO_DECIMAL_DEPTH 26 + +#define pair_err(fmt, ...) \ + dev_err(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) + +#define pair_dbg(fmt, ...) \ + dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) + +/* Sample rates are aligned with that defined in pcm.h file */ +static const u8 process_option[][8][2] = { + /* 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ + {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ + {{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ + {{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ + {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ + {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ +}; + +/* Corresponding to process_option */ +static int supported_input_rate[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, + 96000, 176400, 192000, +}; + +static int supported_asrc_rate[] = { + 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, +}; + +/** + * The following tables map the relationship between asrc_inclk/asrc_outclk in + * fsl_asrc.h and the registers of ASRCSR + */ +static unsigned char input_clk_map_imx35[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, +}; + +static unsigned char output_clk_map_imx35[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, +}; + +/* i.MX53 uses the same map for input and output */ +static unsigned char input_clk_map_imx53[] = { +/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ + 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, +}; + +static unsigned char output_clk_map_imx53[] = { +/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ + 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, +}; + +static unsigned char *clk_map[2]; + +enum fsl_asrc_type { + IMX35_ASRC, + IMX53_ASRC, +}; + +static const struct platform_device_id fsl_asrc_devtype[] = { + { + .name = "imx35-asrc", + .driver_data = IMX35_ASRC, + }, { + .name = "imx53-asrc", + .driver_data = IMX53_ASRC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, fsl_asrc_devtype); + +static const struct of_device_id fsl_asrc_ids[] = { + { + .compatible = "fsl,imx35-asrc", + .data = &fsl_asrc_devtype[IMX35_ASRC], + }, { + .compatible = "fsl,imx53-asrc", + .data = &fsl_asrc_devtype[IMX53_ASRC], + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, fsl_asrc_ids); + +static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) +{ + struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id; + struct device *dev = &asrc_priv->pdev->dev; + enum asrc_pair_index index; + u32 status; + + regmap_read(asrc_priv->regmap, REG_ASRSTR, &status); + + /* Clean overload error */ + regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE); + + /* + * We here use dev_dbg() for all exceptions because ASRC itself does + * not care if FIFO overflowed or underrun while a warning in the + * interrupt would result a ridged conversion. + */ + for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { + if (!asrc_priv->pair[index]) + continue; + + if (status & ASRSTR_ATQOL) { + asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; + dev_dbg(dev, "ASRC Task Queue FIFO overload"); + } + + if (status & ASRSTR_AOOL(index)) { + asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; + pair_dbg("Output Task Overload"); + } + + if (status & ASRSTR_AIOL(index)) { + asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; + pair_dbg("Input Task Overload"); + } + + if (status & ASRSTR_AODO(index)) { + asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; + pair_dbg("Output Data Buffer has overflowed"); + } + + if (status & ASRSTR_AIDU(index)) { + asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; + pair_dbg("Input Data Buffer has underflowed"); + } + } + + return IRQ_HANDLED; +} + +/** + * Request ASRC pair + * + * It assigns pair by the order of A->C->B because allocation of pair B, + * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A + * while pair A and pair C are comparatively independent. + */ +static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) +{ + enum asrc_pair_index index = ASRC_INVALID_PAIR; + struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct device *dev = &asrc_priv->pdev->dev; + unsigned long lock_flags; + int i, ret = 0; + + spin_lock_irqsave(&asrc_priv->lock, lock_flags); + + for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { + if (asrc_priv->pair[i] != NULL) + continue; + + index = i; + + if (i != ASRC_PAIR_B) + break; + } + + if (index == ASRC_INVALID_PAIR) { + dev_err(dev, "all pairs are busy now\n"); + ret = -EBUSY; + } else if (asrc_priv->channel_avail < channels) { + dev_err(dev, "can't afford required channels: %d\n", channels); + ret = -EINVAL; + } else { + asrc_priv->channel_avail -= channels; + asrc_priv->pair[index] = pair; + pair->channels = channels; + pair->index = index; + } + + spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); + + return ret; +} + +/** + * Release ASRC pair + * + * It clears the resource from asrc_priv and releases the occupied channels. + */ +static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) +{ + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + unsigned long lock_flags; + + /* Make sure the pair is disabled */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ASRCEi_MASK(index), 0); + + spin_lock_irqsave(&asrc_priv->lock, lock_flags); + + asrc_priv->channel_avail += pair->channels; + asrc_priv->pair[index] = NULL; + pair->error = 0; + + spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); +} + +/** + * Configure input and output thresholds + */ +static int fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) +{ + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + + regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), + ASRMCRi_EXTTHRSHi_MASK | + ASRMCRi_INFIFO_THRESHOLD_MASK | + ASRMCRi_OUTFIFO_THRESHOLD_MASK, + ASRMCRi_EXTTHRSHi | + ASRMCRi_INFIFO_THRESHOLD(in) | + ASRMCRi_OUTFIFO_THRESHOLD(out)); + + return 0; +} + +/** + * Calculate the total divisor between asrck clock rate and sample rate + * + * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider + */ +static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) +{ + u32 ps; + + /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ + for (ps = 0; div > 8; ps++) + div >>= 1; + + return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; +} + +/** + * Calculate and set the ratio for Ideal Ratio mode only + * + * The ratio is a 32-bit fixed point value with 26 fractional bits. + */ +static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, + int inrate, int outrate) +{ + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + unsigned long ratio; + int i; + + if (!outrate) { + pair_err("output rate should not be zero\n"); + return -EINVAL; + } + + /* Calculate the intergal part of the ratio */ + ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; + + /* ... and then the 26 depth decimal part */ + inrate %= outrate; + + for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { + inrate <<= 1; + + if (inrate < outrate) + continue; + + ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); + inrate -= outrate; + + if (!inrate) + break; + } + + regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio); + regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24); + + return 0; +} + +/** + * Configure the assigned ASRC pair + * + * It configures those ASRC registers according to a configuration instance + * of struct asrc_config which includes in/output sample rate, width, channel + * and clock settings. + */ +static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) +{ + struct asrc_config *config = pair->config; + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + u32 inrate = config->input_sample_rate, indiv; + u32 outrate = config->output_sample_rate, outdiv; + bool ideal = config->inclk == INCLK_NONE; + u32 clk_index[2], div[2]; + int in, out, channels; + struct clk *clk; + + if (!config) { + pair_err("invalid pair config\n"); + return -EINVAL; + } + + /* Validate channels */ + if (config->channel_num < 1 || config->channel_num > 10) { + pair_err("does not support %d channels\n", config->channel_num); + return -EINVAL; + } + + /* Validate output width */ + if (config->output_word_width == ASRC_WIDTH_8_BIT) { + pair_err("does not support 8bit width output\n"); + return -EINVAL; + } + + /* Validate input and output sample rates */ + for (in = 0; in < ARRAY_SIZE(supported_input_rate); in++) + if (inrate == supported_input_rate[in]) + break; + + if (in == ARRAY_SIZE(supported_input_rate)) { + pair_err("unsupported input sample rate: %dHz\n", inrate); + return -EINVAL; + } + + for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) + if (outrate == supported_asrc_rate[out]) + break; + + if (out == ARRAY_SIZE(supported_asrc_rate)) { + pair_err("unsupported output sample rate: %dHz\n", outrate); + return -EINVAL; + } + + /* Validate input and output clock sources */ + clk_index[IN] = clk_map[IN][config->inclk]; + clk_index[OUT] = clk_map[OUT][config->outclk]; + + /* We only have output clock for ideal ratio mode */ + clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; + + div[IN] = clk_get_rate(clk) / inrate; + if (div[IN] == 0) { + pair_err("failed to support input sample rate %dHz by asrck_%x", + inrate, clk_index[ideal ? OUT : IN]); + return -EINVAL; + } + + clk = asrc_priv->asrck_clk[clk_index[OUT]]; + + /* Use fixed output rate for Ideal Ratio mode (INCLK_NONE) */ + if (ideal) + div[OUT] = clk_get_rate(clk) / IDEAL_RATIO_RATE; + else + div[OUT] = clk_get_rate(clk) / outrate; + + if (div[OUT] == 0) { + pair_err("failed to support output sample rate %dHz by asrck_%x", + outrate, clk_index[OUT]); + return -EINVAL; + } + + /* Set the channel number */ + channels = config->channel_num; + + if (asrc_priv->channel_bits < 4) + channels /= 2; + + /* Update channels for current pair */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR, + ASRCNCR_ANCi_MASK(index, asrc_priv->channel_bits), + ASRCNCR_ANCi(index, channels, asrc_priv->channel_bits)); + + /* Default setting: Automatic selection for processing mode */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_USRi_MASK(index), 0); + + /* Set the input and output clock sources */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCSR, + ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), + ASRCSR_AICS(index, clk_index[IN]) | + ASRCSR_AOCS(index, clk_index[OUT])); + + /* Calculate the input clock divisors */ + indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); + outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); + + /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index), + ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | + ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), + ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); + + /* Implement word_width configurations */ + regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index), + ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, + ASRMCR1i_OW16(config->output_word_width) | + ASRMCR1i_IWD(config->input_word_width)); + + /* Enable BUFFER STALL */ + regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), + ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); + + /* Set default thresholds for input and output FIFO */ + fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, + ASRC_INPUTFIFO_THRESHOLD); + + /* Configure the followings only for Ideal Ratio mode */ + if (!ideal) + return 0; + + /* Clear ASTSx bit to use Ideal Ratio mode */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ATSi_MASK(index), 0); + + /* Enable Ideal Ratio mode */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), + ASRCTR_IDR(index) | ASRCTR_USR(index)); + + /* Apply configurations for pre- and post-processing */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, + ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), + ASRCFG_PREMOD(index, process_option[in][out][0]) | + ASRCFG_POSTMOD(index, process_option[in][out][1])); + + return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); +} + +/** + * Start the assigned ASRC pair + * + * It enables the assigned pair and makes it stopped at the stall level. + */ +static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) +{ + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + int reg, retry = 10, i; + + /* Enable the current pair */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); + + /* Wait for status of initialization */ + do { + udelay(5); + regmap_read(asrc_priv->regmap, REG_ASRCFG, ®); + reg &= ASRCFG_INIRQi_MASK(index); + } while (!reg && --retry); + + /* Make the input fifo to ASRC STALL level */ + regmap_read(asrc_priv->regmap, REG_ASRCNCR, ®); + for (i = 0; i < pair->channels * 4; i++) + regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0); + + /* Enable overload interrupt */ + regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE); +} + +/** + * Stop the assigned ASRC pair + */ +static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) +{ + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + + /* Stop the current pair */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ASRCEi_MASK(index), 0); +} + +/** + * Get DMA channel according to the pair and direction. + */ +struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) +{ + struct fsl_asrc *asrc_priv = pair->asrc_priv; + enum asrc_pair_index index = pair->index; + char name[4]; + + sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); + + return dma_request_slave_channel(&asrc_priv->pdev->dev, name); +} +EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel); + +static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); + int width = snd_pcm_format_width(params_format(params)); + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + struct asrc_config config; + int word_width, ret; + + ret = fsl_asrc_request_pair(channels, pair); + if (ret) { + dev_err(dai->dev, "fail to request asrc pair\n"); + return ret; + } + + pair->config = &config; + + if (width == 16) + width = ASRC_WIDTH_16_BIT; + else + width = ASRC_WIDTH_24_BIT; + + if (asrc_priv->asrc_width == 16) + word_width = ASRC_WIDTH_16_BIT; + else + word_width = ASRC_WIDTH_24_BIT; + + config.pair = pair->index; + config.channel_num = channels; + config.inclk = INCLK_NONE; + config.outclk = OUTCLK_ASRCK1_CLK; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + config.input_word_width = width; + config.output_word_width = word_width; + config.input_sample_rate = rate; + config.output_sample_rate = asrc_priv->asrc_rate; + } else { + config.input_word_width = word_width; + config.output_word_width = width; + config.input_sample_rate = asrc_priv->asrc_rate; + config.output_sample_rate = rate; + } + + ret = fsl_asrc_config_pair(pair); + if (ret) { + dev_err(dai->dev, "fail to config asrc pair\n"); + return ret; + } + + return 0; +} + +static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + + if (pair) + fsl_asrc_release_pair(pair); + + return 0; +} + +static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + fsl_asrc_start_pair(pair); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + fsl_asrc_stop_pair(pair); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct snd_soc_dai_ops fsl_asrc_dai_ops = { + .hw_params = fsl_asrc_dai_hw_params, + .hw_free = fsl_asrc_dai_hw_free, + .trigger = fsl_asrc_dai_trigger, +}; + +static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) +{ + struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx, + &asrc_priv->dma_params_rx); + + return 0; +} + +#define FSL_ASRC_RATES SNDRV_PCM_RATE_8000_192000 +#define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FORMAT_S20_3LE) + +static struct snd_soc_dai_driver fsl_asrc_dai = { + .probe = fsl_asrc_dai_probe, + .playback = { + .stream_name = "ASRC-Playback", + .channels_min = 1, + .channels_max = 10, + .rates = FSL_ASRC_RATES, + .formats = FSL_ASRC_FORMATS, + }, + .capture = { + .stream_name = "ASRC-Capture", + .channels_min = 1, + .channels_max = 10, + .rates = FSL_ASRC_RATES, + .formats = FSL_ASRC_FORMATS, + }, + .ops = &fsl_asrc_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_asrc_component = { + .name = "fsl-asrc-dai", +}; + +static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_ASRCTR: + case REG_ASRIER: + case REG_ASRCNCR: + case REG_ASRCFG: + case REG_ASRCSR: + case REG_ASRCDR1: + case REG_ASRCDR2: + case REG_ASRSTR: + case REG_ASRPM1: + case REG_ASRPM2: + case REG_ASRPM3: + case REG_ASRPM4: + case REG_ASRPM5: + case REG_ASRTFR1: + case REG_ASRCCR: + case REG_ASRDOA: + case REG_ASRDOB: + case REG_ASRDOC: + case REG_ASRIDRHA: + case REG_ASRIDRLA: + case REG_ASRIDRHB: + case REG_ASRIDRLB: + case REG_ASRIDRHC: + case REG_ASRIDRLC: + case REG_ASR76K: + case REG_ASR56K: + case REG_ASRMCRA: + case REG_ASRFSTA: + case REG_ASRMCRB: + case REG_ASRFSTB: + case REG_ASRMCRC: + case REG_ASRFSTC: + case REG_ASRMCR1A: + case REG_ASRMCR1B: + case REG_ASRMCR1C: + return true; + default: + return false; + } +} + +static bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_ASRSTR: + case REG_ASRDIA: + case REG_ASRDIB: + case REG_ASRDIC: + case REG_ASRDOA: + case REG_ASRDOB: + case REG_ASRDOC: + case REG_ASRFSTA: + case REG_ASRFSTB: + case REG_ASRFSTC: + case REG_ASRCFG: + return true; + default: + return false; + } +} + +static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_ASRCTR: + case REG_ASRIER: + case REG_ASRCNCR: + case REG_ASRCFG: + case REG_ASRCSR: + case REG_ASRCDR1: + case REG_ASRCDR2: + case REG_ASRSTR: + case REG_ASRPM1: + case REG_ASRPM2: + case REG_ASRPM3: + case REG_ASRPM4: + case REG_ASRPM5: + case REG_ASRTFR1: + case REG_ASRCCR: + case REG_ASRDIA: + case REG_ASRDIB: + case REG_ASRDIC: + case REG_ASRIDRHA: + case REG_ASRIDRLA: + case REG_ASRIDRHB: + case REG_ASRIDRLB: + case REG_ASRIDRHC: + case REG_ASRIDRLC: + case REG_ASR76K: + case REG_ASR56K: + case REG_ASRMCRA: + case REG_ASRMCRB: + case REG_ASRMCRC: + case REG_ASRMCR1A: + case REG_ASRMCR1B: + case REG_ASRMCR1C: + return true; + default: + return false; + } +} + +static struct regmap_config fsl_asrc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = REG_ASRMCR1C, + .readable_reg = fsl_asrc_readable_reg, + .volatile_reg = fsl_asrc_volatile_reg, + .writeable_reg = fsl_asrc_writeable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +/** + * Initialize ASRC registers with a default configurations + */ +static int fsl_asrc_init(struct fsl_asrc *asrc_priv) +{ + /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ + regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN); + + /* Disable interrupt by default */ + regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0); + + /* Apply recommended settings for parameters from Reference Manual */ + regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff); + regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555); + regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280); + regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280); + regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280); + + /* Base address for task queue FIFO. Set to 0x7C */ + regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1, + ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); + + /* Set the processing clock for 76KHz to 133M */ + regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6); + + /* Set the processing clock for 56KHz to 133M */ + regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947); + + return 0; +} + +static int fsl_asrc_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(fsl_asrc_ids, &pdev->dev); + struct device_node *np = pdev->dev.of_node; + struct fsl_asrc *asrc_priv; + enum fsl_asrc_type devtype; + struct resource *res; + void __iomem *regs; + int irq, ret, i; + char tmp[16]; + + asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); + if (!asrc_priv) + return -ENOMEM; + + if (of_id) + pdev->id_entry = of_id->data; + devtype = pdev->id_entry->driver_data; + + switch (devtype) { + case IMX35_ASRC: + asrc_priv->channel_bits = 3; + clk_map[IN] = input_clk_map_imx35; + clk_map[OUT] = output_clk_map_imx35; + break; + case IMX53_ASRC: + asrc_priv->channel_bits = 4; + clk_map[IN] = input_clk_map_imx53; + clk_map[OUT] = output_clk_map_imx53; + break; + default: + dev_err(&pdev->dev, "unsupported device type\n"); + return -EINVAL; + } + + asrc_priv->pdev = pdev; + strcpy(asrc_priv->name, np->name); + + /* Get the addresses and IRQ */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + asrc_priv->paddr = res->start; + + /* Register regmap and let it prepare core clock */ + if (of_property_read_bool(np, "big-endian")) + fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; + + asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "mem", regs, &fsl_asrc_regmap_config); + if (IS_ERR(asrc_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap\n"); + return PTR_ERR(asrc_priv->regmap); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, + asrc_priv->name, asrc_priv); + if (ret) { + dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); + return ret; + } + + asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem"); + if (IS_ERR(asrc_priv->mem_clk)) { + dev_err(&pdev->dev, "failed to get mem clock\n"); + return PTR_ERR(asrc_priv->ipg_clk); + } + + asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(asrc_priv->ipg_clk)) { + dev_err(&pdev->dev, "failed to get ipg clock\n"); + return PTR_ERR(asrc_priv->ipg_clk); + } + + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { + sprintf(tmp, "asrck_%x", i); + asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(asrc_priv->asrck_clk[i])) { + dev_err(&pdev->dev, "failed to get %s clock\n", tmp); + return PTR_ERR(asrc_priv->asrck_clk[i]); + } + } + + ret = fsl_asrc_init(asrc_priv); + if (ret) { + dev_err(&pdev->dev, "failed to init asrc %d\n", ret); + return -EINVAL; + } + + asrc_priv->channel_avail = 10; + + ret = of_property_read_u32(np, "fsl,asrc-rate", + &asrc_priv->asrc_rate); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + return -EINVAL; + } + + ret = of_property_read_u32(np, "fsl,asrc-width", + &asrc_priv->asrc_width); + if (ret) { + dev_err(&pdev->dev, "failed to get output width\n"); + return -EINVAL; + } + + if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) { + dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); + asrc_priv->asrc_width = 24; + } + + platform_set_drvdata(pdev, asrc_priv); + pm_runtime_enable(&pdev->dev); + spin_lock_init(&asrc_priv->lock); + + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, + &fsl_asrc_dai, 1); + if (ret) { + dev_err(&pdev->dev, "failed to register ASoC DAI\n"); + return ret; + } + + ret = devm_snd_soc_register_platform(&pdev->dev, &fsl_asrc_platform); + if (ret) { + dev_err(&pdev->dev, "failed to register ASoC platform\n"); + return ret; + } + + dev_info(&pdev->dev, "driver registered\n"); + + return 0; +} + +#if CONFIG_PM_RUNTIME +static int fsl_asrc_runtime_resume(struct device *dev) +{ + struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + int i; + + clk_prepare_enable(asrc_priv->mem_clk); + clk_prepare_enable(asrc_priv->ipg_clk); + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) + clk_prepare_enable(asrc_priv->asrck_clk[i]); + + return 0; +} + +static int fsl_asrc_runtime_suspend(struct device *dev) +{ + struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) + clk_disable_unprepare(asrc_priv->asrck_clk[i]); + clk_disable_unprepare(asrc_priv->ipg_clk); + clk_disable_unprepare(asrc_priv->mem_clk); + + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +#if CONFIG_PM_SLEEP +static int fsl_asrc_suspend(struct device *dev) +{ + struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + + regcache_cache_only(asrc_priv->regmap, true); + regcache_mark_dirty(asrc_priv->regmap); + + return 0; +} + +static int fsl_asrc_resume(struct device *dev) +{ + struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + u32 asrctr; + + /* Stop all pairs provisionally */ + regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr); + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ASRCEi_ALL_MASK, 0); + + /* Restore all registers */ + regcache_cache_only(asrc_priv->regmap, false); + regcache_sync(asrc_priv->regmap); + + /* Restart enabled pairs */ + regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, + ASRCTR_ASRCEi_ALL_MASK, asrctr); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops fsl_asrc_pm = { + SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) +}; + +static struct platform_driver fsl_asrc_driver = { + .probe = fsl_asrc_probe, + .driver = { + .name = "fsl-asrc", + .of_match_table = fsl_asrc_ids, + .pm = &fsl_asrc_pm, + }, +}; +module_platform_driver(fsl_asrc_driver); + +MODULE_DESCRIPTION("Freescale ASRC ASoC driver"); +MODULE_AUTHOR("Nicolin Chen nicoleotsuka@gmail.com"); +MODULE_ALIAS("platform:fsl-asrc"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h new file mode 100644 index 0000000..a3f211f --- /dev/null +++ b/sound/soc/fsl/fsl_asrc.h @@ -0,0 +1,461 @@ +/* + * fsl_asrc.h - Freescale ASRC ALSA SoC header file + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen nicoleotsuka@gmail.com + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef _FSL_ASRC_H +#define _FSL_ASRC_H + +#define IN 0 +#define OUT 1 + +#define ASRC_DMA_BUFFER_NUM 2 +#define ASRC_INPUTFIFO_THRESHOLD 32 +#define ASRC_OUTPUTFIFO_THRESHOLD 32 +#define ASRC_FIFO_THRESHOLD_MIN 0 +#define ASRC_FIFO_THRESHOLD_MAX 63 +#define ASRC_DMA_BUFFER_SIZE (1024 * 48 * 4) +#define ASRC_MAX_BUFFER_SIZE (1024 * 48) +#define ASRC_OUTPUT_LAST_SAMPLE 8 + +#define IDEAL_RATIO_RATE 1000000 + +#define REG_ASRCTR 0x00 +#define REG_ASRIER 0x04 +#define REG_ASRCNCR 0x0C +#define REG_ASRCFG 0x10 +#define REG_ASRCSR 0x14 + +#define REG_ASRCDR1 0x18 +#define REG_ASRCDR2 0x1C +#define REG_ASRCDR(i) ((i < 2) ? REG_ASRCDR1 : REG_ASRCDR2) + +#define REG_ASRSTR 0x20 +#define REG_ASRRA 0x24 +#define REG_ASRRB 0x28 +#define REG_ASRRC 0x2C +#define REG_ASRPM1 0x40 +#define REG_ASRPM2 0x44 +#define REG_ASRPM3 0x48 +#define REG_ASRPM4 0x4C +#define REG_ASRPM5 0x50 +#define REG_ASRTFR1 0x54 +#define REG_ASRCCR 0x5C + +#define REG_ASRDIA 0x60 +#define REG_ASRDOA 0x64 +#define REG_ASRDIB 0x68 +#define REG_ASRDOB 0x6C +#define REG_ASRDIC 0x70 +#define REG_ASRDOC 0x74 +#define REG_ASRDI(i) (REG_ASRDIA + (i << 3)) +#define REG_ASRDO(i) (REG_ASRDOA + (i << 3)) +#define REG_ASRDx(x, i) (x == IN ? REG_ASRDI(i) : REG_ASRDO(i)) + +#define REG_ASRIDRHA 0x80 +#define REG_ASRIDRLA 0x84 +#define REG_ASRIDRHB 0x88 +#define REG_ASRIDRLB 0x8C +#define REG_ASRIDRHC 0x90 +#define REG_ASRIDRLC 0x94 +#define REG_ASRIDRH(i) (REG_ASRIDRHA + (i << 3)) +#define REG_ASRIDRL(i) (REG_ASRIDRLA + (i << 3)) + +#define REG_ASR76K 0x98 +#define REG_ASR56K 0x9C + +#define REG_ASRMCRA 0xA0 +#define REG_ASRFSTA 0xA4 +#define REG_ASRMCRB 0xA8 +#define REG_ASRFSTB 0xAC +#define REG_ASRMCRC 0xB0 +#define REG_ASRFSTC 0xB4 +#define REG_ASRMCR(i) (REG_ASRMCRA + (i << 3)) +#define REG_ASRFST(i) (REG_ASRFSTA + (i << 3)) + +#define REG_ASRMCR1A 0xC0 +#define REG_ASRMCR1B 0xC4 +#define REG_ASRMCR1C 0xC8 +#define REG_ASRMCR1(i) (REG_ASRMCR1A + (i << 2)) + + +/* REG0 0x00 REG_ASRCTR */ +#define ASRCTR_ATSi_SHIFT(i) (20 + i) +#define ASRCTR_ATSi_MASK(i) (1 << ASRCTR_ATSi_SHIFT(i)) +#define ASRCTR_ATS(i) (1 << ASRCTR_ATSi_SHIFT(i)) +#define ASRCTR_USRi_SHIFT(i) (14 + (i << 1)) +#define ASRCTR_USRi_MASK(i) (1 << ASRCTR_USRi_SHIFT(i)) +#define ASRCTR_USR(i) (1 << ASRCTR_USRi_SHIFT(i)) +#define ASRCTR_IDRi_SHIFT(i) (13 + (i << 1)) +#define ASRCTR_IDRi_MASK(i) (1 << ASRCTR_IDRi_SHIFT(i)) +#define ASRCTR_IDR(i) (1 << ASRCTR_IDRi_SHIFT(i)) +#define ASRCTR_SRST_SHIFT 4 +#define ASRCTR_SRST_MASK (1 << ASRCTR_SRST_SHIFT) +#define ASRCTR_SRST (1 << ASRCTR_SRST_SHIFT) +#define ASRCTR_ASRCEi_SHIFT(i) (1 + i) +#define ASRCTR_ASRCEi_MASK(i) (1 << ASRCTR_ASRCEi_SHIFT(i)) +#define ASRCTR_ASRCE(i) (1 << ASRCTR_ASRCEi_SHIFT(i)) +#define ASRCTR_ASRCEi_ALL_MASK (0x7 << ASRCTR_ASRCEi_SHIFT(0)) +#define ASRCTR_ASRCEN_SHIFT 0 +#define ASRCTR_ASRCEN_MASK (1 << ASRCTR_ASRCEN_SHIFT) +#define ASRCTR_ASRCEN (1 << ASRCTR_ASRCEN_SHIFT) + +/* REG1 0x04 REG_ASRIER */ +#define ASRIER_AFPWE_SHIFT 7 +#define ASRIER_AFPWE_MASK (1 << ASRIER_AFPWE_SHIFT) +#define ASRIER_AFPWE (1 << ASRIER_AFPWE_SHIFT) +#define ASRIER_AOLIE_SHIFT 6 +#define ASRIER_AOLIE_MASK (1 << ASRIER_AOLIE_SHIFT) +#define ASRIER_AOLIE (1 << ASRIER_AOLIE_SHIFT) +#define ASRIER_ADOEi_SHIFT(i) (3 + i) +#define ASRIER_ADOEi_MASK(i) (1 << ASRIER_ADOEi_SHIFT(i)) +#define ASRIER_ADOE(i) (1 << ASRIER_ADOEi_SHIFT(i)) +#define ASRIER_ADIEi_SHIFT(i) (0 + i) +#define ASRIER_ADIEi_MASK(i) (1 << ASRIER_ADIEi_SHIFT(i)) +#define ASRIER_ADIE(i) (1 << ASRIER_ADIEi_SHIFT(i)) + +/* REG2 0x0C REG_ASRCNCR */ +#define ASRCNCR_ANCi_SHIFT(i, b) (b * i) +#define ASRCNCR_ANCi_MASK(i, b) (((1 << b) - 1) << ASRCNCR_ANCi_SHIFT(i, b)) +#define ASRCNCR_ANCi(i, v, b) ((v << ASRCNCR_ANCi_SHIFT(i, b)) & ASRCNCR_ANCi_MASK(i, b)) + +/* REG3 0x10 REG_ASRCFG */ +#define ASRCFG_INIRQi_SHIFT(i) (21 + i) +#define ASRCFG_INIRQi_MASK(i) (1 << ASRCFG_INIRQi_SHIFT(i)) +#define ASRCFG_INIRQi (1 << ASRCFG_INIRQi_SHIFT(i)) +#define ASRCFG_NDPRi_SHIFT(i) (18 + i) +#define ASRCFG_NDPRi_MASK(i) (1 << ASRCFG_NDPRi_SHIFT(i)) +#define ASRCFG_NDPRi (1 << ASRCFG_NDPRi_SHIFT(i)) +#define ASRCFG_POSTMODi_SHIFT(i) (8 + (i << 2)) +#define ASRCFG_POSTMODi_WIDTH 2 +#define ASRCFG_POSTMODi_MASK(i) (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_POSTMOD(i, v) ((v) << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_POSTMODi_UP(i) (0 << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_POSTMODi_DCON(i) (1 << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_POSTMODi_DOWN(i) (2 << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_PREMODi_SHIFT(i) (6 + (i << 2)) +#define ASRCFG_PREMODi_WIDTH 2 +#define ASRCFG_PREMODi_MASK(i) (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMOD(i, v) ((v) << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMODi_UP(i) (0 << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMODi_DCON(i) (1 << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMODi_DOWN(i) (2 << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMODi_BYPASS(i) (3 << ASRCFG_PREMODi_SHIFT(i)) + +/* REG4 0x14 REG_ASRCSR */ +#define ASRCSR_AxCSi_WIDTH 4 +#define ASRCSR_AxCSi_MASK ((1 << ASRCSR_AxCSi_WIDTH) - 1) +#define ASRCSR_AOCSi_SHIFT(i) (12 + (i << 2)) +#define ASRCSR_AOCSi_MASK(i) (((1 << ASRCSR_AxCSi_WIDTH) - 1) << ASRCSR_AOCSi_SHIFT(i)) +#define ASRCSR_AOCS(i, v) ((v) << ASRCSR_AOCSi_SHIFT(i)) +#define ASRCSR_AICSi_SHIFT(i) (i << 2) +#define ASRCSR_AICSi_MASK(i) (((1 << ASRCSR_AxCSi_WIDTH) - 1) << ASRCSR_AICSi_SHIFT(i)) +#define ASRCSR_AICS(i, v) ((v) << ASRCSR_AICSi_SHIFT(i)) + +/* REG5&6 0x18 & 0x1C REG_ASRCDR1 & ASRCDR2 */ +#define ASRCDRi_AxCPi_WIDTH 3 +#define ASRCDRi_AICPi_SHIFT(i) (0 + (i % 2) * 6) +#define ASRCDRi_AICPi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AICPi_SHIFT(i)) +#define ASRCDRi_AICP(i, v) ((v) << ASRCDRi_AICPi_SHIFT(i)) +#define ASRCDRi_AICDi_SHIFT(i) (3 + (i % 2) * 6) +#define ASRCDRi_AICDi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AICDi_SHIFT(i)) +#define ASRCDRi_AICD(i, v) ((v) << ASRCDRi_AICDi_SHIFT(i)) +#define ASRCDRi_AOCPi_SHIFT(i) ((i < 2) ? 12 + i * 6 : 6) +#define ASRCDRi_AOCPi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AOCPi_SHIFT(i)) +#define ASRCDRi_AOCP(i, v) ((v) << ASRCDRi_AOCPi_SHIFT(i)) +#define ASRCDRi_AOCDi_SHIFT(i) ((i < 2) ? 15 + i * 6 : 9) +#define ASRCDRi_AOCDi_MASK(i) (((1 << ASRCDRi_AxCPi_WIDTH) - 1) << ASRCDRi_AOCDi_SHIFT(i)) +#define ASRCDRi_AOCD(i, v) ((v) << ASRCDRi_AOCDi_SHIFT(i)) + +/* REG7 0x20 REG_ASRSTR */ +#define ASRSTR_DSLCNT_SHIFT 21 +#define ASRSTR_DSLCNT_MASK (1 << ASRSTR_DSLCNT_SHIFT) +#define ASRSTR_DSLCNT (1 << ASRSTR_DSLCNT_SHIFT) +#define ASRSTR_ATQOL_SHIFT 20 +#define ASRSTR_ATQOL_MASK (1 << ASRSTR_ATQOL_SHIFT) +#define ASRSTR_ATQOL (1 << ASRSTR_ATQOL_SHIFT) +#define ASRSTR_AOOLi_SHIFT(i) (17 + i) +#define ASRSTR_AOOLi_MASK(i) (1 << ASRSTR_AOOLi_SHIFT(i)) +#define ASRSTR_AOOL(i) (1 << ASRSTR_AOOLi_SHIFT(i)) +#define ASRSTR_AIOLi_SHIFT(i) (14 + i) +#define ASRSTR_AIOLi_MASK(i) (1 << ASRSTR_AIOLi_SHIFT(i)) +#define ASRSTR_AIOL(i) (1 << ASRSTR_AIOLi_SHIFT(i)) +#define ASRSTR_AODOi_SHIFT(i) (11 + i) +#define ASRSTR_AODOi_MASK(i) (1 << ASRSTR_AODOi_SHIFT(i)) +#define ASRSTR_AODO(i) (1 << ASRSTR_AODOi_SHIFT(i)) +#define ASRSTR_AIDUi_SHIFT(i) (8 + i) +#define ASRSTR_AIDUi_MASK(i) (1 << ASRSTR_AIDUi_SHIFT(i)) +#define ASRSTR_AIDU(i) (1 << ASRSTR_AIDUi_SHIFT(i)) +#define ASRSTR_FPWT_SHIFT 7 +#define ASRSTR_FPWT_MASK (1 << ASRSTR_FPWT_SHIFT) +#define ASRSTR_FPWT (1 << ASRSTR_FPWT_SHIFT) +#define ASRSTR_AOLE_SHIFT 6 +#define ASRSTR_AOLE_MASK (1 << ASRSTR_AOLE_SHIFT) +#define ASRSTR_AOLE (1 << ASRSTR_AOLE_SHIFT) +#define ASRSTR_AODEi_SHIFT(i) (3 + i) +#define ASRSTR_AODFi_MASK(i) (1 << ASRSTR_AODEi_SHIFT(i)) +#define ASRSTR_AODF(i) (1 << ASRSTR_AODEi_SHIFT(i)) +#define ASRSTR_AIDEi_SHIFT(i) (0 + i) +#define ASRSTR_AIDEi_MASK(i) (1 << ASRSTR_AIDEi_SHIFT(i)) +#define ASRSTR_AIDE(i) (1 << ASRSTR_AIDEi_SHIFT(i)) + +/* REG10 0x54 REG_ASRTFR1 */ +#define ASRTFR1_TF_BASE_WIDTH 7 +#define ASRTFR1_TF_BASE_SHIFT 6 +#define ASRTFR1_TF_BASE_MASK (((1 << ASRTFR1_TF_BASE_WIDTH) - 1) << ASRTFR1_TF_BASE_SHIFT) +#define ASRTFR1_TF_BASE(i) ((i) << ASRTFR1_TF_BASE_SHIFT) + +/* + * REG22 0xA0 REG_ASRMCRA + * REG24 0xA8 REG_ASRMCRB + * REG26 0xB0 REG_ASRMCRC + */ +#define ASRMCRi_ZEROBUFi_SHIFT 23 +#define ASRMCRi_ZEROBUFi_MASK (1 << ASRMCRi_ZEROBUFi_SHIFT) +#define ASRMCRi_ZEROBUFi (1 << ASRMCRi_ZEROBUFi_SHIFT) +#define ASRMCRi_EXTTHRSHi_SHIFT 22 +#define ASRMCRi_EXTTHRSHi_MASK (1 << ASRMCRi_EXTTHRSHi_SHIFT) +#define ASRMCRi_EXTTHRSHi (1 << ASRMCRi_EXTTHRSHi_SHIFT) +#define ASRMCRi_BUFSTALLi_SHIFT 21 +#define ASRMCRi_BUFSTALLi_MASK (1 << ASRMCRi_BUFSTALLi_SHIFT) +#define ASRMCRi_BUFSTALLi (1 << ASRMCRi_BUFSTALLi_SHIFT) +#define ASRMCRi_BYPASSPOLYi_SHIFT 20 +#define ASRMCRi_BYPASSPOLYi_MASK (1 << ASRMCRi_BYPASSPOLYi_SHIFT) +#define ASRMCRi_BYPASSPOLYi (1 << ASRMCRi_BYPASSPOLYi_SHIFT) +#define ASRMCRi_OUTFIFO_THRESHOLD_WIDTH 6 +#define ASRMCRi_OUTFIFO_THRESHOLD_SHIFT 12 +#define ASRMCRi_OUTFIFO_THRESHOLD_MASK (((1 << ASRMCRi_OUTFIFO_THRESHOLD_WIDTH) - 1) << ASRMCRi_OUTFIFO_THRESHOLD_SHIFT) +#define ASRMCRi_OUTFIFO_THRESHOLD(v) (((v) << ASRMCRi_OUTFIFO_THRESHOLD_SHIFT) & ASRMCRi_OUTFIFO_THRESHOLD_MASK) +#define ASRMCRi_RSYNIFi_SHIFT 11 +#define ASRMCRi_RSYNIFi_MASK (1 << ASRMCRi_RSYNIFi_SHIFT) +#define ASRMCRi_RSYNIFi (1 << ASRMCRi_RSYNIFi_SHIFT) +#define ASRMCRi_RSYNOFi_SHIFT 10 +#define ASRMCRi_RSYNOFi_MASK (1 << ASRMCRi_RSYNOFi_SHIFT) +#define ASRMCRi_RSYNOFi (1 << ASRMCRi_RSYNOFi_SHIFT) +#define ASRMCRi_INFIFO_THRESHOLD_WIDTH 6 +#define ASRMCRi_INFIFO_THRESHOLD_SHIFT 0 +#define ASRMCRi_INFIFO_THRESHOLD_MASK (((1 << ASRMCRi_INFIFO_THRESHOLD_WIDTH) - 1) << ASRMCRi_INFIFO_THRESHOLD_SHIFT) +#define ASRMCRi_INFIFO_THRESHOLD(v) (((v) << ASRMCRi_INFIFO_THRESHOLD_SHIFT) & ASRMCRi_INFIFO_THRESHOLD_MASK) + +/* + * REG23 0xA4 REG_ASRFSTA + * REG25 0xAC REG_ASRFSTB + * REG27 0xB4 REG_ASRFSTC + */ +#define ASRFSTi_OAFi_SHIFT 23 +#define ASRFSTi_OAFi_MASK (1 << ASRFSTi_OAFi_SHIFT) +#define ASRFSTi_OAFi (1 << ASRFSTi_OAFi_SHIFT) +#define ASRFSTi_OUTPUT_FIFO_WIDTH 7 +#define ASRFSTi_OUTPUT_FIFO_SHIFT 12 +#define ASRFSTi_OUTPUT_FIFO_MASK (((1 << ASRFSTi_OUTPUT_FIFO_WIDTH) - 1) << ASRFSTi_OUTPUT_FIFO_SHIFT) +#define ASRFSTi_IAEi_SHIFT 11 +#define ASRFSTi_IAEi_MASK (1 << ASRFSTi_OAFi_SHIFT) +#define ASRFSTi_IAEi (1 << ASRFSTi_OAFi_SHIFT) +#define ASRFSTi_INPUT_FIFO_WIDTH 7 +#define ASRFSTi_INPUT_FIFO_SHIFT 0 +#define ASRFSTi_INPUT_FIFO_MASK ((1 << ASRFSTi_INPUT_FIFO_WIDTH) - 1) + +/* REG28 0xC0 & 0xC4 & 0xC8 REG_ASRMCR1i */ +#define ASRMCR1i_IWD_WIDTH 3 +#define ASRMCR1i_IWD_SHIFT 9 +#define ASRMCR1i_IWD_MASK (((1 << ASRMCR1i_IWD_WIDTH) - 1) << ASRMCR1i_IWD_SHIFT) +#define ASRMCR1i_IWD(v) ((v) << ASRMCR1i_IWD_SHIFT) +#define ASRMCR1i_IMSB_SHIFT 8 +#define ASRMCR1i_IMSB_MASK (1 << ASRMCR1i_IMSB_SHIFT) +#define ASRMCR1i_IMSB_MSB (1 << ASRMCR1i_IMSB_SHIFT) +#define ASRMCR1i_IMSB_LSB (0 << ASRMCR1i_IMSB_SHIFT) +#define ASRMCR1i_OMSB_SHIFT 2 +#define ASRMCR1i_OMSB_MASK (1 << ASRMCR1i_OMSB_SHIFT) +#define ASRMCR1i_OMSB_MSB (1 << ASRMCR1i_OMSB_SHIFT) +#define ASRMCR1i_OMSB_LSB (0 << ASRMCR1i_OMSB_SHIFT) +#define ASRMCR1i_OSGN_SHIFT 1 +#define ASRMCR1i_OSGN_MASK (1 << ASRMCR1i_OSGN_SHIFT) +#define ASRMCR1i_OSGN (1 << ASRMCR1i_OSGN_SHIFT) +#define ASRMCR1i_OW16_SHIFT 0 +#define ASRMCR1i_OW16_MASK (1 << ASRMCR1i_OW16_SHIFT) +#define ASRMCR1i_OW16(v) ((v) << ASRMCR1i_OW16_SHIFT) + + +enum asrc_pair_index { + ASRC_INVALID_PAIR = -1, + ASRC_PAIR_A = 0, + ASRC_PAIR_B = 1, + ASRC_PAIR_C = 2, +}; + +#define ASRC_PAIR_MAX_NUM (ASRC_PAIR_C + 1) + +enum asrc_inclk { + INCLK_NONE = 0x03, + INCLK_ESAI_RX = 0x00, + INCLK_SSI1_RX = 0x01, + INCLK_SSI2_RX = 0x02, + INCLK_SSI3_RX = 0x07, + INCLK_SPDIF_RX = 0x04, + INCLK_MLB_CLK = 0x05, + INCLK_PAD = 0x06, + INCLK_ESAI_TX = 0x08, + INCLK_SSI1_TX = 0x09, + INCLK_SSI2_TX = 0x0a, + INCLK_SSI3_TX = 0x0b, + INCLK_SPDIF_TX = 0x0c, + INCLK_ASRCK1_CLK = 0x0f, +}; + +enum asrc_outclk { + OUTCLK_NONE = 0x03, + OUTCLK_ESAI_TX = 0x00, + OUTCLK_SSI1_TX = 0x01, + OUTCLK_SSI2_TX = 0x02, + OUTCLK_SSI3_TX = 0x07, + OUTCLK_SPDIF_TX = 0x04, + OUTCLK_MLB_CLK = 0x05, + OUTCLK_PAD = 0x06, + OUTCLK_ESAI_RX = 0x08, + OUTCLK_SSI1_RX = 0x09, + OUTCLK_SSI2_RX = 0x0a, + OUTCLK_SSI3_RX = 0x0b, + OUTCLK_SPDIF_RX = 0x0c, + OUTCLK_ASRCK1_CLK = 0x0f, +}; + +#define ASRC_CLK_MAX_NUM 16 + +enum asrc_word_width { + ASRC_WIDTH_24_BIT = 0, + ASRC_WIDTH_16_BIT = 1, + ASRC_WIDTH_8_BIT = 2, +}; + +struct asrc_config { + enum asrc_pair_index pair; + unsigned int channel_num; + unsigned int buffer_num; + unsigned int dma_buffer_size; + unsigned int input_sample_rate; + unsigned int output_sample_rate; + enum asrc_word_width input_word_width; + enum asrc_word_width output_word_width; + enum asrc_inclk inclk; + enum asrc_outclk outclk; +}; + +struct asrc_req { + unsigned int chn_num; + enum asrc_pair_index index; +}; + +struct asrc_querybuf { + unsigned int buffer_index; + unsigned int input_length; + unsigned int output_length; + unsigned long input_offset; + unsigned long output_offset; +}; + +struct asrc_convert_buffer { + void *input_buffer_vaddr; + void *output_buffer_vaddr; + unsigned int input_buffer_length; + unsigned int output_buffer_length; +}; + +struct asrc_status_flags { + enum asrc_pair_index index; + unsigned int overload_error; +}; + +enum asrc_error_status { + ASRC_TASK_Q_OVERLOAD = 0x01, + ASRC_OUTPUT_TASK_OVERLOAD = 0x02, + ASRC_INPUT_TASK_OVERLOAD = 0x04, + ASRC_OUTPUT_BUFFER_OVERFLOW = 0x08, + ASRC_INPUT_BUFFER_UNDERRUN = 0x10, +}; + +struct dma_block { + dma_addr_t dma_paddr; + void *dma_vaddr; + unsigned int length; +}; + +/** + * fsl_asrc_pair: ASRC Pair private data + * + * @asrc_priv: pointer to its parent module + * @config: configuration profile + * @error: error record + * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C) + * @channels: occupied channel number + * @desc: input and output dma descriptors + * @dma_chan: inputer and output DMA channels + * @dma_data: private dma data + * @pos: hardware pointer position + * @private: pair private area + */ +struct fsl_asrc_pair { + struct fsl_asrc *asrc_priv; + struct asrc_config *config; + unsigned int error; + + enum asrc_pair_index index; + unsigned int channels; + + struct dma_async_tx_descriptor *desc[2]; + struct dma_chan *dma_chan[2]; + struct imx_dma_data dma_data; + unsigned int pos; + + void *private; +}; + +/** + * fsl_asrc_pair: ASRC private data + * + * @dma_params_rx: DMA parameters for receive channel + * @dma_params_tx: DMA parameters for transmit channel + * @pdev: platform device pointer + * @regmap: regmap handler + * @paddr: physical address to the base address of registers + * @mem_clk: clock source to access register + * @ipg_clk: clock source to drive peripheral + * @asrck_clk: clock sources to driver ASRC internal logic + * @lock: spin lock for resource protection + * @pair: pair pointers + * @channel_bits: width of ASRCNCR register for each pair + * @channel_avail: non-occupied channel numbers + * @asrc_rate: default sample rate for ASoC Back-Ends + * @asrc_width: default sample width for ASoC Back-Ends + * @name: driver name + */ +struct fsl_asrc { + struct snd_dmaengine_dai_dma_data dma_params_rx; + struct snd_dmaengine_dai_dma_data dma_params_tx; + struct platform_device *pdev; + struct regmap *regmap; + unsigned long paddr; + struct clk *mem_clk; + struct clk *ipg_clk; + struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; + spinlock_t lock; + + struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM]; + unsigned int channel_bits; + unsigned int channel_avail; + + int asrc_rate; + int asrc_width; + + char name[32]; +}; + +extern struct snd_soc_platform_driver fsl_asrc_platform; +struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir); +#endif /* _FSL_ASRC_H */ diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c new file mode 100644 index 0000000..5b1e73e --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -0,0 +1,386 @@ +/* + * Freescale ASRC ALSA SoC Platform (DMA) driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen nicoleotsuka@gmail.com + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/platform_data/dma-imx.h> +#include <sound/dmaengine_pcm.h> +#include <sound/pcm_params.h> + +#include "fsl_asrc.h" + +#define FSL_ASRC_DMABUF_SIZE (256 * 1024) + +static struct snd_pcm_hardware snd_imx_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .buffer_bytes_max = FSL_ASRC_DMABUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = 65535, /* Limited by SDMA engine */ + .periods_min = 2, + .periods_max = 255, + .fifo_size = 0, +}; + +static bool filter(struct dma_chan *chan, void *param) +{ + if (!imx_dma_is_general_purpose(chan)) + return false; + + chan->private = param; + + return true; +} + +static void fsl_asrc_dma_complete(void *arg) +{ + struct snd_pcm_substream *substream = arg; + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + + pair->pos += snd_pcm_lib_period_bytes(substream); + if (pair->pos >= snd_pcm_lib_buffer_bytes(substream)) + pair->pos = 0; + + snd_pcm_period_elapsed(substream); +} + +static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream) +{ + u8 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUT : IN; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + struct device *dev = rtd->platform->dev; + unsigned long flags = DMA_CTRL_ACK; + + /* Prepare and submit Front-End DMA channel */ + if (!substream->runtime->no_period_wakeup) + flags |= DMA_PREP_INTERRUPT; + + pair->pos = 0; + pair->desc[!dir] = dmaengine_prep_dma_cyclic( + pair->dma_chan[!dir], runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), + dir == OUT ? DMA_TO_DEVICE : DMA_FROM_DEVICE, flags); + if (!pair->desc[!dir]) { + dev_err(dev, "failed to prepare slave DMA for Front-End\n"); + return -ENOMEM; + } + + pair->desc[!dir]->callback = fsl_asrc_dma_complete; + pair->desc[!dir]->callback_param = substream; + + dmaengine_submit(pair->desc[!dir]); + + /* Prepare and submit Back-End DMA channel */ + pair->desc[dir] = dmaengine_prep_dma_cyclic( + pair->dma_chan[dir], 0xffff, 64, 64, DMA_DEV_TO_DEV, 0); + if (!pair->desc[dir]) { + dev_err(dev, "failed to prepare slave DMA for Back-End\n"); + return -ENOMEM; + } + + dmaengine_submit(pair->desc[dir]); + + return 0; +} + +static int fsl_asrc_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = fsl_asrc_dma_prepare_and_submit(substream); + if (ret) + return ret; + dma_async_issue_pending(pair->dma_chan[IN]); + dma_async_issue_pending(pair->dma_chan[OUT]); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dmaengine_terminate_all(pair->dma_chan[OUT]); + dmaengine_terminate_all(pair->dma_chan[IN]); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; + struct snd_dmaengine_dai_dma_data *dma_params_be = NULL; + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + struct fsl_asrc *asrc_priv = pair->asrc_priv; + struct dma_slave_config config_fe, config_be; + enum asrc_pair_index index = pair->index; + struct device *dev = rtd->platform->dev; + int stream = substream->stream; + struct imx_dma_data *tmp_data; + struct snd_soc_dpcm *dpcm; + struct dma_chan *tmp_chan; + struct device *dev_be; + u8 dir = tx ? OUT : IN; + dma_cap_mask_t mask; + int ret; + + /* Fetch the Back-End dma_data from DPCM */ + list_for_each_entry(dpcm, &rtd->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + struct snd_pcm_substream *substream_be; + struct snd_soc_dai *dai = be->cpu_dai; + + if (dpcm->fe != rtd) + continue; + + substream_be = snd_soc_dpcm_get_substream(be, stream); + dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be); + dev_be = dai->dev; + break; + } + + if (!dma_params_be) { + dev_err(dev, "failed to get the substream of Back-End\n"); + return -EINVAL; + } + + /* Override dma_data of the Front-End and config its dmaengine */ + dma_params_fe = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + dma_params_fe->addr = asrc_priv->paddr + REG_ASRDx(!dir, index); + dma_params_fe->maxburst = dma_params_be->maxburst; + + pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir); + if (!pair->dma_chan[!dir]) { + dev_err(dev, "failed to request DMA channel\n"); + return -EINVAL; + } + + memset(&config_fe, 0, sizeof(config_fe)); + ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &config_fe); + if (ret) { + dev_err(dev, "failed to prepare DMA config for Front-End\n"); + return ret; + } + + ret = dmaengine_slave_config(pair->dma_chan[!dir], &config_fe); + if (ret) { + dev_err(dev, "failed to config DMA channel for Front-End\n"); + return ret; + } + + /* Request and config DMA channel for Back-End */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_CYCLIC, mask); + + /* Get DMA request of Back-End */ + tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); + tmp_data = tmp_chan->private; + pair->dma_data.dma_request = tmp_data->dma_request; + dma_release_channel(tmp_chan); + + /* Get DMA request of Front-End */ + tmp_chan = fsl_asrc_get_dma_channel(pair, dir); + tmp_data = tmp_chan->private; + pair->dma_data.dma_request2 = tmp_data->dma_request; + pair->dma_data.peripheral_type = tmp_data->peripheral_type; + pair->dma_data.priority = tmp_data->priority; + dma_release_channel(tmp_chan); + + pair->dma_chan[dir] = dma_request_channel(mask, filter, &pair->dma_data); + if (!pair->dma_chan[dir]) { + dev_err(dev, "failed to request DMA channel for Back-End\n"); + return -EINVAL; + } + + if (asrc_priv->asrc_width == 16) + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + + config_be.direction = DMA_DEV_TO_DEV; + config_be.src_addr_width = buswidth; + config_be.src_maxburst = dma_params_be->maxburst; + config_be.dst_addr_width = buswidth; + config_be.dst_maxburst = dma_params_be->maxburst; + + if (tx) { + config_be.src_addr = asrc_priv->paddr + REG_ASRDO(index); + config_be.dst_addr = dma_params_be->addr; + } else { + config_be.dst_addr = asrc_priv->paddr + REG_ASRDI(index); + config_be.src_addr = dma_params_be->addr; + } + + ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be); + if (ret) { + dev_err(dev, "failed to config DMA channel for Back-End\n"); + return ret; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + return 0; +} + +static int fsl_asrc_dma_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + + snd_pcm_set_runtime_buffer(substream, NULL); + + if (pair->dma_chan[IN]) + dma_release_channel(pair->dma_chan[IN]); + + if (pair->dma_chan[OUT]) + dma_release_channel(pair->dma_chan[OUT]); + + pair->dma_chan[IN] = NULL; + pair->dma_chan[OUT] = NULL; + + return 0; +} + +static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct device *dev = rtd->platform->dev; + struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + struct fsl_asrc_pair *pair; + + pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL); + if (!pair) { + dev_err(dev, "failed to allocate pair\n"); + return -ENOMEM; + } + + pair->asrc_priv = asrc_priv; + + runtime->private_data = pair; + + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); + + return 0; +} + +static int fsl_asrc_dma_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + struct fsl_asrc *asrc_priv = pair->asrc_priv; + + if (pair && asrc_priv->pair[pair->index] == pair) + asrc_priv->pair[pair->index] = NULL; + + kfree(pair); + + return 0; +} + +static snd_pcm_uframes_t fsl_asrc_dma_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsl_asrc_pair *pair = runtime->private_data; + + return bytes_to_frames(substream->runtime, pair->pos); +} + +static struct snd_pcm_ops fsl_asrc_dma_pcm_ops = { + .ioctl = snd_pcm_lib_ioctl, + .hw_params = fsl_asrc_dma_hw_params, + .hw_free = fsl_asrc_dma_hw_free, + .trigger = fsl_asrc_dma_trigger, + .open = fsl_asrc_dma_startup, + .close = fsl_asrc_dma_shutdown, + .pointer = fsl_asrc_dma_pcm_pointer, +}; + +static int fsl_asrc_dma_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm_substream *substream; + struct snd_pcm *pcm = rtd->pcm; + int ret, i; + + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(card->dev, "failed to set DMA mask\n"); + return ret; + } + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_LAST; i++) { + substream = pcm->streams[i].substream; + if (!substream) + continue; + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, + FSL_ASRC_DMABUF_SIZE, &substream->dma_buffer); + if (ret) { + dev_err(card->dev, "failed to allocate DMA buffer\n"); + goto err; + } + } + + return 0; + +err: + if (--i == 0 && pcm->streams[i].substream) + snd_dma_free_pages(&pcm->streams[i].substream->dma_buffer); + + return ret; +} + +static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + int i; + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_LAST; i++) { + substream = pcm->streams[i].substream; + if (!substream) + continue; + + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } +} + +struct snd_soc_platform_driver fsl_asrc_platform = { + .ops = &fsl_asrc_dma_pcm_ops, + .pcm_new = fsl_asrc_dma_pcm_new, + .pcm_free = fsl_asrc_dma_pcm_free, +}; +EXPORT_SYMBOL_GPL(fsl_asrc_platform);
On 07/25/2014 09:33 AM, Nicolin Chen wrote:
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a signal associated with an input clock into a signal associated with a different output clock. The driver currently works as a Front End of DPCM with other Back Ends DAI links such as ESAI<->CS42888 and SSI<->WM8962 and SAI. It converts the original sample rate to a common rate supported by Back Ends for playback while converts the common rate of Back Ends to a desired rate for capture. It has 3 pairs to support three different substreams within totally 10 channels.
(...)
+Required properties:
- compatible : Compatible list, must contain "fsl,imx35-asrc" or
- "fsl,imx53-asrc".
- reg : Offset and length of the register set for the device.
- interrupts : Contains the spdif interrupt.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Six dmas have to be defined: "rxa", "rxb", "rxc", "txa", "txb",
and "txc".
- clocks : Contains an entry for each entry in clock-names.
- clock-names : Includes the following entries:
- "mem" Peripheral access clock to access registers.
- "ipg" Peripheral clock to driver module.
- "asrck_<0-f>" Clock sources for input and output clock.
- big-endian : If this property is absent, the native endian mode will
be in use as default, or the big endian mode will be in use
for all the device registers.
- fsl,asrc-rate : Defines a mutual sample rate used by Back End DAI link.
- fsl,asrc-width : Defines a mutual sample width used by Back End DAI link.
indentation for the properties....
- compatible : Should be "fsl,imx35-asrc" or "fsl,imx53-asrc". - reg : Offset and length of the register set for the device. ....
(...)
+static const struct platform_device_id fsl_asrc_devtype[] = {
- {
.name = "imx35-asrc",
.driver_data = IMX35_ASRC,
- }, {
.name = "imx53-asrc",
.driver_data = IMX53_ASRC,
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(platform, fsl_asrc_devtype);
+static const struct of_device_id fsl_asrc_ids[] = {
- {
.compatible = "fsl,imx35-asrc",
.data = &fsl_asrc_devtype[IMX35_ASRC],
- }, {
.compatible = "fsl,imx53-asrc",
.data = &fsl_asrc_devtype[IMX53_ASRC],
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(of, fsl_asrc_ids);
move these ids after probe/remove... every driver follows same thing...
+static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) +{
- struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id;
- struct device *dev = &asrc_priv->pdev->dev;
- enum asrc_pair_index index;
- u32 status;
- regmap_read(asrc_priv->regmap, REG_ASRSTR, &status);
- /* Clean overload error */
- regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE);
- /*
* We here use dev_dbg() for all exceptions because ASRC itself does
* not care if FIFO overflowed or underrun while a warning in the
* interrupt would result a ridged conversion.
*/
- for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) {
if (!asrc_priv->pair[index])
continue;
if (status & ASRSTR_ATQOL) {
asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD;
dev_dbg(dev, "ASRC Task Queue FIFO overload");
missed terminating new line (\n)...
}
if (status & ASRSTR_AOOL(index)) {
asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD;
pair_dbg("Output Task Overload");
same
}
if (status & ASRSTR_AIOL(index)) {
asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD;
pair_dbg("Input Task Overload");
same
}
if (status & ASRSTR_AODO(index)) {
asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW;
pair_dbg("Output Data Buffer has overflowed");
same
}
if (status & ASRSTR_AIDU(index)) {
asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN;
pair_dbg("Input Data Buffer has underflowed");
same..
}
- }
- return IRQ_HANDLED;
+}
(...)
+/**
- Configure input and output thresholds
- */
+static int fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) +{
static void for function..?
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
- enum asrc_pair_index index = pair->index;
- regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
ASRMCRi_EXTTHRSHi_MASK |
ASRMCRi_INFIFO_THRESHOLD_MASK |
ASRMCRi_OUTFIFO_THRESHOLD_MASK,
ASRMCRi_EXTTHRSHi |
ASRMCRi_INFIFO_THRESHOLD(in) |
ASRMCRi_OUTFIFO_THRESHOLD(out));
- return 0;
+}
(...)
+static const struct dev_pm_ops fsl_asrc_pm = {
- SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume)
+};
move device ids to here...
+static struct platform_driver fsl_asrc_driver = {
- .probe = fsl_asrc_probe,
- .driver = {
.name = "fsl-asrc",
.of_match_table = fsl_asrc_ids,
.pm = &fsl_asrc_pm,
- },
+}; +module_platform_driver(fsl_asrc_driver);
Thanks...
Hi Varka,
On Fri, Jul 25, 2014 at 09:54:43AM +0530, Varka Bhadram wrote:
On 07/25/2014 09:33 AM, Nicolin Chen wrote:
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a signal associated with an input clock into a signal associated with a different output clock. The driver currently works as a Front End of DPCM with other Back Ends DAI links such as ESAI<->CS42888 and SSI<->WM8962 and SAI. It converts the original sample rate to a common rate supported by Back Ends for playback while converts the common rate of Back Ends to a desired rate for capture. It has 3 pairs to support three different substreams within totally 10 channels.
(...)
+Required properties:
- compatible : Compatible list, must contain "fsl,imx35-asrc" or
- "fsl,imx53-asrc".
- reg : Offset and length of the register set for the device.
- interrupts : Contains the spdif interrupt.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Six dmas have to be defined: "rxa", "rxb", "rxc", "txa", "txb",
and "txc".
- clocks : Contains an entry for each entry in clock-names.
- clock-names : Includes the following entries:
- "mem" Peripheral access clock to access registers.
- "ipg" Peripheral clock to driver module.
- "asrck_<0-f>" Clock sources for input and output clock.
- big-endian : If this property is absent, the native endian mode will
be in use as default, or the big endian mode will be in use
for all the device registers.
- fsl,asrc-rate : Defines a mutual sample rate used by Back End DAI link.
- fsl,asrc-width : Defines a mutual sample width used by Back End DAI link.
indentation for the properties....
- compatible : Should be "fsl,imx35-asrc" or "fsl,imx53-asrc".
- reg : Offset and length of the register set for the device.
....
(...)
+static const struct platform_device_id fsl_asrc_devtype[] = {
- {
.name = "imx35-asrc",
.driver_data = IMX35_ASRC,
- }, {
.name = "imx53-asrc",
.driver_data = IMX53_ASRC,
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(platform, fsl_asrc_devtype);
+static const struct of_device_id fsl_asrc_ids[] = {
- {
.compatible = "fsl,imx35-asrc",
.data = &fsl_asrc_devtype[IMX35_ASRC],
- }, {
.compatible = "fsl,imx53-asrc",
.data = &fsl_asrc_devtype[IMX53_ASRC],
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(of, fsl_asrc_ids);
move these ids after probe/remove... every driver follows same thing...
+static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) +{
- struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id;
- struct device *dev = &asrc_priv->pdev->dev;
- enum asrc_pair_index index;
- u32 status;
- regmap_read(asrc_priv->regmap, REG_ASRSTR, &status);
- /* Clean overload error */
- regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE);
- /*
* We here use dev_dbg() for all exceptions because ASRC itself does
* not care if FIFO overflowed or underrun while a warning in the
* interrupt would result a ridged conversion.
*/
- for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) {
if (!asrc_priv->pair[index])
continue;
if (status & ASRSTR_ATQOL) {
asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD;
dev_dbg(dev, "ASRC Task Queue FIFO overload");
missed terminating new line (\n)...
}
if (status & ASRSTR_AOOL(index)) {
asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD;
pair_dbg("Output Task Overload");
same
}
if (status & ASRSTR_AIOL(index)) {
asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD;
pair_dbg("Input Task Overload");
same
}
if (status & ASRSTR_AODO(index)) {
asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW;
pair_dbg("Output Data Buffer has overflowed");
same
}
if (status & ASRSTR_AIDU(index)) {
asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN;
pair_dbg("Input Data Buffer has underflowed");
same..
}
- }
- return IRQ_HANDLED;
+}
(...)
+/**
- Configure input and output thresholds
- */
+static int fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) +{
static void for function..?
- struct fsl_asrc *asrc_priv = pair->asrc_priv;
- enum asrc_pair_index index = pair->index;
- regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
ASRMCRi_EXTTHRSHi_MASK |
ASRMCRi_INFIFO_THRESHOLD_MASK |
ASRMCRi_OUTFIFO_THRESHOLD_MASK,
ASRMCRi_EXTTHRSHi |
ASRMCRi_INFIFO_THRESHOLD(in) |
ASRMCRi_OUTFIFO_THRESHOLD(out));
- return 0;
+}
(...)
+static const struct dev_pm_ops fsl_asrc_pm = {
- SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume)
+};
move device ids to here...
I'll fix them all in v4.
Thank you, Nicolin
---
+static struct platform_driver fsl_asrc_driver = {
- .probe = fsl_asrc_probe,
- .driver = {
.name = "fsl-asrc",
.of_match_table = fsl_asrc_ids,
.pm = &fsl_asrc_pm,
- },
+}; +module_platform_driver(fsl_asrc_driver);
Thanks...
-- Regards, Varka Bhadram.
Hi,
What is the best way to test/debug the alc668 driver these days?
I am running kernel 3.14.1 (debian testing/sid).
The laptop is an ASUS N750JK.
Sound works for front left/right speakers but the back speakers and external lfe channel is not working on this laptop.
- I have found a couple of kernel bug reports for other ASUS models with this chipset but they are both marked resolved. Should I open a new ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio test) if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
Pin 0x16 does not appear to work at all.
I see this output when I apply the config in hdajackretask.
0x12 0x90a60140 0x14 0x99130110 0x15 0x04211020 0x16 0x99134111 0x18 0x01a19840 0x19 0x01014011 0x1a 0x411111f0 0x1b 0x411111f0 0x1d 0x40c6852d 0x1e 0x014b1180 0x1f 0x411111f0 1
-- Patrick Shirkey Boost Hardware Ltd
What is the best way to test/debug the alc668 driver these days?
I am running kernel 3.14.1 (debian testing/sid).
The laptop is an ASUS N750JK.
Sound works for front left/right speakers but the back speakers and external lfe channel is not working on this laptop.
You have to post output of alsa-info.sh
Do the BIOS setup all the pin default ?
How many audio jacks ?
Do it support headset or headphone ?
Do you mean there are four internal speakers ?
Do it support surround40 in windows ?
The external sonic master and headphone need two volume controls but alc668 only have three
The best way to test is using latest git version and hda jack retask to
1) four internal speaker and headphone 2) two internal speaker, headphone and external subwoofer
Once you confirm the nodes of the speakers, subwooder You need to decide whether headphone share the volume controls with the speaker/subwoofer
- I have found a couple of kernel bug reports for other ASUS models with
this chipset but they are both marked resolved. Should I open a new ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio test) if
I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
Pin 0x16 does not appear to work at all.
I see this output when I apply the config in hdajackretask.
0x12 0x90a60140 0x14 0x99130110 0x15 0x04211020 0x16 0x99134111 0x18 0x01a19840 0x19 0x01014011 0x1a 0x411111f0 0x1b 0x411111f0 0x1d 0x40c6852d 0x1e 0x014b1180 0x1f 0x411111f0 1
-- Patrick Shirkey Boost Hardware Ltd _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Sat, July 26, 2014 2:01 pm, Raymond Yau wrote:
What is the best way to test/debug the alc668 driver these days?
I am running kernel 3.14.1 (debian testing/sid).
The laptop is an ASUS N750JK.
Sound works for front left/right speakers but the back speakers and external lfe channel is not working on this laptop.
You have to post output of alsa-info.sh
http://boosthardware.com/alsa-info-alc668-n750jk.txt
Do the BIOS setup all the pin default ?
How many audio jacks ?
Standard headphone/mic + yellow external lfe (sonic master). There is also hdmi but I am not testing that at the moment.
Do it support headset or headphone ?
Do you mean there are four internal speakers ?
There are two front speakers which produce sound through the front bottom of the case. There are also two back speakers which do not produce sound in my tests so far.
Do it support surround40 in windows ?
I am not running windows OS on this machine but I suspect it does.
The external sonic master and headphone need two volume controls but alc668 only have three
The best way to test is using latest git version and hda jack retask to
The process has changed somewhat since I last did this.
Turns out that is not such as easy process with the 3.14.1 kernel in debian sid/testing. From the looks of it I have to compile my own kernel to get all the necessary build files.
make[1]: Leaving directory '/home/patrick/code/alsa/alsa-driver/alsa' make -C /lib/modules/3.14-1-amd64/source SUBDIRS=/home/patrick/code/alsa/alsa-driver/alsa CPP="gcc -E" CC="gcc" modules make[1]: Entering directory '/usr/src/linux-headers-3.14-1-common'
ERROR: Kernel configuration is invalid. include/generated/autoconf.h or include/config/auto.conf are missing. Run 'make oldconfig && make prepare' on kernel src to fix it.
WARNING: Symbol version dump /usr/src/linux-headers-3.14-1-common/Module.symvers is missing; modules will have no dependencies and modversions.
find: `/usr/src/linux-headers-3.14-1-common/alsa-kernel/': No such file or directory find: `/usr/src/linux-headers-3.14-1-common/alsa-kernel/': No such file or directory find: `/usr/src/linux-headers-3.14-1-common/alsa-kernel/': No such file or directory Building modules, stage 2. /usr/src/linux-headers-3.14-1-common/scripts/Makefile.modpost:42: include/config/auto.conf: No such file or directory find: `/usr/src/linux-headers-3.14-1-common/alsa-kernel/': No such file or directory find: `/usr/src/linux-headers-3.14-1-common/alsa-kernel/': No such file or directory find: `/usr/src/linux-headers-3.14-1-common/alsa-kernel/': No such file or directory make[2]: *** No rule to make target 'include/config/auto.conf'. Stop. Makefile:1294: recipe for target 'modules' failed make[1]: *** [modules] Error 2 make[1]: Leaving directory '/usr/src/linux-headers-3.14-1-common' Makefile:167: recipe for target 'compile' failed make: *** [compile] Error 2
- four internal speaker and headphone
- two internal speaker, headphone and external subwoofer
Once you confirm the nodes of the speakers, subwooder You need to decide whether headphone share the volume controls with the speaker/subwoofer
I have spent some time on this step already with 3.14.1
Is there a specific reason this process is not already scripted other than no one has taken the time to do it?
Can we not create a test script that will run through all the logical combinations and provide all the relevant info?
- I have found a couple of kernel bug reports for other ASUS models
with this chipset but they are both marked resolved. Should I open a new ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio test)
if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
Pin 0x16 does not appear to work at all.
I see this output when I apply the config in hdajackretask.
0x12 0x90a60140 0x14 0x99130110 0x15 0x04211020 0x16 0x99134111 0x18 0x01a19840 0x19 0x01014011 0x1a 0x411111f0 0x1b 0x411111f0 0x1d 0x40c6852d 0x1e 0x014b1180 0x1f 0x411111f0 1
-- Patrick Shirkey Boost Hardware Ltd
What is the best way to test/debug the alc668 driver these days?
I am running kernel 3.14.1 (debian testing/sid).
The laptop is an ASUS N750JK.
Sound works for front left/right speakers but the back speakers and external lfe channel is not working on this laptop.
You have to post output of alsa-info.sh
Seem BIOS only set up the front speakers
How many audio jacks ?
Standard headphone/mic + yellow external lfe (sonic master). There is also hdmi but I am not testing that at the moment.
http://www.asus.com/Notebooks_Ultrabooks/N750JK/specifications/
Do you mean headset ?
Do it support headset or headphone ?
Do you mean there are four internal speakers ?
There are two front speakers which produce sound through the front bottom of the case. There are also two back speakers which do not produce sound in my tests so far.
Do it support surround40 in windows ?
I am not running windows OS on this machine but I suspect it does.
The external sonic master and headphone need two volume controls but alc668 only have three
The best way to test is using latest git version and hda jack retask to
The process has changed somewhat since I last did this.
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/log/sound/pci/h...
- four internal speaker and headphone
- two internal speaker, headphone and external subwoofer
Once you confirm the nodes of the speakers, subwooder You need to decide whether headphone share the volume controls with the speaker/subwoofer
I have spent some time on this step already with 3.14.1
Did you retask the node of subwoofer as speaker or line out ?
For multi channel, the sequence number is ascending and the driver expect they have same type i.e, all speakers or all line out jacks
Did you find the node of the rear speakers in (1) ?
Did surround 4.0 work when you fix the rear speaker ?
Did you find the node of the external subwoofer in (2) ?
Did the sonic master subwoofer detected ? hda jack sense test -a
Do the subwoofer only use right channel ?
Do surround 2.1 works ?
Is there a specific reason this process is not already scripted other than no one has taken the time to do it?
Do surround 4.1 or 5.1 work when you fix both speaker and subwoofer ?
Do you prefer driver create headphone volume control or subwoofer volume control ?
Can we not create a test script that will run through all the logical combinations and provide all the relevant info?
The driver hardcore the name of volume control to bass when there are two speaker nodes for those 2.1
- I have found a couple of kernel bug reports for other ASUS models
with this chipset but they are both marked resolved. Should I open a new ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio test)
if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
Pin 0x16 does not appear to work at all.
I see this output when I apply the config in hdajackretask.
0x12 0x90a60140 0x14 0x99130110 0x15 0x04211020 0x16 0x99134111 0x18 0x01a19840 0x19 0x01014011 0x1a 0x411111f0 0x1b 0x411111f0 0x1d 0x40c6852d 0x1e 0x014b1180 0x1f 0x411111f0 1
On Tue, July 29, 2014 1:58 pm, Raymond Yau wrote:
What is the best way to test/debug the alc668 driver these days?
I am running kernel 3.14.1 (debian testing/sid).
The laptop is an ASUS N750JK.
Sound works for front left/right speakers but the back speakers and external lfe channel is not working on this laptop.
You have to post output of alsa-info.sh
Seem BIOS only set up the front speakers
There is nothing in the bios to configure the audio device
How many audio jacks ?
Standard headphone/mic + yellow external lfe (sonic master). There is also hdmi but I am not testing that at the moment.
http://www.asus.com/Notebooks_Ultrabooks/N750JK/specifications/
Do you mean headset ?
There are the following jacks:
1 x headphone 1 x mic(line in) 1 x sonic master (yellow) 1 x hdmi (intel Haswell hdmi)
Do it support headset or headphone ?
Do you mean there are four internal speakers ?
There are two front speakers which produce sound through the front bottom of the case. There are also two back speakers which do not produce sound in my tests so far.
Do it support surround40 in windows ?
I am not running windows OS on this machine but I suspect it does.
The external sonic master and headphone need two volume controls but alc668 only have three
The best way to test is using latest git version and hda jack retask
to
The process has changed somewhat since I last did this.
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/log/sound/pci/h...
That suggest not much has changed for a while?
- four internal speaker and headphone
- two internal speaker, headphone and external subwoofer
Once you confirm the nodes of the speakers, subwooder You need to decide whether headphone share the volume controls with
the
speaker/subwoofer
I have spent some time on this step already with 3.14.1
Did you retask the node of subwoofer as speaker or line out ?
I have tried both but I have not been able to identify the subwoofer.
I have tried playing with: 16, 19, 1a
For multi channel, the sequence number is ascending and the driver expect they have same type i.e, all speakers or all line out jacks
Did you find the node of the rear speakers in (1) ?
I have not found them yet.
Did surround 4.0 work when you fix the rear speaker ?
Only the front speakers play audio but they don't work with 4.0 enabled
Did you find the node of the external subwoofer in (2) ?
Not yet.
Did the sonic master subwoofer detected ? hda jack sense test -a
I have grabbed the scripts but I get this error when running hda-analyzer:
Traceback (most recent call last): File "/dev/shm/hda-analyzer/hda_analyzer.py", line 546, in <module> sys.exit(main(sys.argv)) File "/dev/shm/hda-analyzer/hda_analyzer.py", line 523, in main if read_nodes(sys.argv[1:]) == 0: File "/dev/shm/hda-analyzer/hda_analyzer.py", line 89, in read_nodes read_nodes2(c.card, i) File "/dev/shm/hda-analyzer/hda_analyzer.py", line 60, in read_nodes2 c = HDACodec(card, codec) File "/dev/shm/hda-analyzer/hda_codec.py", line 1041, in __init__ self.parse_proc() File "/dev/shm/hda-analyzer/hda_codec.py", line 1140, in parse_proc self.proc_codec = HDACodecProc(self.card, self.device, file) File "/dev/shm/hda-analyzer/hda_proc.py", line 479, in __init__ self.parse(proc_file) File "/dev/shm/hda-analyzer/hda_proc.py", line 677, in parse node.add_digital(line[11:]) File "/dev/shm/hda-analyzer/hda_proc.py", line 296, in add_digital self.wrongfile('unknown dig1 bit %s' % repr(b)) File "/dev/shm/hda-analyzer/hda_proc.py", line 143, in wrongfile raise ValueError, "wrong proc file format (%s)" % msg ValueError: wrong proc file format (unknown dig1 bit 'KAE')
Do the subwoofer only use right channel ?
I cannot hear the subwoofer at this point
Do surround 2.1 works ?
It says it is working but I do not get sound out of the sub woofer. I can hear static(whitenoise) through the front speakers (with pulseaudio test) if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
Is there a specific reason this process is not already scripted other than no one has taken the time to do it?
Do surround 4.1 or 5.1 work when you fix both speaker and subwoofer ?
Surround 4.1/5/1 do not produce any sound from my tests so far (using PA Test)
Do you prefer driver create headphone volume control or subwoofer volume control ?
I would like the lfe to be sent through the yellow sonic master jack. I am not concerned with the headset jack at the moment. A cursory test shows just the right channel is working on the headset jack.
Can we not create a test script that will run through all the logical combinations and provide all the relevant info?
The driver hardcore the name of volume control to bass when there are two speaker nodes for those 2.1
I do not see any controls for the bass volume in alsamixer
- I have found a couple of kernel bug reports for other ASUS models
with this chipset but they are both marked resolved. Should I open a new ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio test)
if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
Pin 0x16 does not appear to work at all.
I see this output when I apply the config in hdajackretask.
0x12 0x90a60140 0x14 0x99130110 0x15 0x04211020 0x16 0x99134111 0x18 0x01a19840 0x19 0x01014011 0x1a 0x411111f0 0x1b 0x411111f0 0x1d 0x40c6852d 0x1e 0x014b1180 0x1f 0x411111f0 1
-- Patrick Shirkey Boost Hardware Ltd
What is the best way to test/debug the alc668 driver these days?
I am running kernel 3.14.1 (debian testing/sid).
The laptop is an ASUS N750JK.
Sound works for front left/right speakers but the back speakers and external lfe channel is not working on this laptop.
You have to post output of alsa-info.sh
Seem BIOS only set up the front speakers
There is nothing in the bios to configure the audio device
How many audio jacks ?
Standard headphone/mic + yellow external lfe (sonic master). There is also hdmi but I am not testing that at the moment.
http://www.asus.com/Notebooks_Ultrabooks/N750JK/specifications/
Do you mean headset ?
There are the following jacks:
1 x headphone
Do you mean no optical spdif ?
1 x mic(line in)
Switching Mic Jack to line in can be performed by mic Jack mode switch using hint add_jack_modes=true
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/Documentat...
1 x sonic master (yellow) 1 x hdmi (intel Haswell hdmi)
Do it support headset or headphone ?
Do you mean there are four internal speakers ?
There are two front speakers which produce sound through the front bottom of the case. There are also two back speakers which do not produce
sound
in my tests so far.
Do it support surround40 in windows ?
I am not running windows OS on this machine but I suspect it does.
The external sonic master and headphone need two volume controls but alc668 only have three
The best way to test is using latest git version and hda jack retask
to
- four internal speaker and headphone
- two internal speaker, headphone and external subwoofer
Once you confirm the nodes of the speakers, subwooder You need to decide whether headphone share the volume controls with
the
speaker/subwoofer
I have spent some time on this step already with 3.14.1
Did you retask the node of subwoofer as speaker or line out ?
I have tried both but I have not been able to identify the subwoofer.
I have tried playing with: 16, 19, 1a
Did you find the node of the rear speakers in (1) ?
I have not found them yet.
Did surround 4.0 work when you fix the rear speaker ?
Only the front speakers play audio but they don't work with 4.0 enabled
Did you find the node of the external subwoofer in (2) ?
Not yet.
Did the sonic master subwoofer detected ? hda jack sense test -a
I have grabbed the scripts but I get this error when running hda-analyzer:
You can use hda-verb GET_PIN_SENSE to test all the pin complex nodes which pincap support DETECT
Do the subwoofer only use right channel ?
I cannot hear the subwoofer at this point
Do surround 2.1 works ?
It says it is working but I do not get sound out of the sub woofer. I can hear static(whitenoise) through the front speakers (with pulseaudio test) if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
http://git.alsa-project.org/?p=alsa-tools.git;a=blob;f=hdajackretask/README;...
Did you use apply button(dyanmic reconfiguartion) or installment boot override (early patching) ?
Is there a specific reason this process is not already scripted other than no one has taken the time to do it?
Do surround 4.1 or 5.1 work when you fix both speaker and subwoofer ?
Surround 4.1/5/1 do not produce any sound from my tests so far (using PA Test)
Do you prefer driver create headphone volume control or subwoofer
volume
control ?
I would like the lfe to be sent through the yellow sonic master jack. I am not concerned with the headset jack at the moment. A cursory test shows just the right channel is working on the headset jack.
Can we not create a test script that will run through all the logical combinations and provide all the relevant info?
The driver hardcore the name of volume control to bass when there are
two
speaker nodes for those 2.1
I do not see any controls for the bass volume in alsamixer
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound/pc...
- I have found a couple of kernel bug reports for other ASUS models
with this chipset but they are both marked resolved. Should I open a new ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio
test)
if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
For multi channel, the sequence number is ascending and the driver
expect
they have same type i.e, all speakers or all line out jacks
Pin Default 0x90170110: [Fixed] Speaker at Int N/A Conn = Analog, Color = Unknown DefAssociation = 0x1, Sequence = 0x0 Misc = NO_PRESENCE
The rear speaker need same default association but sequence number higher than that of the front speaker
The external subwoofer may use [jack] speaker with same default association and higher sequence number if it can be detected
The driver won't use all of them for multi channel if you retasked it as line out
On Thu, July 31, 2014 1:27 pm, Raymond Yau wrote:
You can use hda-verb GET_PIN_SENSE to test all the pin complex nodes which pincap support DETECT
I have tried a few attempts but it's pretty confusing.
These ones don't do anything:
# hda-verb /dev/snd/hwC1D0 GET_PIN_SENSE # hda-verb /dev/snd/hwC1D0 0x0 GET_PIN_SENSE
I don't know what to make of this output:
# hda-verb /dev/snd/hwC1D0 0x0 GET_PIN_SENSE PIN_CAP nid = 0x0, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC0D0 0x0 GET_PIN_SENSE PIN_CAP nid = 0x0, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC0D0 0x16 GET_PIN_SENSE PIN_CAP nid = 0x16, verb = 0xf09, param = 0xc value = 0xffffffff # hda-verb /dev/snd/hwC0D0 0x19 GET_PIN_SENSE PIN_CAP nid = 0x19, verb = 0xf09, param = 0xc value = 0xffffffff # hda-verb /dev/snd/hwC0D0 0x1a GET_PIN_SENSE PIN_CAP nid = 0x1a, verb = 0xf09, param = 0xc value = 0xffffffff # hda-verb /dev/snd/hwC0D0 0x1b GET_PIN_SENSE PIN_CAP nid = 0x1b, verb = 0xf09, param = 0xc value = 0xffffffff
Do surround 2.1 works ?
It says it is working but I do not get sound out of the sub woofer. I can hear static(whitenoise) through the front speakers (with pulseaudio test) if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
http://git.alsa-project.org/?p=alsa-tools.git;a=blob;f=hdajackretask/README;...
Did you use apply button(dyanmic reconfiguartion) or installment boot override (early patching) ?
I have tried both options.
After rebooting with the apply option set I don't hear any static or audio with the PA test app.
I do not see any controls for the bass volume in alsamixer
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound/pc...
I have checked alsamixer again after the last round of tinkering with hdajackretask and" Speaker CLFE" is now showing up but it does not have volume control just mute on/off.
I see the following new controls
Speaker CFLE (mute only) Speaker Front (mute + vol) Speaker Side (mute only) Speaker Surround (mute + vol)
- I have found a couple of kernel bug reports for other ASUS
models
with this chipset but they are both marked resolved. Should I open a
new
ticket ?
https://bugzilla.kernel.org/show_bug.cgi?id=65091 https://bugzilla.kernel.org/show_bug.cgi?id=66271
- I can hear static through the front speakers (with pulseaudio
test)
if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
For multi channel, the sequence number is ascending and the driver
expect
they have same type i.e, all speakers or all line out jacks
Pin Default 0x90170110: [Fixed] Speaker at Int N/A Conn = Analog, Color = Unknown DefAssociation = 0x1, Sequence = 0x0 Misc = NO_PRESENCE
The rear speaker need same default association but sequence number higher than that of the front speaker
The external subwoofer may use [jack] speaker with same default association and higher sequence number if it can be detected
The driver won't use all of them for multi channel if you retasked it as line out
I have tried several combinations with hdajackretask
I am not able to get audio out of the physical rear speakers or sonic master output.
I can get audio to play back in the front l/c/r speakers with varying combinations.
ex.
7.1 side l/r plays through front l/r or front c 4.0 rear r/l plays through front l/r 2.1 l/r plays through front l/r 2.1 subwoofer plays white noise through front c
Most of the time it is only front left/right that make any sound. Sometimes there is no sound on one audio profile but it works on a couple of channels on another profile.
Any time that the Center LFE works it produces white noise.
I have tried with both options: apply and patch/reboot
I can keep playing around with the settings until I eventually stumble on a combination that works but it seems like this process should be scriptable. Given that I will probably spend hours of my time on the test process and I have already spent 4 separate sessions on testing it seems like it would be better value for my time and others going forward to write a test script.
So what do I need to do to write a script that will test all the combinations and play audio through them? Or am I missing something that someone else has already written for this purpose?
Currently I am using this process:
1: hdajackretask - modify params 2: pulseaudio -k 3: hdajackretask : apply settings 4: pulseaudio -D 5: open PA audio config 6: select audio output option and press test speakers button 7: manually press every button
Rinse and repeat.
Surely there is a more humane method for testing the variations ;-)
-- Patrick Shirkey Boost Hardware Ltd
http://git.alsa-project.org/?p=alsa.git;a=commitdiff;h=48ed9474fc6724dc1486d...
Have you try the fix ?
You can use hda-verb GET_PIN_SENSE to test all the pin complex nodes
which
pincap support DETECT
I have tried a few attempts but it's pretty confusing.
These ones don't do anything:
# hda-verb /dev/snd/hwC1D0 GET_PIN_SENSE # hda-verb /dev/snd/hwC1D0 0x0 GET_PIN_SENSE
I don't know what to make of this output:
Bit 31 is PD
VALUE should return 0 when Jack is UNplugged and 0x80000000 when Jack is plugged for those pin which support DETECT
# hda-verb /dev/snd/hwC1D0 0x0 GET_PIN_SENSE PIN_CAP nid = 0x0, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC0D0 0x0 GET_PIN_SENSE PIN_CAP nid = 0x0, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC0D0 0x16 GET_PIN_SENSE PIN_CAP nid = 0x16, verb = 0xf09, param = 0xc value = 0xffffffff # hda-verb /dev/snd/hwC0D0 0x19 GET_PIN_SENSE PIN_CAP nid = 0x19, verb = 0xf09, param = 0xc value = 0xffffffff # hda-verb /dev/snd/hwC0D0 0x1a GET_PIN_SENSE PIN_CAP nid = 0x1a, verb = 0xf09, param = 0xc value = 0xffffffff # hda-verb /dev/snd/hwC0D0 0x1b GET_PIN_SENSE PIN_CAP nid = 0x1b, verb = 0xf09, param = 0xc value = 0xffffffff
But your alc668 is on card 1 , the second hda controller
Do surround 2.1 works ?
It says it is working but I do not get sound out of the sub woofer. I can hear static(whitenoise) through the front speakers (with pulseaudio test) if I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal (Center/LFE) or vice versa with hdajackretask.
http://git.alsa-project.org/?p=alsa-tools.git;a=blob;f=hdajackretask/README;...
Did you use apply button(dyanmic reconfiguartion) or installment boot override (early patching) ?
I have tried both options.
After rebooting with the apply option set I don't hear any static or audio with the PA test app.
I do not see any controls for the bass volume in alsamixer
https://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/commit/sound/pc...
I have checked alsamixer again after the last round of tinkering with hdajackretask and" Speaker CLFE" is now showing up but it does not have volume control just mute on/off.
I see the following new controls
Speaker CFLE (mute only) Speaker Front (mute + vol) Speaker Side (mute only) Speaker Surround (mute + vol)
hda-jack-retask won't check whether your codec have enough audio output if you changed all the nodes to speaker
But the driver expect multiout support up to 8 channels when parsing the pin
As alc668 only support 6 channels, hda_generic.c just assign audio output and create volume control but Jack detection controls and mute switch are created according to the number of parsed pins which support Jack detect and mute switch
Do the headphone still work with pulseaudio since there is no headphone playback volume and headphone is share SPEAKER FRONT PLAYBAACK VOLUME control with front speaker ?
> - I have found a couple of kernel bug reports for other ASUS
models
> with > this chipset but they are both marked resolved. Should I open a
new
> ticket > ? > > https://bugzilla.kernel.org/show_bug.cgi?id=65091 > https://bugzilla.kernel.org/show_bug.cgi?id=66271 > > - I can hear static through the front speakers (with pulseaudio
test)
> if > I set pins 0x19 and 0x1a to Line Out (Center/LFE) and Internal > (Center/LFE) or vice versa with hdajackretask. >
For multi channel, the sequence number is ascending and the driver
expect
they have same type i.e, all speakers or all line out jacks
Pin Default 0x90170110: [Fixed] Speaker at Int N/A Conn = Analog, Color = Unknown DefAssociation = 0x1, Sequence = 0x0 Misc = NO_PRESENCE
The rear speaker need same default association but sequence number higher than that of the front speaker
The external subwoofer may use [jack] speaker with same default association and higher sequence number if it can be detected
The driver won't use all of them for multi channel if you retasked it as line out
I have tried several combinations with hdajackretask
I am not able to get audio out of the physical rear speakers or sonic master output. :
So what do I need to do to write a script that will test all the combinations and play audio through them? Or am I missing something that someone else has already written for this purpose?
Currently I am using this process:
1: hdajackretask - modify params 2: pulseaudio -k 3: hdajackretask : apply settings 4: pulseaudio -D 5: open PA audio config 6: select audio output option and press test speakers button 7: manually press every button
Use install boot option and reboot to test the driver with hda-jack-retask.fw patch
Should not use pulseaudio when testing
speaker-test -c2 -t wav -D hw:1,0
speaker-test -c4 -t wav -D hw:1,0
Test 6 channel only after you find both rear speaker and subwoofer
speaker-test -c6 -t wav -D hw:1,0
if the connected retasked pin is not the correct pin ,you can use hda_analyzer to change the pin ctls of the remaining unconnected pin to OUT, unmute and coonect the pin to second/third dac through audio mixers
On Thu, July 31, 2014 11:38 pm, Raymond Yau wrote:
http://git.alsa-project.org/?p=alsa.git;a=commitdiff;h=48ed9474fc6724dc1486d...
Have you try the fix ?
I did not see that update.
run.py works now without any modifications on this machine.
I have generated a graph.
http://boosthardware.com/hda_graph-1.png
You can use hda-verb GET_PIN_SENSE to test all the pin complex nodes
which
pincap support DETECT
I have tried a few attempts but it's pretty confusing.
These ones don't do anything:
# hda-verb /dev/snd/hwC1D0 GET_PIN_SENSE # hda-verb /dev/snd/hwC1D0 0x0 GET_PIN_SENSE
I don't know what to make of this output:
Bit 31 is PD
VALUE should return 0 when Jack is UNplugged and 0x80000000 when Jack is plugged for those pin which support DETECT
But your alc668 is on card 1 , the second hda controller
Sorry. Missed that one.
# hda-verb /dev/snd/hwC1D0 0x16 GET_PIN_SENSE PIN_CAP nid = 0x16, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC1D0 0x19 GET_PIN_SENSE PIN_CAP nid = 0x19, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC1D0 0x11a GET_PIN_SENSE PIN_CAP invalid nid 0x11a # hda-verb /dev/snd/hwC1D0 0x1a GET_PIN_SENSE PIN_CAP nid = 0x1a, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC1D0 0x1b GET_PIN_SENSE PIN_CAP nid = 0x1b, verb = 0xf09, param = 0xc value = 0x0
I see the following new controls
Speaker CFLE (mute only) Speaker Front (mute + vol) Speaker Side (mute only) Speaker Surround (mute + vol)
hda-jack-retask won't check whether your codec have enough audio output if you changed all the nodes to speaker
But the driver expect multiout support up to 8 channels when parsing the pin
As alc668 only support 6 channels, hda_generic.c just assign audio output and create volume control but Jack detection controls and mute switch are created according to the number of parsed pins which support Jack detect and mute switch
Do the headphone still work with pulseaudio since there is no headphone playback volume and headphone is share SPEAKER FRONT PLAYBAACK VOLUME control with front speaker ?
With speaker-test I can hear audio on the right channel
speaker-test -c2 -t wav -D hw:1,0
audio comes out of front left/right
speaker-test -c4 -t wav -D hw:1,0
front left/right has no audio rear left/right audio comes out of front left/right speakers
# speaker-test -c6 -t wav -D hw:1,0
speaker-test 1.0.28
Playback device is hw:1,0 Stream parameters are 48000Hz, S16_LE, 6 channels WAV file(s) Channels count (6) not available for playbacks: Invalid argument Setting of hwparams failed: Invalid argument
if the connected retasked pin is not the correct pin ,you can use hda_analyzer to change the pin ctls of the remaining unconnected pin to OUT, unmute and coonect the pin to second/third dac through audio mixers
This is a bit confusing to master. How should I approach it given the layout of the graph linked above?
-- Patrick Shirkey Boost Hardware Ltd
http://git.alsa-project.org/?p=alsa.git;a=commitdiff;h=48ed9474fc6724dc1486d...
Have you try the fix ?
I did not see that update.
run.py works now without any modifications on this machine.
I have generated a graph.
You can use hda-verb GET_PIN_SENSE to test all the pin complex nodes
which
pincap support DETECT
I have tried a few attempts but it's pretty confusing.
These ones don't do anything:
# hda-verb /dev/snd/hwC1D0 GET_PIN_SENSE # hda-verb /dev/snd/hwC1D0 0x0 GET_PIN_SENSE
I don't know what to make of this output:
Bit 31 is PD
VALUE should return 0 when Jack is UNplugged and 0x80000000 when Jack
is
plugged for those pin which support DETECT
But your alc668 is on card 1 , the second hda controller
Sorry. Missed that one.
# hda-verb /dev/snd/hwC1D0 0x16 GET_PIN_SENSE PIN_CAP nid = 0x16, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC1D0 0x19 GET_PIN_SENSE PIN_CAP nid = 0x19, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC1D0 0x11a GET_PIN_SENSE PIN_CAP invalid nid 0x11a # hda-verb /dev/snd/hwC1D0 0x1a GET_PIN_SENSE PIN_CAP nid = 0x1a, verb = 0xf09, param = 0xc value = 0x0 # hda-verb /dev/snd/hwC1D0 0x1b GET_PIN_SENSE PIN_CAP nid = 0x1b, verb = 0xf09, param = 0xc value = 0x0
Do you mean the plugging of subwoofer cannot be detected
hda-jack-sense-test -c 1 -a
I see the following new controls
Speaker CFLE (mute only) Speaker Front (mute + vol) Speaker Side (mute only) Speaker Surround (mute + vol)
hda-jack-retask won't check whether your codec have enough audio output
if
you changed all the nodes to speaker
But the driver expect multiout support up to 8 channels when parsing the pin
As alc668 only support 6 channels, hda_generic.c just assign audio
output
and create volume control but Jack detection controls and mute switch
are
created according to the number of parsed pins which support Jack detect and mute switch
Do the headphone still work with pulseaudio since there is no headphone playback volume and headphone is share SPEAKER FRONT PLAYBAACK VOLUME control with front speaker ?
With speaker-test I can hear audio on the right channel
speaker-test -c2 -t wav -D hw:1,0
audio comes out of front left/right
speaker-test -c4 -t wav -D hw:1,0
front left/right has no audio rear left/right audio comes out of front left/right speakers
# speaker-test -c6 -t wav -D hw:1,0
speaker-test 1.0.28
Playback device is hw:1,0 Stream parameters are 48000Hz, S16_LE, 6 channels WAV file(s) Channels count (6) not available for playbacks: Invalid argument Setting of hwparams failed: Invalid argument
The graph don't contain enough into for debugg
Post output of alsa-info.sh after retasked
Seem headphone is more important than multichannel speaker when evaluating the badness of config
You may need to configure alsa driver --with-debug=verbose to produce more information in system log about how it evaluate the badness
On Fri, August 1, 2014 5:19 pm, Raymond Yau wrote:
alsa-info:
retask and apply http://boosthardware.com/alsa-info1.txt
store and reboot http://boosthardware.com/alsa-info2.txt
Do you mean the plugging of subwoofer cannot be detected
hda-jack-sense-test -c 1 -a
prior to latest changes with hdajackretask:
# python alsa-jack-sense-test.py -c 1 -a Pin 0x12 (Internal Mic): present = No Pin 0x14 (Internal Speaker): present = No Pin 0x15 (Black HP Out): present = No Pin 0x16 (Not connected): present = No Pin 0x18 (Black Mic): present = No Pin 0x19 (Not connected): present = No Pin 0x1a (Not connected): present = No Pin 0x1b (Not connected): present = No Pin 0x1d (Not connected): present = No Pin 0x1e (Black SPDIF Out): present = No Pin 0x1f (Not connected): present = No
headset connected:
# python alsa-jack-sense-test.py -c 1 -a Pin 0x12 (Internal Mic): present = No Pin 0x14 (Internal Speaker): present = No Pin 0x15 (Black HP Out): present = Yes Pin 0x16 (Not connected): present = No Pin 0x18 (Black Mic): present = No Pin 0x19 (Not connected): present = No Pin 0x1a (Not connected): present = No Pin 0x1b (Not connected): present = No Pin 0x1d (Not connected): present = No Pin 0x1e (Black SPDIF Out): present = No Pin 0x1f (Not connected): present = No
after latest reboot (alsa-info2.txt):
# python alsa-jack-sense-test.py -c 1 -a Pin 0x12 (Internal Mic): present = No Pin 0x14 (Internal Speaker): present = No Pin 0x15 (Black HP Out): present = No Pin 0x16 (Not connected): present = No Pin 0x18 (Black Mic): present = No Pin 0x19 (Not connected): present = No Pin 0x1a (Not connected): present = No Pin 0x1b (Not connected): present = No Pin 0x1d (Not connected): present = No Pin 0x1e (Black SPDIF Out): present = No Pin 0x1f (Not connected): present = No
headset connected:
# python alsa-jack-sense-test.py -c 1 -a Pin 0x12 (Internal Mic): present = No Pin 0x14 (Internal Speaker): present = No Pin 0x15 (Black HP Out): present = Yes Pin 0x16 (Not connected): present = No Pin 0x18 (Black Mic): present = No Pin 0x19 (Not connected): present = No Pin 0x1a (Not connected): present = No Pin 0x1b (Not connected): present = No Pin 0x1d (Not connected): present = No Pin 0x1e (Black SPDIF Out): present = No Pin 0x1f (Not connected): present = No
The graph don't contain enough into for debugg
Post output of alsa-info.sh after retasked
Seem headphone is more important than multichannel speaker when evaluating the badness of config
You may need to configure alsa driver --with-debug=verbose to produce more information in system log about how it evaluate the badness
Easier said than done. I have to build a custom kernel in order to get custom alsa-drivers to build on this machine so at the moment I am stuck with whatever I got in 3.14.1. From the list above can you make a recommendation for the best options to test?
According to hdajackretask the pins I can retask for output are the following:
Pin 0x14 (Internal Speaker): present = No Pin 0x15 (Black HP Out): present = No Pin 0x16 (Not connected): present = No Pin 0x18 (Black Mic): present = No Pin 0x19 (Not connected): present = No Pin 0x1a (Not connected): present = No
- The other pins present just a few options for input ex, mic, line in, spdif.
-- Patrick Shirkey Boost Hardware Ltd
alsa-info:
retask and apply http://boosthardware.com/alsa-info1.txt
store and reboot http://boosthardware.com/alsa-info2.txt
Any reason to use asus-mode4 and hda-jack-retask at the same time ?
Try model=auto when you use patch=,hda-jack-retask.fw
Your alsa-info missing many important info , need all info from alsactl, amixer, sysfs about the driver init pins and user init pins, allay/arecord -l
No information about which Jack have been retasked
On Fri, August 1, 2014 8:04 pm, Raymond Yau wrote:
alsa-info:
retask and apply http://boosthardware.com/alsa-info1.txt
store and reboot http://boosthardware.com/alsa-info2.txt
Any reason to use asus-mode4 and hda-jack-retask at the same time ?
I had it in place because at one point it seemed to allow PA to have addition profiles other than stereo. However the line below seems to be a better combination.
Try model=auto when you use patch=,hda-jack-retask.fw
That nugget of information seems to have enabled the bass speaker in alsa after the last reboot.
/etc/modprobe.d/alsa-base.conf options snd-hda-intel model=auto patch=,hda-jack-retask.fw
Your alsa-info missing many important info , need all info from alsactl, amixer, sysfs about the driver init pins and user init pins, allay/arecord -l
http://boosthardware.com/alsa-info4.txt
No information about which Jack have been retasked
For the info file above I have the following retask assignments:
0x14 Line out (front) 0x15 Line out (center/LFE) 0x16 Line Out (Back) 0x18 Internal Speaker 0x19 Internal Speaker(Back) 0x1a Internal mic
- With the following command I can hear "rear center" through the sonic master speaker when channel 5 is testing.
speaker-test -D hw:1 -c 6 -t wav
- I do not hear any sound when rear left/right is testing.
- I do not hear any audio through the LFE with PA test on any of the audio profiles.
- I will play around with the retask assignments now that something seems to be working. Looks like I'm on the right track now.
Thanks for all your help so far.
-- Patrick Shirkey Boost Hardware Ltd
Hi Varka,
Regarding a point you suggested.
On Fri, Jul 25, 2014 at 09:54:43AM +0530, Varka Bhadram wrote:
On 07/25/2014 09:33 AM, Nicolin Chen wrote: (...)
+static const struct platform_device_id fsl_asrc_devtype[] = {
- {
.name = "imx35-asrc",
.driver_data = IMX35_ASRC,
- }, {
.name = "imx53-asrc",
.driver_data = IMX53_ASRC,
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(platform, fsl_asrc_devtype);
+static const struct of_device_id fsl_asrc_ids[] = {
- {
.compatible = "fsl,imx35-asrc",
.data = &fsl_asrc_devtype[IMX35_ASRC],
- }, {
.compatible = "fsl,imx53-asrc",
.data = &fsl_asrc_devtype[IMX53_ASRC],
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(of, fsl_asrc_ids);
move these ids after probe/remove... every driver follows same thing...
Hmm.. fsl_asrc_ids is called in probe(), so it's probably not a good choice to put them after probe/remove. And actually not every driver does so. For example drivers/i2c/busses/i2c-s3c2410.c
I think it should be okay to put here if it contains data.
Thank you, Nicolin
Hi Nicolin,
On 07/25/2014 11:24 AM, Nicolin Chen wrote:
Hi Varka,
Regarding a point you suggested.
On Fri, Jul 25, 2014 at 09:54:43AM +0530, Varka Bhadram wrote:
On 07/25/2014 09:33 AM, Nicolin Chen wrote: (...)
+static const struct platform_device_id fsl_asrc_devtype[] = {
- {
.name = "imx35-asrc",
.driver_data = IMX35_ASRC,
- }, {
.name = "imx53-asrc",
.driver_data = IMX53_ASRC,
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(platform, fsl_asrc_devtype);
+static const struct of_device_id fsl_asrc_ids[] = {
- {
.compatible = "fsl,imx35-asrc",
.data = &fsl_asrc_devtype[IMX35_ASRC],
- }, {
.compatible = "fsl,imx53-asrc",
.data = &fsl_asrc_devtype[IMX53_ASRC],
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(of, fsl_asrc_ids);
move these ids after probe/remove... every driver follows same thing...
Hmm.. fsl_asrc_ids is called in probe(), so it's probably not a good choice to put them after probe/remove. And actually not every driver does so. For example drivers/i2c/busses/i2c-s3c2410.c
I think it should be okay to put here if it contains data.
You are using these ids in the probe .Tt should be above the probe() so we can see of_match_device() directly... and also one more thing that the interrupt handler also would be immediately above the probe()
ex: static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) { ... }
device ids..
your_probe() { ... }
your_remove() { ... }
Now every driver that is coming following this style...
If your not using device ids in probe then it would be like
static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) { ... }
your_probe() { ... }
your_remove() { ... }
device ids..
Thanks...
On Fri, Jul 25, 2014 at 11:47:42AM +0530, Varka Bhadram wrote:
Hi Nicolin,
On 07/25/2014 11:24 AM, Nicolin Chen wrote:
Hi Varka,
Regarding a point you suggested.
On Fri, Jul 25, 2014 at 09:54:43AM +0530, Varka Bhadram wrote:
On 07/25/2014 09:33 AM, Nicolin Chen wrote: (...)
+static const struct platform_device_id fsl_asrc_devtype[] = {
- {
.name = "imx35-asrc",
.driver_data = IMX35_ASRC,
- }, {
.name = "imx53-asrc",
.driver_data = IMX53_ASRC,
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(platform, fsl_asrc_devtype);
+static const struct of_device_id fsl_asrc_ids[] = {
- {
.compatible = "fsl,imx35-asrc",
.data = &fsl_asrc_devtype[IMX35_ASRC],
- }, {
.compatible = "fsl,imx53-asrc",
.data = &fsl_asrc_devtype[IMX53_ASRC],
- }, {
/* sentinel */
- }
+}; +MODULE_DEVICE_TABLE(of, fsl_asrc_ids);
move these ids after probe/remove... every driver follows same thing...
Hmm.. fsl_asrc_ids is called in probe(), so it's probably not a good choice to put them after probe/remove. And actually not every driver does so. For example drivers/i2c/busses/i2c-s3c2410.c
I think it should be okay to put here if it contains data.
You are using these ids in the probe .Tt should be above the probe() so we can see of_match_device() directly... and also one more thing that the interrupt handler also would be immediately above the probe()
ex: static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) { ... }
device ids..
your_probe() { ... }
your_remove() { ... }
Now every driver that is coming following this style...
I see....
Will follow this style.
Thank you! Nicolin
---
If your not using device ids in probe then it would be like
static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) { ... }
your_probe() { ... }
your_remove() { ... }
device ids..
Thanks...
-- Regards, Varka Bhadram.
- big-endian : If this property is absent, the native endian mode will
be in use as default, or the big endian mode will be in use
for all the device registers.
Native endian is meaningless. If a CPU supports both BE and LE, there is no native endianness. The endianness of the kernel is dynamic while the endianness of registers in HW is fixed.
Just choose an endianness to assume by default (presumably little). That way this describes the HW and always works with a kernel of arbitrary endianness.
Thanks, Mark.
On Tue, Jul 29, 2014 at 10:46:13AM +0100, Mark Rutland wrote:
- big-endian : If this property is absent, the native endian mode will
be in use as default, or the big endian mode will be in use
for all the device registers.
Native endian is meaningless. If a CPU supports both BE and LE, there is no native endianness. The endianness of the kernel is dynamic while the endianness of registers in HW is fixed.
Just choose an endianness to assume by default (presumably little). That way this describes the HW and always works with a kernel of arbitrary endianness.
Thank you for the comments.
I just revised it by using 'little endian as default' and sent the patch v6.
Please take a look at the new version.
Thanks again, Nicolin
participants (6)
-
Mark Rutland
-
Nicolin Chen
-
Nicolin Chen
-
Patrick Shirkey
-
Raymond Yau
-
Varka Bhadram