return le32_to_cpu(data);
 }
 
+/*
+ * Try to set the given sample rate:
+ *
+ * Return 0 if the clock source is read-only, the actual rate on success,
+ * or a negative error code.
+ *
+ * This function gets called from format.c to validate each sample rate, too.
+ * Hence no message is shown upon error
+ */
+int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
+                                const struct audioformat *fmt,
+                                int clock, int rate)
+{
+       bool writeable;
+       u32 bmControls;
+       __le32 data;
+       int err;
+
+       if (fmt->protocol == UAC_VERSION_3) {
+               struct uac3_clock_source_descriptor *cs_desc;
+
+               cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock);
+               bmControls = le32_to_cpu(cs_desc->bmControls);
+       } else {
+               struct uac_clock_source_descriptor *cs_desc;
+
+               cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
+               bmControls = cs_desc->bmControls;
+       }
+
+       writeable = uac_v2v3_control_is_writeable(bmControls,
+                                                 UAC2_CS_CONTROL_SAM_FREQ);
+       if (!writeable)
+               return 0;
+
+       data = cpu_to_le32(rate);
+       err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8,
+                             snd_usb_ctrl_intf(chip) | (clock << 8),
+                             &data, sizeof(data));
+       if (err < 0)
+               return err;
+
+       return get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock);
+}
+
 static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
-                             struct usb_host_interface *alts,
-                             struct audioformat *fmt, int rate)
+                               struct usb_host_interface *alts,
+                               struct audioformat *fmt, int rate)
 {
        struct usb_device *dev = chip->dev;
-       __le32 data;
-       int err, cur_rate, prev_rate;
+       int cur_rate, prev_rate;
        int clock;
-       bool writeable;
-       u32 bmControls;
 
        /* First, try to find a valid clock. This may trigger
         * automatic clock selection if the current clock is not
        if (prev_rate == rate)
                goto validation;
 
-       if (fmt->protocol == UAC_VERSION_3) {
-               struct uac3_clock_source_descriptor *cs_desc;
-
-               cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock);
-               bmControls = le32_to_cpu(cs_desc->bmControls);
-       } else {
-               struct uac_clock_source_descriptor *cs_desc;
-
-               cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
-               bmControls = cs_desc->bmControls;
+       cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate);
+       if (cur_rate < 0) {
+               usb_audio_err(chip,
+                             "%d:%d: cannot set freq %d (v2/v3): err %d\n",
+                             iface, fmt->altsetting, rate, cur_rate);
+               return cur_rate;
        }
 
-       writeable = uac_v2v3_control_is_writeable(bmControls,
-                                                 UAC2_CS_CONTROL_SAM_FREQ);
-       if (writeable) {
-               data = cpu_to_le32(rate);
-               err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
-                                     USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-                                     UAC2_CS_CONTROL_SAM_FREQ << 8,
-                                     snd_usb_ctrl_intf(chip) | (clock << 8),
-                                     &data, sizeof(data));
-               if (err < 0) {
-                       usb_audio_err(chip,
-                               "%d:%d: cannot set freq %d (v2/v3): err %d\n",
-                               iface, fmt->altsetting, rate, err);
-                       return err;
-               }
-
-               cur_rate = get_sample_rate_v2v3(chip, iface,
-                                               fmt->altsetting, clock);
-       } else {
+       if (!cur_rate)
                cur_rate = prev_rate;
-       }
 
        if (cur_rate != rate) {
-               if (!writeable) {
-                       usb_audio_warn(chip,
-                                "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
-                                iface, fmt->altsetting, rate, cur_rate);
-                       return -ENXIO;
-               }
-               usb_audio_dbg(chip,
-                       "current rate %d is different from the runtime rate %d\n",
-                       cur_rate, rate);
+               usb_audio_warn(chip,
+                              "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
+                              fmt->iface, fmt->altsetting, rate, cur_rate);
+               return -ENXIO;
        }
 
        /* Some devices doesn't respond to sample rate changes while the
 
        return -ENODEV;
 }
 
+/* check whether the given altsetting is supported for the already set rate */
+static bool check_valid_altsetting_v2v3(struct snd_usb_audio *chip, int iface,
+                                       int altsetting)
+{
+       struct usb_device *dev = chip->dev;
+       __le64 raw_data = 0;
+       u64 data;
+       int err;
+
+       /* we assume 64bit is enough for any altsettings */
+       if (snd_BUG_ON(altsetting >= 64 - 8))
+               return false;
+
+       err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_AS_VAL_ALT_SETTINGS << 8,
+                             iface, &raw_data, sizeof(raw_data));
+       if (err < 0)
+               return false;
+
+       data = le64_to_cpu(raw_data);
+       /* first byte contains the bitmap size */
+       if ((data & 0xff) * 8 < altsetting)
+               return false;
+       if (data & (1ULL << (altsetting + 8)))
+               return true;
+
+       return false;
+}
+
+/*
+ * Validate each sample rate with the altsetting
+ * Rebuild the rate table if only partial values are valid
+ */
+static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip,
+                                          struct audioformat *fp,
+                                          int clock)
+{
+       struct usb_device *dev = chip->dev;
+       unsigned int *table;
+       unsigned int nr_rates;
+       unsigned int rate_min = 0x7fffffff;
+       unsigned int rate_max = 0;
+       unsigned int rates = 0;
+       int i, err;
+
+       table = kcalloc(fp->nr_rates, sizeof(*table), GFP_KERNEL);
+       if (!table)
+               return -ENOMEM;
+
+       /* clear the interface altsetting at first */
+       usb_set_interface(dev, fp->iface, 0);
+
+       nr_rates = 0;
+       for (i = 0; i < fp->nr_rates; i++) {
+               err = snd_usb_set_sample_rate_v2v3(chip, fp, clock,
+                                                  fp->rate_table[i]);
+               if (err < 0)
+                       continue;
+
+               if (check_valid_altsetting_v2v3(chip, fp->iface, fp->altsetting)) {
+                       table[nr_rates++] = fp->rate_table[i];
+                       if (rate_min > fp->rate_table[i])
+                               rate_min = fp->rate_table[i];
+                       if (rate_max < fp->rate_table[i])
+                               rate_max = fp->rate_table[i];
+                       rates |= snd_pcm_rate_to_rate_bit(fp->rate_table[i]);
+               }
+       }
+
+       if (!nr_rates) {
+               usb_audio_dbg(chip,
+                             "No valid sample rate available for %d:%d, assuming a firmware bug\n",
+                             fp->iface, fp->altsetting);
+               nr_rates = fp->nr_rates; /* continue as is */
+       }
+
+       if (fp->nr_rates == nr_rates) {
+               kfree(table);
+               return 0;
+       }
+
+       kfree(fp->rate_table);
+       fp->rate_table = table;
+       fp->nr_rates = nr_rates;
+       fp->rate_min = rate_min;
+       fp->rate_max = rate_max;
+       fp->rates = rates;
+       return 0;
+}
+
 /*
  * parse the format descriptor and stores the possible sample rates
  * on the audioformat table (audio class v2 and v3).
         * allocated, so the rates will be stored */
        parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);
 
+       ret = validate_sample_rate_table_v2v3(chip, fp, clock);
+
 err_free:
        kfree(data);
 err: