Merge tag 'asoc-fix-v5.3-rc3' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorTakashi Iwai <tiwai@suse.de>
Tue, 6 Aug 2019 10:28:08 +0000 (12:28 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 6 Aug 2019 10:28:08 +0000 (12:28 +0200)
ASoC: Fixes for v5.3

A relatively large batch of mostly unremarkable fixes here, a couple of
small core fixes for fairly obscure issues, more comment/email updates
with no code impact than usual and a bunch of small driver fixes.

The support for new sample rates in the max98373 driver is a fix for the
fact that the driver declared support for those rates but would in fact
return an error if these rates were selected.

40 files changed:
MAINTAINERS
include/sound/simple_card_utils.h
include/uapi/sound/sof/fw.h
include/uapi/sound/sof/header.h
sound/soc/amd/raven/acp3x-pcm-dma.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/max98373.c [changed mode: 0644->0755]
sound/soc/codecs/max98373.h [changed mode: 0644->0755]
sound/soc/codecs/pcm3060-i2c.c
sound/soc/codecs/pcm3060-spi.c
sound/soc/codecs/pcm3060.c
sound/soc/codecs/pcm3060.h
sound/soc/codecs/rt1011.c
sound/soc/codecs/rt1308.c [changed mode: 0755->0644]
sound/soc/codecs/rt1308.h [changed mode: 0755->0644]
sound/soc/generic/audio-graph-card.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/common/soc-acpi-intel-bxt-match.c
sound/soc/intel/common/soc-acpi-intel-byt-match.c
sound/soc/intel/common/soc-acpi-intel-cht-match.c
sound/soc/intel/common/soc-acpi-intel-cnl-match.c
sound/soc/intel/common/soc-acpi-intel-glk-match.c
sound/soc/intel/common/soc-acpi-intel-hda-match.c
sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
sound/soc/intel/common/soc-acpi-intel-icl-match.c
sound/soc/intel/common/soc-acpi-intel-kbl-match.c
sound/soc/intel/common/soc-acpi-intel-skl-match.c
sound/soc/qcom/apq8016_sbc.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_max98090.c
sound/soc/samsung/odroid.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/hda-ipc.c
sound/soc/sunxi/sun4i-i2s.c
sound/soc/ti/davinci-mcasp.c

index 0b9192c..f227f7e 100644 (file)
@@ -7871,6 +7871,7 @@ S:        Maintained
 F:     drivers/video/fbdev/i810/
 
 INTEL ASoC DRIVERS
+M:     Cezary Rojewski <cezary.rojewski@intel.com>
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <liam.r.girdwood@linux.intel.com>
 M:     Jie Yang <yang.jie@linux.intel.com>
@@ -15805,7 +15806,7 @@ S:      Maintained
 F:     drivers/net/ethernet/ti/netcp*
 
 TI PCM3060 ASoC CODEC DRIVER
-M:     Kirill Marinushkin <kmarinushkin@birdec.tech>
+M:     Kirill Marinushkin <kmarinushkin@birdec.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/devicetree/bindings/sound/pcm3060.txt
index 954563e..985a5f5 100644 (file)
@@ -141,6 +141,10 @@ inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
 {
        struct device *dev = simple_priv_to_dev(priv);
 
+       /* dai might be NULL */
+       if (!dai)
+               return;
+
        if (dai->name)
                dev_dbg(dev, "%s dai name = %s\n",
                        name, dai->name);
index 1afca97..e9f6974 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __INCLUDE_UAPI_SOF_FW_H__
 #define __INCLUDE_UAPI_SOF_FW_H__
 
+#include <linux/types.h>
+
 #define SND_SOF_FW_SIG_SIZE    4
 #define SND_SOF_FW_ABI         1
 #define SND_SOF_FW_SIG         "Reef"
@@ -46,8 +48,8 @@ enum snd_sof_fw_blk_type {
 
 struct snd_sof_blk_hdr {
        enum snd_sof_fw_blk_type type;
-       uint32_t size;          /* bytes minus this header */
-       uint32_t offset;        /* offset from base */
+       __u32 size;             /* bytes minus this header */
+       __u32 offset;           /* offset from base */
 } __packed;
 
 /*
@@ -61,8 +63,8 @@ enum snd_sof_fw_mod_type {
 
 struct snd_sof_mod_hdr {
        enum snd_sof_fw_mod_type type;
-       uint32_t size;          /* bytes minus this header */
-       uint32_t num_blocks;    /* number of blocks */
+       __u32 size;             /* bytes minus this header */
+       __u32 num_blocks;       /* number of blocks */
 } __packed;
 
 /*
@@ -70,9 +72,9 @@ struct snd_sof_mod_hdr {
  */
 struct snd_sof_fw_header {
        unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */
-       uint32_t file_size;     /* size of file minus this header */
-       uint32_t num_modules;   /* number of modules */
-       uint32_t abi;           /* version of header format */
+       __u32 file_size;        /* size of file minus this header */
+       __u32 num_modules;      /* number of modules */
+       __u32 abi;              /* version of header format */
 } __packed;
 
 #endif
index 7868990..5f4518e 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__
 #define __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__
 
+#include <linux/types.h>
+
 /*
  * Header for all non IPC ABI data.
  *
  * Used by any bespoke component data structures or binary blobs.
  */
 struct sof_abi_hdr {
-       uint32_t magic;         /**< 'S', 'O', 'F', '\0' */
-       uint32_t type;          /**< component specific type */
-       uint32_t size;          /**< size in bytes of data excl. this struct */
-       uint32_t abi;           /**< SOF ABI version */
-       uint32_t reserved[4];   /**< reserved for future use */
-       uint32_t data[0];       /**< Component data - opaque to core */
+       __u32 magic;            /**< 'S', 'O', 'F', '\0' */
+       __u32 type;             /**< component specific type */
+       __u32 size;             /**< size in bytes of data excl. this struct */
+       __u32 abi;              /**< SOF ABI version */
+       __u32 reserved[4];      /**< reserved for future use */
+       __u32 data[0];          /**< Component data - opaque to core */
 }  __packed;
 
 #endif
index a4ade6b..bc4dfaf 100644 (file)
@@ -31,8 +31,8 @@ struct i2s_stream_instance {
        u16 num_pages;
        u16 channels;
        u32 xfer_resolution;
-       struct page *pg;
        u64 bytescount;
+       dma_addr_t dma_addr;
        void __iomem *acp3x_base;
 };
 
@@ -211,9 +211,8 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
 static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
 {
        u16 page_idx;
-       u64 addr;
        u32 low, high, val, acp_fifo_addr;
-       struct page *pg = rtd->pg;
+       dma_addr_t addr = rtd->dma_addr;
 
        /* 8 scratch registers used to map one 64 bit address */
        if (direction == SNDRV_PCM_STREAM_PLAYBACK)
@@ -229,7 +228,6 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
 
        for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
                /* Load the low address of page int ACP SRAM through SRBM */
-               addr = page_to_phys(pg);
                low = lower_32_bits(addr);
                high = upper_32_bits(addr);
 
@@ -239,7 +237,7 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
                                + 4);
                /* Move to next physically contiguos page */
                val += 8;
-               pg++;
+               addr += PAGE_SIZE;
        }
 
        if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -341,7 +339,6 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
 {
        int status;
        u64 size;
-       struct page *pg;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct i2s_stream_instance *rtd = runtime->private_data;
 
@@ -354,9 +351,8 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
                return status;
 
        memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
-       pg = virt_to_page(substream->dma_buffer.area);
-       if (pg) {
-               rtd->pg = pg;
+       if (substream->dma_buffer.area) {
+               rtd->dma_addr = substream->dma_buffer.addr;
                rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
                config_acp3x_dma(rtd, substream->stream);
                status = 0;
@@ -385,9 +381,11 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
 
 static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
+                                                                   DRV_NAME);
+       struct device *parent = component->dev->parent;
        snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
-                                             rtd->pcm->card->dev,
-                                             MIN_BUFFER, MAX_BUFFER);
+                                             parent, MIN_BUFFER, MAX_BUFFER);
        return 0;
 }
 
index 6203f54..5b049fc 100644 (file)
@@ -47,6 +47,7 @@ struct cs42xx8_priv {
        unsigned long sysclk;
        u32 tx_channels;
        struct gpio_desc *gpiod_reset;
+       u32 rate[2];
 };
 
 /* -127.5dB to 0dB with step of 0.5dB */
@@ -176,21 +177,27 @@ static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
 };
 
 struct cs42xx8_ratios {
-       unsigned int ratio;
-       unsigned char speed;
-       unsigned char mclk;
+       unsigned int mfreq;
+       unsigned int min_mclk;
+       unsigned int max_mclk;
+       unsigned int ratio[3];
 };
 
+/*
+ * According to reference mannual, define the cs42xx8_ratio struct
+ * MFreq2 | MFreq1 | MFreq0 |     Description     | SSM | DSM | QSM |
+ * 0      | 0      | 0      |1.029MHz to 12.8MHz  | 256 | 128 |  64 |
+ * 0      | 0      | 1      |1.536MHz to 19.2MHz  | 384 | 192 |  96 |
+ * 0      | 1      | 0      |2.048MHz to 25.6MHz  | 512 | 256 | 128 |
+ * 0      | 1      | 1      |3.072MHz to 38.4MHz  | 768 | 384 | 192 |
+ * 1      | x      | x      |4.096MHz to 51.2MHz  |1024 | 512 | 256 |
+ */
 static const struct cs42xx8_ratios cs42xx8_ratios[] = {
-       { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
-       { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
-       { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
-       { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
-       { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
-       { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
-       { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
-       { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
-       { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
+       { 0, 1029000, 12800000, {256, 128, 64} },
+       { 2, 1536000, 19200000, {384, 192, 96} },
+       { 4, 2048000, 25600000, {512, 256, 128} },
+       { 6, 3072000, 38400000, {768, 384, 192} },
+       { 8, 4096000, 51200000, {1024, 512, 256} },
 };
 
 static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -257,14 +264,68 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_component *component = dai->component;
        struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-       u32 ratio = cs42xx8->sysclk / params_rate(params);
-       u32 i, fm, val, mask;
+       u32 ratio[2];
+       u32 rate[2];
+       u32 fm[2];
+       u32 i, val, mask;
+       bool condition1, condition2;
 
        if (tx)
                cs42xx8->tx_channels = params_channels(params);
 
+       rate[tx]  = params_rate(params);
+       rate[!tx] = cs42xx8->rate[!tx];
+
+       ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;
+       ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;
+
+       /* Get functional mode for tx and rx according to rate */
+       for (i = 0; i < 2; i++) {
+               if (cs42xx8->slave_mode) {
+                       fm[i] = CS42XX8_FM_AUTO;
+               } else {
+                       if (rate[i] < 50000) {
+                               fm[i] = CS42XX8_FM_SINGLE;
+                       } else if (rate[i] > 50000 && rate[i] < 100000) {
+                               fm[i] = CS42XX8_FM_DOUBLE;
+                       } else if (rate[i] > 100000 && rate[i] < 200000) {
+                               fm[i] = CS42XX8_FM_QUAD;
+                       } else {
+                               dev_err(component->dev,
+                                       "unsupported sample rate\n");
+                               return -EINVAL;
+                       }
+               }
+       }
+
        for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
-               if (cs42xx8_ratios[i].ratio == ratio)
+               /* Is the ratio[tx] valid ? */
+               condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?
+                       (cs42xx8_ratios[i].ratio[0] == ratio[tx] ||
+                       cs42xx8_ratios[i].ratio[1] == ratio[tx] ||
+                       cs42xx8_ratios[i].ratio[2] == ratio[tx]) :
+                       (cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&
+                       cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&
+                       cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;
+
+               if (!ratio[tx])
+                       condition1 = true;
+
+               /* Is the ratio[!tx] valid ? */
+               condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?
+                       (cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||
+                       cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||
+                       cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :
+                       (cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));
+
+               if (!ratio[!tx])
+                       condition2 = true;
+
+               /*
+                * Both ratio[tx] and ratio[!tx] is valid, then we get
+                * a proper MFreq.
+                */
+               if (condition1 && condition2)
                        break;
        }
 
@@ -273,15 +334,31 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       mask = CS42XX8_FUNCMOD_MFREQ_MASK;
-       val = cs42xx8_ratios[i].mclk;
+       cs42xx8->rate[tx] = params_rate(params);
 
-       fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
+       mask = CS42XX8_FUNCMOD_MFREQ_MASK;
+       val = cs42xx8_ratios[i].mfreq;
 
        regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
                           CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
-                          CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
+                          CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);
+
+       return 0;
+}
+
+static int cs42xx8_hw_free(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
+       /* Clear stored rate */
+       cs42xx8->rate[tx] = 0;
+
+       regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
+                          CS42XX8_FUNCMOD_xC_FM_MASK(tx),
+                          CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));
        return 0;
 }
 
@@ -302,6 +379,7 @@ static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
        .set_fmt        = cs42xx8_set_dai_fmt,
        .set_sysclk     = cs42xx8_set_dai_sysclk,
        .hw_params      = cs42xx8_hw_params,
+       .hw_free        = cs42xx8_hw_free,
        .digital_mute   = cs42xx8_digital_mute,
 };
 
index 6f0e28f..16313b9 100644 (file)
 #include <sound/soc-dapm.h>
 
 struct max98357a_priv {
-       struct delayed_work enable_sdmode_work;
        struct gpio_desc *sdmode;
        unsigned int sdmode_delay;
 };
 
-static void max98357a_enable_sdmode_work(struct work_struct *work)
-{
-       struct max98357a_priv *max98357a =
-       container_of(work, struct max98357a_priv,
-                       enable_sdmode_work.work);
-
-       gpiod_set_value(max98357a->sdmode, 1);
-}
-
 static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
                int cmd, struct snd_soc_dai *dai)
 {
@@ -46,14 +36,12 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               queue_delayed_work(system_power_efficient_wq,
-                               &max98357a->enable_sdmode_work,
-                               msecs_to_jiffies(max98357a->sdmode_delay));
+               mdelay(max98357a->sdmode_delay);
+               gpiod_set_value(max98357a->sdmode, 1);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               cancel_delayed_work_sync(&max98357a->enable_sdmode_work);
                gpiod_set_value(max98357a->sdmode, 0);
                break;
        }
@@ -112,30 +100,25 @@ static int max98357a_platform_probe(struct platform_device *pdev)
        int ret;
 
        max98357a = devm_kzalloc(&pdev->dev, sizeof(*max98357a), GFP_KERNEL);
-
        if (!max98357a)
                return -ENOMEM;
 
        max98357a->sdmode = devm_gpiod_get_optional(&pdev->dev,
                                "sdmode", GPIOD_OUT_LOW);
-
        if (IS_ERR(max98357a->sdmode))
                return PTR_ERR(max98357a->sdmode);
 
        ret = device_property_read_u32(&pdev->dev, "sdmode-delay",
                                        &max98357a->sdmode_delay);
-
        if (ret) {
                max98357a->sdmode_delay = 0;
                dev_dbg(&pdev->dev,
-                       "no optional property 'sdmode-delay' found, default: no delay\n");
+                       "no optional property 'sdmode-delay' found, "
+                       "default: no delay\n");
        }
 
        dev_set_drvdata(&pdev->dev, max98357a);
 
-       INIT_DELAYED_WORK(&max98357a->enable_sdmode_work,
-                               max98357a_enable_sdmode_work);
-
        return devm_snd_soc_register_component(&pdev->dev,
                        &max98357a_component_driver,
                        &max98357a_dai_driver, 1);
old mode 100644 (file)
new mode 100755 (executable)
index 528695c..8c601a3
@@ -267,6 +267,12 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
        case 48000:
                sampling_rate = MAX98373_PCM_SR_SET1_SR_48000;
                break;
+       case 88200:
+               sampling_rate = MAX98373_PCM_SR_SET1_SR_88200;
+               break;
+       case 96000:
+               sampling_rate = MAX98373_PCM_SR_SET1_SR_96000;
+               break;
        default:
                dev_err(component->dev, "rate %d not supported\n",
                        params_rate(params));
old mode 100644 (file)
new mode 100755 (executable)
index f6a37aa..a59e513
 #define MAX98373_PCM_SR_SET1_SR_32000 (0x6 << 0)
 #define MAX98373_PCM_SR_SET1_SR_44100 (0x7 << 0)
 #define MAX98373_PCM_SR_SET1_SR_48000 (0x8 << 0)
+#define MAX98373_PCM_SR_SET1_SR_88200 (0x9 << 0)
+#define MAX98373_PCM_SR_SET1_SR_96000 (0xA << 0)
 
 /* MAX98373_R2028_PCM_SR_SETUP_2 */
 #define MAX98373_PCM_SR_SET2_SR_MASK (0xF << 4)
index cdc8314..abcdeb9 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PCM3060 I2C driver
 //
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
 
 #include <linux/i2c.h>
 #include <linux/module.h>
@@ -56,5 +56,5 @@ static struct i2c_driver pcm3060_i2c_driver = {
 module_i2c_driver(pcm3060_i2c_driver);
 
 MODULE_DESCRIPTION("PCM3060 I2C driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
+MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
 MODULE_LICENSE("GPL v2");
index f6f19fa..3b79734 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PCM3060 SPI driver
 //
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
 
 #include <linux/module.h>
 #include <linux/spi/spi.h>
@@ -55,5 +55,5 @@ static struct spi_driver pcm3060_spi_driver = {
 module_spi_driver(pcm3060_spi_driver);
 
 MODULE_DESCRIPTION("PCM3060 SPI driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
+MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
 MODULE_LICENSE("GPL v2");
index 32b26f1..b235806 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PCM3060 codec driver
 //
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
 
 #include <linux/module.h>
 #include <sound/pcm_params.h>
@@ -342,5 +342,5 @@ int pcm3060_probe(struct device *dev)
 EXPORT_SYMBOL(pcm3060_probe);
 
 MODULE_DESCRIPTION("PCM3060 codec driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
+MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
 MODULE_LICENSE("GPL v2");
index 75931c9..18d51e5 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * PCM3060 codec driver
  *
- * Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+ * Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
  */
 
 #ifndef _SND_SOC_PCM3060_H
index 5605b66..0a6ff13 100644 (file)
@@ -39,7 +39,7 @@ static const struct reg_sequence init_list[] = {
        { RT1011_POWER_9, 0xa840 },
 
        { RT1011_ADC_SET_5, 0x0a20 },
-       { RT1011_DAC_SET_2, 0xa232 },
+       { RT1011_DAC_SET_2, 0xa032 },
        { RT1011_ADC_SET_1, 0x2925 },
 
        { RT1011_SPK_PRO_DC_DET_1, 0xb00c },
@@ -1917,7 +1917,7 @@ static int rt1011_set_bias_level(struct snd_soc_component *component,
                snd_soc_component_write(component,
                        RT1011_SYSTEM_RESET_2, 0x0000);
                snd_soc_component_write(component,
-                       RT1011_SYSTEM_RESET_3, 0x0000);
+                       RT1011_SYSTEM_RESET_3, 0x0001);
                snd_soc_component_write(component,
                        RT1011_SYSTEM_RESET_1, 0x003f);
                snd_soc_component_write(component,
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 30a4e83..288df24 100644 (file)
@@ -63,6 +63,7 @@ static int graph_get_dai_id(struct device_node *ep)
        struct device_node *endpoint;
        struct of_endpoint info;
        int i, id;
+       const u32 *reg;
        int ret;
 
        /* use driver specified DAI ID if exist */
@@ -83,8 +84,9 @@ static int graph_get_dai_id(struct device_node *ep)
                        return info.id;
 
                node = of_get_parent(ep);
+               reg = of_get_property(node, "reg", NULL);
                of_node_put(node);
-               if (of_get_property(node, "reg", NULL))
+               if (reg)
                        return info.port;
        }
        node = of_graph_get_port_parent(ep);
@@ -208,10 +210,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
        dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
 
-       of_node_put(ports);
-       of_node_put(port);
-       of_node_put(node);
-
        if (li->cpu) {
                int is_single_links = 0;
 
@@ -229,17 +227,17 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
                ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links);
                if (ret)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_set_dailink_name(dev, dai_link,
                                                   "fe.%s",
                                                   cpus->dai_name);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                /* card->num_links includes Codec */
                asoc_simple_canonicalize_cpu(dai_link, is_single_links);
@@ -263,17 +261,17 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
                ret = asoc_simple_parse_codec(ep, dai_link);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_set_dailink_name(dev, dai_link,
                                                   "be.%s",
                                                   codecs->dai_name);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                /* check "prefix" from top node */
                snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
@@ -293,19 +291,23 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
        ret = asoc_simple_parse_tdm(ep, dai);
        if (ret)
-               return ret;
+               goto out_put_node;
 
        ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
                                       NULL, &dai_link->dai_fmt);
        if (ret < 0)
-               return ret;
+               goto out_put_node;
 
        dai_link->dpcm_playback         = 1;
        dai_link->dpcm_capture          = 1;
        dai_link->ops                   = &graph_ops;
        dai_link->init                  = asoc_simple_dai_init;
 
-       return 0;
+out_put_node:
+       of_node_put(ports);
+       of_node_put(port);
+       of_node_put(node);
+       return ret;
 }
 
 static int graph_dai_link_of(struct asoc_simple_priv *priv,
index ac8678f..556b1a7 100644 (file)
@@ -349,6 +349,13 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link)
        /* Assumes platform == cpu */
        if (!dai_link->platforms->of_node)
                dai_link->platforms->of_node = dai_link->cpus->of_node;
+
+       /*
+        * DPCM BE can be no platform.
+        * Alloced memory will be waste, but not leak.
+        */
+       if (!dai_link->platforms->of_node)
+               dai_link->num_platforms = 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
 
index e5cde0d..ef84915 100644 (file)
@@ -124,8 +124,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
        li->link++;
 
-       of_node_put(node);
-
        /* For single DAI link & old style of DT node */
        if (is_top)
                prefix = PREFIX;
@@ -147,17 +145,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
                ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links);
                if (ret)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_set_dailink_name(dev, dai_link,
                                                   "fe.%s",
                                                   cpus->dai_name);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                asoc_simple_canonicalize_cpu(dai_link, is_single_links);
        } else {
@@ -180,17 +178,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
                ret = asoc_simple_parse_codec(np, dai_link);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                ret = asoc_simple_set_dailink_name(dev, dai_link,
                                                   "be.%s",
                                                   codecs->dai_name);
                if (ret < 0)
-                       return ret;
+                       goto out_put_node;
 
                /* check "prefix" from top node */
                snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
@@ -208,19 +206,21 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 
        ret = asoc_simple_parse_tdm(np, dai);
        if (ret)
-               return ret;
+               goto out_put_node;
 
        ret = asoc_simple_parse_daifmt(dev, node, codec,
                                       prefix, &dai_link->dai_fmt);
        if (ret < 0)
-               return ret;
+               goto out_put_node;
 
        dai_link->dpcm_playback         = 1;
        dai_link->dpcm_capture          = 1;
        dai_link->ops                   = &simple_ops;
        dai_link->init                  = asoc_simple_dai_init;
 
-       return 0;
+out_put_node:
+       of_node_put(node);
+       return ret;
 }
 
 static int simple_dai_link_of(struct asoc_simple_priv *priv,
@@ -364,8 +364,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
                        goto error;
                }
 
-               of_node_put(codec);
-
                /* get convert-xxx property */
                memset(&adata, 0, sizeof(adata));
                for_each_child_of_node(node, np)
@@ -387,11 +385,13 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
                                ret = func_noml(priv, np, codec, li, is_top);
 
                        if (ret < 0) {
+                               of_node_put(codec);
                                of_node_put(np);
                                goto error;
                        }
                }
 
+               of_node_put(codec);
                node = of_get_next_child(top, node);
        } while (!is_top && node);
 
index fac09be..4661233 100644 (file)
@@ -437,6 +437,14 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = {
 
 /* Please keep this list alphabetically sorted */
 static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
+       {       /* Irbis NB41 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "NB41"),
+               },
+               .driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN2_MAP
+                                       | BYT_CHT_ES8316_JD_INVERTED),
+       },
        {       /* Teclast X98 Plus II */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
index 229e395..4a5adae 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * soc-apci-intel-bxt-match.c - tables and support for BXT ACPI enumeration.
+ * soc-acpi-intel-bxt-match.c - tables and support for BXT ACPI enumeration.
  *
  * Copyright (c) 2018, Intel Corporation.
  *
index b94b482..1cc801b 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-byt-match.c - tables and support for BYT ACPI enumeration.
+ * soc-acpi-intel-byt-match.c - tables and support for BYT ACPI enumeration.
  *
  * Copyright (c) 2017, Intel Corporation.
  */
index b7f11f6..d0fb43c 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-cht-match.c - tables and support for CHT ACPI enumeration.
+ * soc-acpi-intel-cht-match.c - tables and support for CHT ACPI enumeration.
  *
  * Copyright (c) 2017, Intel Corporation.
  */
index c36c0aa..771b0ef 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * soc-apci-intel-cnl-match.c - tables and support for CNL ACPI enumeration.
+ * soc-acpi-intel-cnl-match.c - tables and support for CNL ACPI enumeration.
  *
  * Copyright (c) 2018, Intel Corporation.
  *
index 616eb09..60dea35 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * soc-apci-intel-glk-match.c - tables and support for GLK ACPI enumeration.
+ * soc-acpi-intel-glk-match.c - tables and support for GLK ACPI enumeration.
  *
  * Copyright (c) 2018, Intel Corporation.
  *
index 68ae43f..cc972d2 100644 (file)
@@ -2,7 +2,7 @@
 // Copyright (c) 2018, Intel Corporation.
 
 /*
- * soc-apci-intel-hda-match.c - tables and support for HDA+ACPI enumeration.
+ * soc-acpi-intel-hda-match.c - tables and support for HDA+ACPI enumeration.
  *
  */
 
index d27853e..34eb0ba 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * soc-apci-intel-hsw-bdw-match.c - tables and support for ACPI enumeration.
+ * soc-acpi-intel-hsw-bdw-match.c - tables and support for ACPI enumeration.
  *
  * Copyright (c) 2017, Intel Corporation.
  */
index 0b430b9..3897766 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration.
+ * soc-acpi-intel-icl-match.c - tables and support for ICL ACPI enumeration.
  *
  * Copyright (c) 2018, Intel Corporation.
  *
index 4b33105..e200baa 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * soc-apci-intel-kbl-match.c - tables and support for KBL ACPI enumeration.
+ * soc-acpi-intel-kbl-match.c - tables and support for KBL ACPI enumeration.
  *
  * Copyright (c) 2018, Intel Corporation.
  *
index 0c9c0ed..42fa40a 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * soc-apci-intel-skl-match.c - tables and support for SKL ACPI enumeration.
+ * soc-acpi-intel-skl-match.c - tables and support for SKL ACPI enumeration.
  *
  * Copyright (c) 2018, Intel Corporation.
  *
index f60a719..ac75838 100644 (file)
@@ -150,17 +150,17 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
 
        link = data->dai_link;
 
-       dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
-       if (!dlc)
-               return ERR_PTR(-ENOMEM);
+       for_each_child_of_node(node, np) {
+               dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
+               if (!dlc)
+                       return ERR_PTR(-ENOMEM);
 
-       link->cpus      = &dlc[0];
-       link->platforms = &dlc[1];
+               link->cpus      = &dlc[0];
+               link->platforms = &dlc[1];
 
-       link->num_cpus          = 1;
-       link->num_platforms     = 1;
+               link->num_cpus          = 1;
+               link->num_platforms     = 1;
 
-       for_each_child_of_node(node, np) {
                cpu = of_get_child_by_name(np, "cpu");
                codec = of_get_child_by_name(np, "codec");
 
index 0a34d0e..88ebaf6 100644 (file)
@@ -326,7 +326,6 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
                val |= I2S_CHN_4;
                break;
        case 2:
-       case 1:
                val |= I2S_CHN_2;
                break;
        default:
@@ -459,7 +458,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
        },
        .capture = {
                .stream_name = "Capture",
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_192000,
                .formats = (SNDRV_PCM_FMTBIT_S8 |
@@ -659,7 +658,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
        }
 
        if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
-               if (val >= 1 && val <= 8)
+               if (val >= 2 && val <= 8)
                        soc_dai->capture.channels_max = val;
        }
 
index c5fc246..782e534 100644 (file)
@@ -61,6 +61,37 @@ static const struct snd_kcontrol_new rk_mc_controls[] = {
        SOC_DAPM_PIN_SWITCH("Speaker"),
 };
 
+static int rk_jack_event(struct notifier_block *nb, unsigned long event,
+                        void *data)
+{
+       struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
+       struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+
+       if (event & SND_JACK_MICROPHONE)
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+       else
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct notifier_block rk_jack_nb = {
+       .notifier_call = rk_jack_event,
+};
+
+static int rk_init(struct snd_soc_pcm_runtime *runtime)
+{
+       /*
+        * The jack has already been created in the rk_98090_headset_init()
+        * function.
+        */
+       snd_soc_jack_notifier_register(&headset_jack, &rk_jack_nb);
+
+       return 0;
+}
+
 static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -119,6 +150,7 @@ SND_SOC_DAILINK_DEFS(hifi,
 static struct snd_soc_dai_link rk_dailink = {
        .name = "max98090",
        .stream_name = "Audio",
+       .init = rk_init,
        .ops = &rk_aif1_ops,
        /* set max98090 as slave */
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
index dfb6e46..f0f5fa9 100644 (file)
@@ -284,9 +284,8 @@ static int odroid_audio_probe(struct platform_device *pdev)
        }
 
        of_node_put(cpu);
-       of_node_put(codec);
        if (ret < 0)
-               return ret;
+               goto err_put_node;
 
        ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link);
        if (ret < 0)
@@ -309,7 +308,6 @@ static int odroid_audio_probe(struct platform_device *pdev)
                ret = PTR_ERR(priv->clk_i2s_bus);
                goto err_put_sclk;
        }
-       of_node_put(cpu_dai);
 
        ret = devm_snd_soc_register_card(dev, card);
        if (ret < 0) {
@@ -317,6 +315,8 @@ static int odroid_audio_probe(struct platform_device *pdev)
                goto err_put_clk_i2s;
        }
 
+       of_node_put(cpu_dai);
+       of_node_put(codec);
        return 0;
 
 err_put_clk_i2s:
@@ -326,6 +326,8 @@ err_put_sclk:
 err_put_cpu_dai:
        of_node_put(cpu_dai);
        snd_soc_of_put_dai_link_codecs(codec_link);
+err_put_node:
+       of_node_put(codec);
        return ret;
 }
 
index fd6eaae..44f899b 100644 (file)
@@ -1515,8 +1515,11 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
                }
        }
 
-       if (dai_link->dai_fmt)
-               snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
+       if (dai_link->dai_fmt) {
+               ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
+               if (ret)
+                       return ret;
+       }
 
        ret = soc_post_component_init(rtd, dai_link->name);
        if (ret)
index f013b24..2790c00 100644 (file)
@@ -1157,8 +1157,8 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
                list_add_tail(&widget->work_list, list);
 
        if (custom_stop_condition && custom_stop_condition(widget, dir)) {
-               widget->endpoints[dir] = 1;
-               return widget->endpoints[dir];
+               list = NULL;
+               custom_stop_condition = NULL;
        }
 
        if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
@@ -1195,8 +1195,8 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
  *
  * Optionally, can be supplied with a function acting as a stopping condition.
  * This function takes the dapm widget currently being examined and the walk
- * direction as an arguments, it should return true if the walk should be
- * stopped and false otherwise.
+ * direction as an arguments, it should return true if widgets from that point
+ * in the graph onwards should not be added to the widget list.
  */
 static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
        struct list_head *list,
@@ -3706,6 +3706,8 @@ request_failed:
                dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
                        w->name, ret);
 
+       kfree_const(w->sname);
+       kfree(w);
        return ERR_PTR(ret);
 }
 
index f2b3929..ffd8d43 100644 (file)
@@ -101,8 +101,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
                /*
                 * This interrupt is not shared so no need to return IRQ_NONE.
                 */
-               dev_err_ratelimited(sdev->dev,
-                                   "error: nothing to do in IRQ thread\n");
+               dev_dbg_ratelimited(sdev->dev,
+                                   "nothing to do in IPC IRQ thread\n");
        }
 
        /* re-enable IPC interrupt */
index 50244b8..2ecba91 100644 (file)
@@ -224,8 +224,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
                /*
                 * This interrupt is not shared so no need to return IRQ_NONE.
                 */
-               dev_err_ratelimited(sdev->dev,
-                                   "error: nothing to do in IRQ thread\n");
+               dev_dbg_ratelimited(sdev->dev,
+                                   "nothing to do in IPC IRQ thread\n");
        }
 
        /* re-enable IPC interrupt */
index 9b22329..7fa5c61 100644 (file)
@@ -1002,8 +1002,8 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
        .field_rxchanmap        = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
        .field_txchansel        = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
        .field_rxchansel        = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
-       .get_sr                 = sun8i_i2s_get_sr_wss,
-       .get_wss                = sun8i_i2s_get_sr_wss,
+       .get_sr                 = sun4i_i2s_get_sr,
+       .get_wss                = sun4i_i2s_get_wss,
 };
 
 static int sun4i_i2s_init_regmap_fields(struct device *dev,
index ac59b50..bc7bf15 100644 (file)
@@ -195,7 +195,7 @@ static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
 {
        u32 bit;
 
-       for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) {
+       for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) {
                if (enable)
                        mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
                else
@@ -223,6 +223,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
        if (mcasp_is_synchronous(mcasp)) {
                mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
                mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+               mcasp_set_clk_pdir(mcasp, true);
        }
 
        /* Activate serializer(s) */
@@ -1256,6 +1257,28 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
+                                           struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask nfmt;
+       int i, slot_width;
+
+       snd_mask_none(&nfmt);
+       slot_width = rd->mcasp->slot_width;
+
+       for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+               if (snd_mask_test(fmt, i)) {
+                       if (snd_pcm_format_width(i) <= slot_width) {
+                               snd_mask_set(&nfmt, i);
+                       }
+               }
+       }
+
+       return snd_mask_refine(fmt, &nfmt);
+}
+
 static const unsigned int davinci_mcasp_dai_rates[] = {
        8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
        88200, 96000, 176400, 192000,
@@ -1377,7 +1400,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
        struct davinci_mcasp_ruledata *ruledata =
                                        &mcasp->ruledata[substream->stream];
        u32 max_channels = 0;
-       int i, dir;
+       int i, dir, ret;
        int tdm_slots = mcasp->tdm_slots;
 
        /* Do not allow more then one stream per direction */
@@ -1406,6 +1429,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                        max_channels++;
        }
        ruledata->serializers = max_channels;
+       ruledata->mcasp = mcasp;
        max_channels *= tdm_slots;
        /*
         * If the already active stream has less channels than the calculated
@@ -1431,20 +1455,22 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                   0, SNDRV_PCM_HW_PARAM_CHANNELS,
                                   &mcasp->chconstr[substream->stream]);
 
-       if (mcasp->slot_width)
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            8, mcasp->slot_width);
+       if (mcasp->slot_width) {
+               /* Only allow formats require <= slot_width bits on the bus */
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_FORMAT,
+                                         davinci_mcasp_hw_rule_slot_width,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
+               if (ret)
+                       return ret;
+       }
 
        /*
         * If we rely on implicit BCLK divider setting we should
         * set constraints based on what we can provide.
         */
        if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
-               int ret;
-
-               ruledata->mcasp = mcasp;
-
                ret = snd_pcm_hw_rule_add(substream->runtime, 0,
                                          SNDRV_PCM_HW_PARAM_RATE,
                                          davinci_mcasp_hw_rule_rate,