Merge remote-tracking branch 'stable/linux-5.10.y' into rpi-5.10.y
authorpopcornmix <popcornmix@gmail.com>
Mon, 15 Mar 2021 15:33:27 +0000 (15:33 +0000)
committerpopcornmix <popcornmix@gmail.com>
Mon, 15 Mar 2021 15:33:27 +0000 (15:33 +0000)
47 files changed:
Makefile
arch/arm64/Kconfig
arch/parisc/Kconfig
arch/x86/kvm/svm/svm.c
arch/x86/kvm/x86.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/evhandler.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/video_detect.c
drivers/bluetooth/hci_qca.c
drivers/bus/ti-sysc.c
drivers/gpu/drm/msm/adreno/a5xx_gpu.c
drivers/hid/hid-ids.h
drivers/hid/hid-mf.c
drivers/hid/hid-quirks.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/iommu/amd/iommu.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/misc/eeprom/eeprom_93xx46.c
drivers/mmc/host/sdhci-of-dwcmshc.c
drivers/net/wireless/marvell/mwifiex/pcie.c
drivers/net/wireless/marvell/mwifiex/pcie.h
drivers/nvme/host/pci.c
drivers/pci/controller/cadence/pci-j721e.c
drivers/pci/controller/cadence/pcie-cadence-host.c
drivers/pci/controller/cadence/pcie-cadence.h
drivers/pci/quirks.c
drivers/platform/x86/acer-wmi.c
drivers/scsi/ufs/ufs-exynos.c
drivers/scsi/ufs/ufs-mediatek.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/usb/cdns3/core.c
drivers/usb/cdns3/core.h
drivers/usb/cdns3/host-export.h
drivers/usb/cdns3/host.c
fs/btrfs/delayed-inode.c
fs/btrfs/inode.c
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
include/linux/eeprom_93xx46.h
include/linux/platform_data/ti-sysc.h
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/sof/intel/Kconfig
sound/usb/mixer_quirks.c

index b8a4e01..780a2e7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 5
 PATCHLEVEL = 10
-SUBLEVEL = 22
+SUBLEVEL = 23
 EXTRAVERSION =
 NAME = Dare mighty things
 
index afe4bc5..c1be642 100644 (file)
@@ -950,8 +950,9 @@ choice
          that is selected here.
 
 config CPU_BIG_ENDIAN
-       bool "Build big-endian kernel"
-       help
+       bool "Build big-endian kernel"
+       depends on !LD_IS_LLD || LLD_VERSION >= 130000
+       help
          Say Y if you plan on running a kernel with a big-endian userspace.
 
 config CPU_LITTLE_ENDIAN
index 04dc17d..14f3252 100644 (file)
@@ -201,9 +201,12 @@ config PREFETCH
        def_bool y
        depends on PA8X00 || PA7200
 
+config PARISC_HUGE_KERNEL
+       def_bool y if !MODULES || UBSAN || FTRACE || COMPILE_TEST
+
 config MLONGCALLS
-       def_bool y if !MODULES || UBSAN || FTRACE
-       bool "Enable the -mlong-calls compiler option for big kernels" if MODULES && !UBSAN && !FTRACE
+       def_bool y if PARISC_HUGE_KERNEL
+       bool "Enable the -mlong-calls compiler option for big kernels" if !PARISC_HUGE_KERNEL
        depends on PA8X00
        help
          If you configure the kernel to include many drivers built-in instead
index 76ab1ee..642f0da 100644 (file)
@@ -1192,6 +1192,7 @@ static void init_vmcb(struct vcpu_svm *svm)
        init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
        init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
 
+       svm_set_cr4(&svm->vcpu, 0);
        svm_set_efer(&svm->vcpu, 0);
        save->dr6 = 0xffff0ff0;
        kvm_set_rflags(&svm->vcpu, 2);
index e7ca622..2249a7d 100644 (file)
@@ -404,6 +404,8 @@ bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type);
                __reserved_bits |= X86_CR4_UMIP;        \
        if (!__cpu_has(__c, X86_FEATURE_VMX))           \
                __reserved_bits |= X86_CR4_VMXE;        \
+       if (!__cpu_has(__c, X86_FEATURE_PCID))          \
+               __reserved_bits |= X86_CR4_PCIDE;       \
        __reserved_bits;                                \
 })
 
index 9f0219a..dd7efaf 100644 (file)
@@ -284,6 +284,7 @@ struct acpi_object_addr_handler {
        acpi_adr_space_handler handler;
        struct acpi_namespace_node *node;       /* Parent device */
        void *context;
+       acpi_mutex context_mutex;
        acpi_adr_space_setup setup;
        union acpi_operand_object *region_list; /* Regions using this handler */
        union acpi_operand_object *next;
index 5884eba..3438dc1 100644 (file)
@@ -489,6 +489,13 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node,
 
        /* Init handler obj */
 
+       status =
+           acpi_os_create_mutex(&handler_obj->address_space.context_mutex);
+       if (ACPI_FAILURE(status)) {
+               acpi_ut_remove_reference(handler_obj);
+               goto unlock_and_exit;
+       }
+
        handler_obj->address_space.space_id = (u8)space_id;
        handler_obj->address_space.handler_flags = flags;
        handler_obj->address_space.region_list = NULL;
index 738d4b2..980efc9 100644 (file)
@@ -111,6 +111,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        union acpi_operand_object *region_obj2;
        void *region_context = NULL;
        struct acpi_connection_info *context;
+       acpi_mutex context_mutex;
+       u8 context_locked;
        acpi_physical_address address;
 
        ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
@@ -135,6 +137,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        }
 
        context = handler_desc->address_space.context;
+       context_mutex = handler_desc->address_space.context_mutex;
+       context_locked = FALSE;
 
        /*
         * It may be the case that the region has never been initialized.
@@ -203,6 +207,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        handler = handler_desc->address_space.handler;
        address = (region_obj->region.address + region_offset);
 
+       ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+                         "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
+                         &region_obj->region.handler->address_space, handler,
+                         ACPI_FORMAT_UINT64(address),
+                         acpi_ut_get_region_name(region_obj->region.
+                                                 space_id)));
+
+       if (!(handler_desc->address_space.handler_flags &
+             ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+               /*
+                * For handlers other than the default (supplied) handlers, we must
+                * exit the interpreter because the handler *might* block -- we don't
+                * know what it will do, so we can't hold the lock on the interpreter.
+                */
+               acpi_ex_exit_interpreter();
+       }
+
        /*
         * Special handling for generic_serial_bus and general_purpose_io:
         * There are three extra parameters that must be passed to the
@@ -211,6 +232,11 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
         *   2) Length of the above buffer
         *   3) Actual access length from the access_as() op
         *
+        * Since we pass these extra parameters via the context, which is
+        * shared between threads, we must lock the context to avoid these
+        * parameters being changed from another thread before the handler
+        * has completed running.
+        *
         * In addition, for general_purpose_io, the Address and bit_width fields
         * are defined as follows:
         *   1) Address is the pin number index of the field (bit offset from
@@ -220,6 +246,14 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
            context && field_obj) {
 
+               status =
+                   acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
+               if (ACPI_FAILURE(status)) {
+                       goto re_enter_interpreter;
+               }
+
+               context_locked = TRUE;
+
                /* Get the Connection (resource_template) buffer */
 
                context->connection = field_obj->field.resource_buffer;
@@ -229,6 +263,14 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
            context && field_obj) {
 
+               status =
+                   acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
+               if (ACPI_FAILURE(status)) {
+                       goto re_enter_interpreter;
+               }
+
+               context_locked = TRUE;
+
                /* Get the Connection (resource_template) buffer */
 
                context->connection = field_obj->field.resource_buffer;
@@ -238,28 +280,15 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                bit_width = field_obj->field.bit_length;
        }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
-                         "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
-                         &region_obj->region.handler->address_space, handler,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(region_obj->region.
-                                                 space_id)));
-
-       if (!(handler_desc->address_space.handler_flags &
-             ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
-               /*
-                * For handlers other than the default (supplied) handlers, we must
-                * exit the interpreter because the handler *might* block -- we don't
-                * know what it will do, so we can't hold the lock on the interpreter.
-                */
-               acpi_ex_exit_interpreter();
-       }
-
        /* Call the handler */
 
        status = handler(function, address, bit_width, value, context,
                         region_obj2->extra.region_context);
 
+       if (context_locked) {
+               acpi_os_release_mutex(context_mutex);
+       }
+
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
                                acpi_ut_get_region_name(region_obj->region.
@@ -276,6 +305,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                }
        }
 
+re_enter_interpreter:
        if (!(handler_desc->address_space.handler_flags &
              ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
                /*
index da97fd0..3bb06f1 100644 (file)
@@ -201,6 +201,8 @@ acpi_remove_address_space_handler(acpi_handle device,
 
                        /* Now we can delete the handler object */
 
+                       acpi_os_release_mutex(handler_obj->address_space.
+                                             context_mutex);
                        acpi_ut_remove_reference(handler_obj);
                        goto unlock_and_exit;
                }
index 4f5463b..811d298 100644 (file)
@@ -140,6 +140,13 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_vendor,
+       .ident = "GIGABYTE GB-BXBT-2807",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
+               },
+       },
+       {
        .ident = "Sony VPCEH3U1E",
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
index 5c26c7d..ad47ff0 100644 (file)
@@ -78,6 +78,7 @@ enum qca_flags {
 
 enum qca_capabilities {
        QCA_CAP_WIDEBAND_SPEECH = BIT(0),
+       QCA_CAP_VALID_LE_STATES = BIT(1),
 };
 
 /* HCI_IBS transmit side sleep protocol states */
@@ -1782,7 +1783,7 @@ static const struct qca_device_data qca_soc_data_wcn3991 = {
                { "vddch0", 450000 },
        },
        .num_vregs = 4,
-       .capabilities = QCA_CAP_WIDEBAND_SPEECH,
+       .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
 };
 
 static const struct qca_device_data qca_soc_data_wcn3998 = {
@@ -2019,11 +2020,17 @@ static int qca_serdev_probe(struct serdev_device *serdev)
                hdev->shutdown = qca_power_off;
        }
 
-       /* Wideband speech support must be set per driver since it can't be
-        * queried via hci.
-        */
-       if (data && (data->capabilities & QCA_CAP_WIDEBAND_SPEECH))
-               set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
+       if (data) {
+               /* Wideband speech support must be set per driver since it can't
+                * be queried via hci. Same with the valid le states quirk.
+                */
+               if (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)
+                       set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
+                               &hdev->quirks);
+
+               if (data->capabilities & QCA_CAP_VALID_LE_STATES)
+                       set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
+       }
 
        return 0;
 }
index 92ecf1a..45f5530 100644 (file)
@@ -1379,6 +1379,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   SYSC_QUIRK_CLKDM_NOAUTO),
        SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
                   SYSC_QUIRK_CLKDM_NOAUTO),
+       SYSC_QUIRK("gpmc", 0, 0, 0x10, 0x14, 0x00000060, 0xffffffff,
+                  SYSC_QUIRK_GPMC_DEBUG),
        SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff,
                   SYSC_QUIRK_OPT_CLKS_NEEDED),
        SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
@@ -1814,6 +1816,14 @@ static void sysc_init_module_quirks(struct sysc *ddata)
                return;
        }
 
+#ifdef CONFIG_OMAP_GPMC_DEBUG
+       if (ddata->cfg.quirks & SYSC_QUIRK_GPMC_DEBUG) {
+               ddata->cfg.quirks |= SYSC_QUIRK_NO_RESET_ON_INIT;
+
+               return;
+       }
+#endif
+
        if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) {
                ddata->pre_reset_quirk = sysc_pre_reset_quirk_i2c;
                ddata->post_reset_quirk = sysc_post_reset_quirk_i2c;
index 69ed2c6..5e11cdb 100644 (file)
@@ -626,8 +626,6 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
        if (adreno_gpu->info->quirks & ADRENO_QUIRK_TWO_PASS_USE_WFI)
                gpu_rmw(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8));
 
-       gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0xc0200100);
-
        /* Enable USE_RETENTION_FLOPS */
        gpu_write(gpu, REG_A5XX_CP_CHICKEN_DBG, 0x02000000);
 
index 95fa95e..e476ca6 100644 (file)
 #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR    0x1803
 #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1     0x1843
 #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2     0x1844
+#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE3     0x1846
 
 #define USB_VENDOR_ID_DWAV             0x0eef
 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER   0x0001
 #define USB_DEVICE_ID_INNEX_GENESIS_ATARI      0x4745
 
 #define USB_VENDOR_ID_ITE               0x048d
+#define I2C_VENDOR_ID_ITE              0x103c
+#define I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15      0x184f
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA2  0x8350
 #define I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720   0x837a
index fc75f30..92d7ecd 100644 (file)
@@ -153,6 +153,8 @@ static const struct hid_device_id mf_devices[] = {
                .driver_data = HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2),
                .driver_data = 0 }, /* No quirk required */
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3),
+               .driver_data = HID_QUIRK_MULTI_INPUT },
        { }
 };
 MODULE_DEVICE_TABLE(hid, mf_devices);
index 3cde18e..bdc135f 100644 (file)
@@ -73,6 +73,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
@@ -486,6 +487,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3) },
 #endif
 #if IS_ENABLED(CONFIG_HID_MICROSOFT)
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
index aeff1ff..cb7758d 100644 (file)
@@ -171,6 +171,8 @@ static const struct i2c_hid_quirks {
                I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
        { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
                I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
+       { I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15,
+               I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
        { I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_3118,
                I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
        { USB_VENDOR_ID_ELAN, HID_ANY_ID,
index b9cf594..5f11957 100644 (file)
@@ -1503,6 +1503,10 @@ static bool increase_address_space(struct protection_domain *domain,
        bool ret = true;
        u64 *pte;
 
+       pte = (void *)get_zeroed_page(gfp);
+       if (!pte)
+               return false;
+
        spin_lock_irqsave(&domain->lock, flags);
 
        amd_iommu_domain_get_pgtable(domain, &pgtable);
@@ -1514,10 +1518,6 @@ static bool increase_address_space(struct protection_domain *domain,
        if (WARN_ON_ONCE(pgtable.mode == PAGE_MODE_6_LEVEL))
                goto out;
 
-       pte = (void *)get_zeroed_page(gfp);
-       if (!pte)
-               goto out;
-
        *pte = PM_LEVEL_PDE(pgtable.mode, iommu_virt_to_phys(pgtable.root));
 
        pgtable.root  = pte;
@@ -1531,10 +1531,12 @@ static bool increase_address_space(struct protection_domain *domain,
         */
        amd_iommu_domain_set_pgtable(domain, pte, pgtable.mode);
 
+       pte = NULL;
        ret = true;
 
 out:
        spin_unlock_irqrestore(&domain->lock, flags);
+       free_page((unsigned long)pte);
 
        return ret;
 }
index 4b0c53f..4e8132d 100644 (file)
@@ -2074,6 +2074,10 @@ static struct {
         * 0x1451 is PCI ID for the IOMMU found on Ryzen
         */
        { PCI_VENDOR_ID_AMD, 0x1451 },
+       /* According to sudo lspci -nn,
+        * 0x1423 is the PCI ID for the IOMMU found on Kaveri
+        */
+       { PCI_VENDOR_ID_AMD, 0x1423 },
 };
 
 static bool cx23885_does_need_dma_reset(void)
index d92c4d2..6e5f544 100644 (file)
@@ -35,6 +35,10 @@ static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
                  EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
 };
 
+static const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = {
+       .quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE,
+};
+
 struct eeprom_93xx46_dev {
        struct spi_device *spi;
        struct eeprom_93xx46_platform_data *pdata;
@@ -55,6 +59,11 @@ static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev)
        return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
 }
 
+static inline bool has_quirk_extra_read_cycle(struct eeprom_93xx46_dev *edev)
+{
+       return edev->pdata->quirks & EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE;
+}
+
 static int eeprom_93xx46_read(void *priv, unsigned int off,
                              void *val, size_t count)
 {
@@ -96,6 +105,11 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
                dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
                        cmd_addr, edev->spi->max_speed_hz);
 
+               if (has_quirk_extra_read_cycle(edev)) {
+                       cmd_addr <<= 1;
+                       bits += 1;
+               }
+
                spi_message_init(&m);
 
                t[0].tx_buf = (char *)&cmd_addr;
@@ -363,6 +377,7 @@ static void select_deassert(void *context)
 static const struct of_device_id eeprom_93xx46_of_table[] = {
        { .compatible = "eeprom-93xx46", },
        { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
+       { .compatible = "microchip,93lc46b", .data = &microchip_93lc46b_data, },
        {}
 };
 MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table);
index d90020e..59d8d96 100644 (file)
@@ -112,6 +112,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = {
 static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
        .ops = &sdhci_dwcmshc_ops,
        .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
 static int dwcmshc_probe(struct platform_device *pdev)
index 6a10ff0..33cf952 100644 (file)
@@ -526,6 +526,8 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
        clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
        clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
        mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+
+       card->pci_reset_ongoing = true;
 }
 
 /*
@@ -554,6 +556,8 @@ static void mwifiex_pcie_reset_done(struct pci_dev *pdev)
                dev_err(&pdev->dev, "reinit failed: %d\n", ret);
        else
                mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+
+       card->pci_reset_ongoing = false;
 }
 
 static const struct pci_error_handlers mwifiex_pcie_err_handler = {
@@ -3142,7 +3146,19 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter)
        int ret;
        u32 fw_status;
 
-       cancel_work_sync(&card->work);
+       /* Perform the cancel_work_sync() only when we're not resetting
+        * the card. It's because that function never returns if we're
+        * in reset path. If we're here when resetting the card, it means
+        * that we failed to reset the card (reset failure path).
+        */
+       if (!card->pci_reset_ongoing) {
+               mwifiex_dbg(adapter, MSG, "performing cancel_work_sync()...\n");
+               cancel_work_sync(&card->work);
+               mwifiex_dbg(adapter, MSG, "cancel_work_sync() done\n");
+       } else {
+               mwifiex_dbg(adapter, MSG,
+                           "skipped cancel_work_sync() because we're in card reset failure path\n");
+       }
 
        ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
        if (fw_status == FIRMWARE_READY_PCIE) {
index 843d57e..5ed613d 100644 (file)
@@ -242,6 +242,8 @@ struct pcie_service_card {
        struct mwifiex_msix_context share_irq_ctx;
        struct work_struct work;
        unsigned long work_flags;
+
+       bool pci_reset_ongoing;
 };
 
 static inline int
index 4a33287..99c59f9 100644 (file)
@@ -3235,7 +3235,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_DEVICE(0x126f, 0x2263),   /* Silicon Motion unidentified */
                .driver_data = NVME_QUIRK_NO_NS_DESC_LIST, },
        { PCI_DEVICE(0x1bb1, 0x0100),   /* Seagate Nytro Flash Storage */
-               .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
+               .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY |
+                               NVME_QUIRK_NO_NS_DESC_LIST, },
        { PCI_DEVICE(0x1c58, 0x0003),   /* HGST adapter */
                .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
        { PCI_DEVICE(0x1c58, 0x0023),   /* WDC SN200 adapter */
@@ -3249,6 +3250,9 @@ static const struct pci_device_id nvme_id_table[] = {
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_DEVICE(0x1987, 0x5016),   /* Phison E16 */
                .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+       { PCI_DEVICE(0x1b4b, 0x1092),   /* Lexar 256 GB SSD */
+               .driver_data = NVME_QUIRK_NO_NS_DESC_LIST |
+                               NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_DEVICE(0x1d1d, 0x1f1f),   /* LighNVM qemu device */
                .driver_data = NVME_QUIRK_LIGHTNVM, },
        { PCI_DEVICE(0x1d1d, 0x2807),   /* CNEX WL */
@@ -3264,6 +3268,8 @@ static const struct pci_device_id nvme_id_table[] = {
                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
        { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+       { PCI_DEVICE(0x2646, 0x2262),   /* KINGSTON SKC2000 NVMe SSD */
+               .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
        { PCI_DEVICE(0x2646, 0x2263),   /* KINGSTON A2000 NVMe SSD  */
                .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
index 586b9d6..d34ca0f 100644 (file)
@@ -63,6 +63,7 @@ enum j721e_pcie_mode {
 
 struct j721e_pcie_data {
        enum j721e_pcie_mode    mode;
+       bool quirk_retrain_flag;
 };
 
 static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
@@ -270,6 +271,7 @@ static struct pci_ops cdns_ti_pcie_host_ops = {
 
 static const struct j721e_pcie_data j721e_pcie_rc_data = {
        .mode = PCI_MODE_RC,
+       .quirk_retrain_flag = true,
 };
 
 static const struct j721e_pcie_data j721e_pcie_ep_data = {
@@ -378,6 +380,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
                bridge->ops = &cdns_ti_pcie_host_ops;
                rc = pci_host_bridge_priv(bridge);
+               rc->quirk_retrain_flag = data->quirk_retrain_flag;
 
                cdns_pcie = &rc->pcie;
                cdns_pcie->dev = dev;
index 1cb7cfc..73dcf8c 100644 (file)
@@ -77,6 +77,68 @@ static struct pci_ops cdns_pcie_host_ops = {
        .write          = pci_generic_config_write,
 };
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+       struct device *dev = pcie->dev;
+       int retries;
+
+       /* Check if the link is up or not */
+       for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+               if (cdns_pcie_link_up(pcie)) {
+                       dev_info(dev, "Link up\n");
+                       return 0;
+               }
+               usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+       u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+       u16 lnk_stat, lnk_ctl;
+       int ret = 0;
+
+       /*
+        * Set retrain bit if current speed is 2.5 GB/s,
+        * but the PCIe root port support is > 2.5 GB/s.
+        */
+
+       lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+                                            PCI_EXP_LNKCAP));
+       if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+               return ret;
+
+       lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+       if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+               lnk_ctl = cdns_pcie_rp_readw(pcie,
+                                            pcie_cap_off + PCI_EXP_LNKCTL);
+               lnk_ctl |= PCI_EXP_LNKCTL_RL;
+               cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+                                   lnk_ctl);
+
+               ret = cdns_pcie_host_wait_for_link(pcie);
+       }
+       return ret;
+}
+
+static int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc)
+{
+       struct cdns_pcie *pcie = &rc->pcie;
+       int ret;
+
+       ret = cdns_pcie_host_wait_for_link(pcie);
+
+       /*
+        * Retrain link for Gen2 training defect
+        * if quirk flag is set.
+        */
+       if (!ret && rc->quirk_retrain_flag)
+               ret = cdns_pcie_retrain(pcie);
+
+       return ret;
+}
 
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
@@ -399,23 +461,6 @@ static int cdns_pcie_host_init(struct device *dev,
        return cdns_pcie_host_init_address_translation(rc);
 }
 
-static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
-{
-       struct device *dev = pcie->dev;
-       int retries;
-
-       /* Check if the link is up or not */
-       for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-               if (cdns_pcie_link_up(pcie)) {
-                       dev_info(dev, "Link up\n");
-                       return 0;
-               }
-               usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-       }
-
-       return -ETIMEDOUT;
-}
-
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
        struct device *dev = rc->pcie.dev;
@@ -458,7 +503,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
                return ret;
        }
 
-       ret = cdns_pcie_host_wait_for_link(pcie);
+       ret = cdns_pcie_host_start_link(rc);
        if (ret)
                dev_dbg(dev, "PCIe link never came up\n");
 
index feed1e3..6705a5f 100644 (file)
  * Root Port Registers (PCI configuration space for the root port function)
  */
 #define CDNS_PCIE_RP_BASE      0x00200000
-
+#define CDNS_PCIE_RP_CAP_OFFSET 0xc0
 
 /*
  * Address Translation Registers
@@ -290,6 +290,7 @@ struct cdns_pcie {
  * @device_id: PCI device ID
  * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 and        RP_NO_BAR if it's free or
  *                available
+ * @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
  */
 struct cdns_pcie_rc {
        struct cdns_pcie        pcie;
@@ -298,6 +299,7 @@ struct cdns_pcie_rc {
        u32                     vendor_id;
        u32                     device_id;
        bool                    avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
+       bool                    quirk_retrain_flag;
 };
 
 /**
@@ -413,6 +415,13 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
        cdns_pcie_write_sz(addr, 0x2, value);
 }
 
+static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
+{
+       void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+       return cdns_pcie_read_sz(addr, 0x2);
+}
+
 /* Endpoint Function register access */
 static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
                                          u32 reg, u8 value)
index fb1dc11..b570f29 100644 (file)
@@ -3998,6 +3998,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9183,
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
                         quirk_dma_func1_alias);
+/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c135 */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9215,
+                        quirk_dma_func1_alias);
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220,
                         quirk_dma_func1_alias);
index 5592a92..80983f9 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/input/sparse-keymap.h>
 #include <acpi/video.h>
 
+ACPI_MODULE_NAME(KBUILD_MODNAME);
 MODULE_AUTHOR("Carlos Corbacho");
 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
 MODULE_LICENSE("GPL");
@@ -80,7 +81,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
 
 enum acer_wmi_event_ids {
        WMID_HOTKEY_EVENT = 0x1,
-       WMID_ACCEL_EVENT = 0x5,
+       WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
 };
 
 static const struct key_entry acer_wmi_keymap[] __initconst = {
@@ -128,7 +129,9 @@ struct event_return_value {
        u8 function;
        u8 key_num;
        u16 device_state;
-       u32 reserved;
+       u16 reserved1;
+       u8 kbd_dock_state;
+       u8 reserved2;
 } __attribute__((packed));
 
 /*
@@ -206,14 +209,13 @@ struct hotkey_function_type_aa {
 /*
  * Interface capability flags
  */
-#define ACER_CAP_MAILLED               (1<<0)
-#define ACER_CAP_WIRELESS              (1<<1)
-#define ACER_CAP_BLUETOOTH             (1<<2)
-#define ACER_CAP_BRIGHTNESS            (1<<3)
-#define ACER_CAP_THREEG                        (1<<4)
-#define ACER_CAP_ACCEL                 (1<<5)
-#define ACER_CAP_RFBTN                 (1<<6)
-#define ACER_CAP_ANY                   (0xFFFFFFFF)
+#define ACER_CAP_MAILLED               BIT(0)
+#define ACER_CAP_WIRELESS              BIT(1)
+#define ACER_CAP_BLUETOOTH             BIT(2)
+#define ACER_CAP_BRIGHTNESS            BIT(3)
+#define ACER_CAP_THREEG                        BIT(4)
+#define ACER_CAP_SET_FUNCTION_MODE     BIT(5)
+#define ACER_CAP_KBD_DOCK              BIT(6)
 
 /*
  * Interface type flags
@@ -236,6 +238,7 @@ static int mailled = -1;
 static int brightness = -1;
 static int threeg = -1;
 static int force_series;
+static int force_caps = -1;
 static bool ec_raw_mode;
 static bool has_type_aa;
 static u16 commun_func_bitmap;
@@ -245,11 +248,13 @@ module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
 module_param(threeg, int, 0444);
 module_param(force_series, int, 0444);
+module_param(force_caps, int, 0444);
 module_param(ec_raw_mode, bool, 0444);
 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
 MODULE_PARM_DESC(force_series, "Force a different laptop series");
+MODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
 MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
 
 struct acer_data {
@@ -319,6 +324,15 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
        return 1;
 }
 
+static int __init set_force_caps(const struct dmi_system_id *dmi)
+{
+       if (force_caps == -1) {
+               force_caps = (uintptr_t)dmi->driver_data;
+               pr_info("Found %s, set force_caps to 0x%x\n", dmi->ident, force_caps);
+       }
+       return 1;
+}
+
 static struct quirk_entry quirk_unknown = {
 };
 
@@ -497,6 +511,33 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
                },
                .driver_data = &quirk_acer_travelmate_2490,
        },
+       {
+               .callback = set_force_caps,
+               .ident = "Acer Aspire Switch 10E SW3-016",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-016"),
+               },
+               .driver_data = (void *)ACER_CAP_KBD_DOCK,
+       },
+       {
+               .callback = set_force_caps,
+               .ident = "Acer Aspire Switch 10 SW5-012",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+               },
+               .driver_data = (void *)ACER_CAP_KBD_DOCK,
+       },
+       {
+               .callback = set_force_caps,
+               .ident = "Acer One 10 (S1003)",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
+               },
+               .driver_data = (void *)ACER_CAP_KBD_DOCK,
+       },
        {}
 };
 
@@ -1253,10 +1294,8 @@ static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
                interface->capability |= ACER_CAP_THREEG;
        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
                interface->capability |= ACER_CAP_BLUETOOTH;
-       if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN) {
-               interface->capability |= ACER_CAP_RFBTN;
+       if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN)
                commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
-       }
 
        commun_fn_key_number = type_aa->commun_fn_key_number;
 }
@@ -1520,7 +1559,7 @@ static int acer_gsensor_event(void)
        struct acpi_buffer output;
        union acpi_object out_obj[5];
 
-       if (!has_cap(ACER_CAP_ACCEL))
+       if (!acer_wmi_accel_dev)
                return -1;
 
        output.length = sizeof(out_obj);
@@ -1544,6 +1583,71 @@ static int acer_gsensor_event(void)
 }
 
 /*
+ * Switch series keyboard dock status
+ */
+static int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state)
+{
+       switch (kbd_dock_state) {
+       case 0x01: /* Docked, traditional clamshell laptop mode */
+               return 0;
+       case 0x04: /* Stand-alone tablet */
+       case 0x40: /* Docked, tent mode, keyboard not usable */
+               return 1;
+       default:
+               pr_warn("Unknown kbd_dock_state 0x%02x\n", kbd_dock_state);
+       }
+
+       return 0;
+}
+
+static void acer_kbd_dock_get_initial_state(void)
+{
+       u8 *output, input[8] = { 0x05, 0x00, };
+       struct acpi_buffer input_buf = { sizeof(input), input };
+       struct acpi_buffer output_buf = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+       int sw_tablet_mode;
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Error getting keyboard-dock initial status"));
+               return;
+       }
+
+       obj = output_buf.pointer;
+       if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
+               pr_err("Unexpected output format getting keyboard-dock initial status\n");
+               goto out_free_obj;
+       }
+
+       output = obj->buffer.pointer;
+       if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) {
+               pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting keyboard-dock initial status\n",
+                      output[0], output[3]);
+               goto out_free_obj;
+       }
+
+       sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(output[4]);
+       input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
+
+out_free_obj:
+       kfree(obj);
+}
+
+static void acer_kbd_dock_event(const struct event_return_value *event)
+{
+       int sw_tablet_mode;
+
+       if (!has_cap(ACER_CAP_KBD_DOCK))
+               return;
+
+       sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(event->kbd_dock_state);
+       input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
+       input_sync(acer_wmi_input_dev);
+}
+
+/*
  * Rfkill devices
  */
 static void acer_rfkill_update(struct work_struct *ignored);
@@ -1770,8 +1874,9 @@ static void acer_wmi_notify(u32 value, void *context)
                        sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
                }
                break;
-       case WMID_ACCEL_EVENT:
+       case WMID_ACCEL_OR_KBD_DOCK_EVENT:
                acer_gsensor_event();
+               acer_kbd_dock_event(&return_value);
                break;
        default:
                pr_warn("Unknown function number - %d - %d\n",
@@ -1894,8 +1999,6 @@ static int __init acer_wmi_accel_setup(void)
        gsensor_handle = acpi_device_handle(adev);
        acpi_dev_put(adev);
 
-       interface->capability |= ACER_CAP_ACCEL;
-
        acer_wmi_accel_dev = input_allocate_device();
        if (!acer_wmi_accel_dev)
                return -ENOMEM;
@@ -1921,11 +2024,6 @@ err_free_dev:
        return err;
 }
 
-static void acer_wmi_accel_destroy(void)
-{
-       input_unregister_device(acer_wmi_accel_dev);
-}
-
 static int __init acer_wmi_input_setup(void)
 {
        acpi_status status;
@@ -1943,6 +2041,9 @@ static int __init acer_wmi_input_setup(void)
        if (err)
                goto err_free_dev;
 
+       if (has_cap(ACER_CAP_KBD_DOCK))
+               input_set_capability(acer_wmi_input_dev, EV_SW, SW_TABLET_MODE);
+
        status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
                                                acer_wmi_notify, NULL);
        if (ACPI_FAILURE(status)) {
@@ -1950,6 +2051,9 @@ static int __init acer_wmi_input_setup(void)
                goto err_free_dev;
        }
 
+       if (has_cap(ACER_CAP_KBD_DOCK))
+               acer_kbd_dock_get_initial_state();
+
        err = input_register_device(acer_wmi_input_dev);
        if (err)
                goto err_uninstall_notifier;
@@ -2080,7 +2184,7 @@ static int acer_resume(struct device *dev)
        if (has_cap(ACER_CAP_BRIGHTNESS))
                set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
 
-       if (has_cap(ACER_CAP_ACCEL))
+       if (acer_wmi_accel_dev)
                acer_gsensor_init();
 
        return 0;
@@ -2181,7 +2285,7 @@ static int __init acer_wmi_init(void)
                }
                /* WMID always provides brightness methods */
                interface->capability |= ACER_CAP_BRIGHTNESS;
-       } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
+       } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) {
                pr_err("No WMID device detection method found\n");
                return -ENODEV;
        }
@@ -2211,7 +2315,14 @@ static int __init acer_wmi_init(void)
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                interface->capability &= ~ACER_CAP_BRIGHTNESS;
 
-       if (wmi_has_guid(WMID_GUID3)) {
+       if (wmi_has_guid(WMID_GUID3))
+               interface->capability |= ACER_CAP_SET_FUNCTION_MODE;
+
+       if (force_caps != -1)
+               interface->capability = force_caps;
+
+       if (wmi_has_guid(WMID_GUID3) &&
+           (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
                if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
                        pr_warn("Cannot enable RF Button Driver\n");
 
@@ -2270,8 +2381,8 @@ error_device_alloc:
 error_platform_register:
        if (wmi_has_guid(ACERWMID_EVENT_GUID))
                acer_wmi_input_destroy();
-       if (has_cap(ACER_CAP_ACCEL))
-               acer_wmi_accel_destroy();
+       if (acer_wmi_accel_dev)
+               input_unregister_device(acer_wmi_accel_dev);
 
        return err;
 }
@@ -2281,8 +2392,8 @@ static void __exit acer_wmi_exit(void)
        if (wmi_has_guid(ACERWMID_EVENT_GUID))
                acer_wmi_input_destroy();
 
-       if (has_cap(ACER_CAP_ACCEL))
-               acer_wmi_accel_destroy();
+       if (acer_wmi_accel_dev)
+               input_unregister_device(acer_wmi_accel_dev);
 
        remove_debugfs();
        platform_device_unregister(acer_platform_device);
index 5e6b95d..f54b494 100644 (file)
@@ -653,6 +653,11 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
                }
        }
 
+       /* setting for three timeout values for traffic class #0 */
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 8064);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 28224);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 20160);
+
        return 0;
 out:
        return ret;
@@ -1249,7 +1254,9 @@ struct exynos_ufs_drv_data exynos_ufs_drvs = {
                                  UFSHCI_QUIRK_BROKEN_HCE |
                                  UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR |
                                  UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
-                                 UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL,
+                                 UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL |
+                                 UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING |
+                                 UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE,
        .opts                   = EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL |
                                  EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
                                  EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX |
index 914a827..9347134 100644 (file)
@@ -566,6 +566,7 @@ static int ufs_mtk_init(struct ufs_hba *hba)
 
        /* Enable WriteBooster */
        hba->caps |= UFSHCD_CAP_WB_EN;
+       hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL;
        hba->vps->wb_flush_threshold = UFS_WB_BUF_REMAIN_PERCENT(80);
 
        /*
index 8132893..5a7cc2e 100644 (file)
@@ -4153,25 +4153,27 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
                ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
                                                pwr_mode->hs_rate);
 
-       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0),
-                       DL_FC0ProtectionTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1),
-                       DL_TC0ReplayTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2),
-                       DL_AFC0ReqTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA3),
-                       DL_FC1ProtectionTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA4),
-                       DL_TC1ReplayTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA5),
-                       DL_AFC1ReqTimeOutVal_Default);
-
-       ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalFC0ProtectionTimeOutVal),
-                       DL_FC0ProtectionTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalTC0ReplayTimeOutVal),
-                       DL_TC0ReplayTimeOutVal_Default);
-       ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal),
-                       DL_AFC0ReqTimeOutVal_Default);
+       if (!(hba->quirks & UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING)) {
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0),
+                               DL_FC0ProtectionTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1),
+                               DL_TC0ReplayTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2),
+                               DL_AFC0ReqTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA3),
+                               DL_FC1ProtectionTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA4),
+                               DL_TC1ReplayTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA5),
+                               DL_AFC1ReqTimeOutVal_Default);
+
+               ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalFC0ProtectionTimeOutVal),
+                               DL_FC0ProtectionTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalTC0ReplayTimeOutVal),
+                               DL_TC0ReplayTimeOutVal_Default);
+               ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal),
+                               DL_AFC0ReqTimeOutVal_Default);
+       }
 
        ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4
                        | pwr_mode->pwr_tx);
@@ -4746,6 +4748,8 @@ static int ufshcd_slave_configure(struct scsi_device *sdev)
        struct request_queue *q = sdev->request_queue;
 
        blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
+       if (hba->quirks & UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE)
+               blk_queue_update_dma_alignment(q, PAGE_SIZE - 1);
 
        if (ufshcd_is_rpm_autosuspend_allowed(hba))
                sdev->rpm_autosuspend = 1;
index 6c62a28..812aa34 100644 (file)
@@ -544,6 +544,16 @@ enum ufshcd_quirks {
         */
        UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL          = 1 << 12,
 
+       /*
+        * This quirk needs to disable unipro timeout values
+        * before power mode change
+        */
+       UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING = 1 << 13,
+
+       /*
+        * This quirk allows only sg entries aligned with page size.
+        */
+       UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE            = 1 << 14,
 };
 
 enum ufshcd_caps {
index 039ab5d..6eeb7ed 100644 (file)
@@ -569,7 +569,8 @@ static int cdns3_probe(struct platform_device *pdev)
        device_set_wakeup_capable(dev, true);
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
-       pm_runtime_forbid(dev);
+       if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)))
+               pm_runtime_forbid(dev);
 
        /*
         * The controller needs less time between bus and controller suspend,
index 8a40d53..3176f92 100644 (file)
@@ -42,6 +42,8 @@ struct cdns3_role_driver {
 struct cdns3_platform_data {
        int (*platform_suspend)(struct device *dev,
                        bool suspend, bool wakeup);
+       unsigned long quirks;
+#define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0)
 };
 
 /**
@@ -73,6 +75,7 @@ struct cdns3_platform_data {
  * @wakeup_pending: wakeup interrupt pending
  * @pdata: platform data from glue layer
  * @lock: spinlock structure
+ * @xhci_plat_data: xhci private data structure pointer
  */
 struct cdns3 {
        struct device                   *dev;
@@ -106,6 +109,7 @@ struct cdns3 {
        bool                            wakeup_pending;
        struct cdns3_platform_data      *pdata;
        spinlock_t                      lock;
+       struct xhci_plat_priv           *xhci_plat_data;
 };
 
 int cdns3_hw_role_switch(struct cdns3 *cdns);
index ae11810..2604171 100644 (file)
@@ -9,9 +9,11 @@
 #ifndef __LINUX_CDNS3_HOST_EXPORT
 #define __LINUX_CDNS3_HOST_EXPORT
 
+struct usb_hcd;
 #ifdef CONFIG_USB_CDNS3_HOST
 
 int cdns3_host_init(struct cdns3 *cdns);
+int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd);
 
 #else
 
@@ -21,6 +23,10 @@ static inline int cdns3_host_init(struct cdns3 *cdns)
 }
 
 static inline void cdns3_host_exit(struct cdns3 *cdns) { }
+static inline int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd)
+{
+       return 0;
+}
 
 #endif /* CONFIG_USB_CDNS3_HOST */
 
index b3e2cb6..1029777 100644 (file)
 #include "drd.h"
 #include "host-export.h"
 #include <linux/usb/hcd.h>
+#include "../host/xhci.h"
+#include "../host/xhci-plat.h"
+
+#define XECP_PORT_CAP_REG      0x8000
+#define XECP_AUX_CTRL_REG1     0x8120
+
+#define CFG_RXDET_P3_EN                BIT(15)
+#define LPM_2_STB_SWITCH_EN    BIT(25)
+
+static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
+       .quirks = XHCI_SKIP_PHY_INIT,
+       .suspend_quirk = xhci_cdns3_suspend_quirk,
+};
 
 static int __cdns3_host_init(struct cdns3 *cdns)
 {
@@ -39,10 +52,25 @@ static int __cdns3_host_init(struct cdns3 *cdns)
                goto err1;
        }
 
+       cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
+                       sizeof(struct xhci_plat_priv), GFP_KERNEL);
+       if (!cdns->xhci_plat_data) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))
+               cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+
+       ret = platform_device_add_data(xhci, cdns->xhci_plat_data,
+                       sizeof(struct xhci_plat_priv));
+       if (ret)
+               goto free_memory;
+
        ret = platform_device_add(xhci);
        if (ret) {
                dev_err(cdns->dev, "failed to register xHCI device\n");
-               goto err1;
+               goto free_memory;
        }
 
        /* Glue needs to access xHCI region register for Power management */
@@ -51,13 +79,43 @@ static int __cdns3_host_init(struct cdns3 *cdns)
                cdns->xhci_regs = hcd->regs;
 
        return 0;
+
+free_memory:
+       kfree(cdns->xhci_plat_data);
 err1:
        platform_device_put(xhci);
        return ret;
 }
 
+int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       u32 value;
+
+       if (pm_runtime_status_suspended(hcd->self.controller))
+               return 0;
+
+       /* set usbcmd.EU3S */
+       value = readl(&xhci->op_regs->command);
+       value |= CMD_PM_INDEX;
+       writel(value, &xhci->op_regs->command);
+
+       if (hcd->regs) {
+               value = readl(hcd->regs + XECP_AUX_CTRL_REG1);
+               value |= CFG_RXDET_P3_EN;
+               writel(value, hcd->regs + XECP_AUX_CTRL_REG1);
+
+               value = readl(hcd->regs + XECP_PORT_CAP_REG);
+               value |= LPM_2_STB_SWITCH_EN;
+               writel(value, hcd->regs + XECP_PORT_CAP_REG);
+       }
+
+       return 0;
+}
+
 static void cdns3_host_exit(struct cdns3 *cdns)
 {
+       kfree(cdns->xhci_plat_data);
        platform_device_unregister(cdns->host_dev);
        cdns->host_dev = NULL;
        cdns3_drd_host_off(cdns);
index 36e0de3..4e2cce5 100644 (file)
@@ -627,7 +627,8 @@ static int btrfs_delayed_inode_reserve_metadata(
         */
        if (!src_rsv || (!trans->bytes_reserved &&
                         src_rsv->type != BTRFS_BLOCK_RSV_DELALLOC)) {
-               ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
+               ret = btrfs_qgroup_reserve_meta(root, num_bytes,
+                                         BTRFS_QGROUP_RSV_META_PREALLOC, true);
                if (ret < 0)
                        return ret;
                ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes,
index 9b3df72..cbeb0cd 100644 (file)
@@ -5798,7 +5798,7 @@ static int btrfs_dirty_inode(struct inode *inode)
                return PTR_ERR(trans);
 
        ret = btrfs_update_inode(trans, root, inode);
-       if (ret && ret == -ENOSPC) {
+       if (ret && (ret == -ENOSPC || ret == -EDQUOT)) {
                /* whoops, lets try again with the full transaction */
                btrfs_end_transaction(trans);
                trans = btrfs_start_transaction(root, 1);
index d504a9a..cd9b1a1 100644 (file)
@@ -3875,8 +3875,8 @@ static int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes,
        return num_bytes;
 }
 
-static int qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
-                               enum btrfs_qgroup_rsv_type type, bool enforce)
+int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
+                             enum btrfs_qgroup_rsv_type type, bool enforce)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        int ret;
@@ -3907,14 +3907,14 @@ int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
 {
        int ret;
 
-       ret = qgroup_reserve_meta(root, num_bytes, type, enforce);
+       ret = btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce);
        if (ret <= 0 && ret != -EDQUOT)
                return ret;
 
        ret = try_flush_qgroup(root);
        if (ret < 0)
                return ret;
-       return qgroup_reserve_meta(root, num_bytes, type, enforce);
+       return btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce);
 }
 
 void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
index 50dea9a..7283e4f 100644 (file)
@@ -361,6 +361,8 @@ int btrfs_qgroup_release_data(struct btrfs_inode *inode, u64 start, u64 len);
 int btrfs_qgroup_free_data(struct btrfs_inode *inode,
                           struct extent_changeset *reserved, u64 start,
                           u64 len);
+int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
+                             enum btrfs_qgroup_rsv_type type, bool enforce);
 int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
                                enum btrfs_qgroup_rsv_type type, bool enforce);
 /* Reserve metadata space for pertrans and prealloc type */
index eec7928..99580c2 100644 (file)
@@ -16,6 +16,8 @@ struct eeprom_93xx46_platform_data {
 #define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ           (1 << 0)
 /* Instructions such as EWEN are (addrlen + 2) in length. */
 #define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH         (1 << 1)
+/* Add extra cycle after address during a read */
+#define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE           BIT(2)
 
        /*
         * optional hooks to control additional logic
index 240dce5..fafc1be 100644 (file)
@@ -50,6 +50,7 @@ struct sysc_regbits {
        s8 emufree_shift;
 };
 
+#define SYSC_QUIRK_GPMC_DEBUG          BIT(26)
 #define SYSC_MODULE_QUIRK_ENA_RESETDONE        BIT(25)
 #define SYSC_MODULE_QUIRK_PRUSS                BIT(24)
 #define SYSC_MODULE_QUIRK_DSS_RESET    BIT(23)
index 3af4cb8..d56db9f 100644 (file)
@@ -439,6 +439,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
        },
        {
                .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
+       {
+               .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"),
                },
index 0f1d845..1d76773 100644 (file)
@@ -48,26 +48,14 @@ static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
 }
 
 static const struct dmi_system_id sof_sdw_quirk_table[] = {
+       /* CometLake devices */
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
-               },
-               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
-                                       SOF_RT711_JD_SRC_JD2 |
-                                       SOF_RT715_DAI_ID_FIX),
-       },
-       {
-               .callback = sof_sdw_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
                },
-               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
-                                       SOF_RT711_JD_SRC_JD2 |
-                                       SOF_RT715_DAI_ID_FIX |
-                                       SOF_SDW_FOUR_SPK),
+               .driver_data = (void *)SOF_SDW_PCH_DMIC,
        },
        {
                .callback = sof_sdw_quirk_cb,
@@ -98,7 +86,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_RT715_DAI_ID_FIX |
                                        SOF_SDW_FOUR_SPK),
        },
-               {
+       {
                .callback = sof_sdw_quirk_cb,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
@@ -108,6 +96,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_RT715_DAI_ID_FIX |
                                        SOF_SDW_FOUR_SPK),
        },
+       /* IceLake devices */
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+               },
+               .driver_data = (void *)SOF_SDW_PCH_DMIC,
+       },
+       /* TigerLake devices */
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
@@ -123,18 +121,23 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
                },
-               .driver_data = (void *)SOF_SDW_PCH_DMIC,
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX),
        },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
                },
-               .driver_data = (void *)SOF_SDW_PCH_DMIC,
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX |
+                                       SOF_SDW_FOUR_SPK),
        },
        {
                .callback = sof_sdw_quirk_cb,
@@ -156,7 +159,34 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_SDW_PCH_DMIC |
                                        SOF_SDW_FOUR_SPK),
        },
-
+       {
+               /*
+                * this entry covers multiple HP SKUs. The family name
+                * does not seem robust enough, so we use a partial
+                * match that ignores the product name suffix
+                * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
+                */
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"),
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_PCH_DMIC |
+                                       SOF_RT711_JD_SRC_JD2),
+       },
+       /* TigerLake-SDCA devices */
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_RT711_JD_SRC_JD2 |
+                                       SOF_RT715_DAI_ID_FIX |
+                                       SOF_SDW_FOUR_SPK),
+       },
        {}
 };
 
index de7ff2d..6708a2c 100644 (file)
@@ -84,7 +84,7 @@ config SND_SOC_SOF_BAYTRAIL
 
 config SND_SOC_SOF_BROADWELL_SUPPORT
        bool "SOF support for Broadwell"
-       depends on SND_SOC_INTEL_HASWELL=n
+       depends on SND_SOC_INTEL_CATPT=n
        help
          This adds support for Sound Open Firmware for Intel(R) platforms
          using the Broadwell processors.
index df036a3..448de77 100644 (file)
@@ -2603,141 +2603,251 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
 }
 
 /*
- * Pioneer DJ DJM-250MK2 and maybe other DJM models
+ * Pioneer DJ DJM Mixers
  *
- * For playback, no duplicate mapping should be set.
- * There are three mixer stereo channels (CH1, CH2, AUX)
- * and three stereo sources (Playback 1-2, Playback 3-4, Playback 5-6).
- * Each channel should be mapped just once to one source.
- * If mapped multiple times, only one source will play on given channel
- * (sources are not mixed together).
+ * These devices generally have options for soft-switching the playback and
+ * capture sources in addition to the recording level. Although different
+ * devices have different configurations, there seems to be canonical values
+ * for specific capture/playback types:  See the definitions of these below.
  *
- * For recording, duplicate mapping is OK. We will get the same signal multiple times.
- *
- * Channels 7-8 are in both directions fixed to FX SEND / FX RETURN.
- *
- * See also notes in the quirks-table.h file.
+ * The wValue is masked with the stereo channel number. e.g. Setting Ch2 to
+ * capture phono would be 0x0203. Capture, playback and capture level have
+ * different wIndexes.
  */
 
-struct snd_pioneer_djm_option {
-       const u16 wIndex;
-       const u16 wValue;
+// Capture types
+#define SND_DJM_CAP_LINE       0x00
+#define SND_DJM_CAP_CDLINE     0x01
+#define SND_DJM_CAP_DIGITAL    0x02
+#define SND_DJM_CAP_PHONO      0x03
+#define SND_DJM_CAP_PFADER     0x06
+#define SND_DJM_CAP_XFADERA    0x07
+#define SND_DJM_CAP_XFADERB    0x08
+#define SND_DJM_CAP_MIC                0x09
+#define SND_DJM_CAP_AUX                0x0d
+#define SND_DJM_CAP_RECOUT     0x0a
+#define SND_DJM_CAP_NONE       0x0f
+#define SND_DJM_CAP_CH1PFADER  0x11
+#define SND_DJM_CAP_CH2PFADER  0x12
+#define SND_DJM_CAP_CH3PFADER  0x13
+#define SND_DJM_CAP_CH4PFADER  0x14
+
+// Playback types
+#define SND_DJM_PB_CH1         0x00
+#define SND_DJM_PB_CH2         0x01
+#define SND_DJM_PB_AUX         0x04
+
+#define SND_DJM_WINDEX_CAP     0x8002
+#define SND_DJM_WINDEX_CAPLVL  0x8003
+#define SND_DJM_WINDEX_PB      0x8016
+
+// kcontrol->private_value layout
+#define SND_DJM_VALUE_MASK     0x0000ffff
+#define SND_DJM_GROUP_MASK     0x00ff0000
+#define SND_DJM_DEVICE_MASK    0xff000000
+#define SND_DJM_GROUP_SHIFT    16
+#define SND_DJM_DEVICE_SHIFT   24
+
+// device table index
+#define SND_DJM_250MK2_IDX     0x0
+#define SND_DJM_750_IDX                0x1
+#define SND_DJM_900NXS2_IDX    0x2
+
+
+#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
+       .name = _name, \
+       .options = snd_djm_opts_##suffix, \
+       .noptions = ARRAY_SIZE(snd_djm_opts_##suffix), \
+       .default_value = _default_value, \
+       .wIndex = _windex }
+
+#define SND_DJM_DEVICE(suffix) { \
+       .controls = snd_djm_ctls_##suffix, \
+       .ncontrols = ARRAY_SIZE(snd_djm_ctls_##suffix) }
+
+
+struct snd_djm_device {
        const char *name;
+       const struct snd_djm_ctl *controls;
+       size_t ncontrols;
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_level[] = {
-       { .name =  "-5 dB",                  .wValue = 0x0300, .wIndex = 0x8003 },
-       { .name = "-10 dB",                  .wValue = 0x0200, .wIndex = 0x8003 },
-       { .name = "-15 dB",                  .wValue = 0x0100, .wIndex = 0x8003 },
-       { .name = "-19 dB",                  .wValue = 0x0000, .wIndex = 0x8003 }
+struct snd_djm_ctl {
+       const char *name;
+       const u16 *options;
+       size_t noptions;
+       u16 default_value;
+       u16 wIndex;
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch12[] = {
-       { .name =  "CH1 Control Tone PHONO", .wValue = 0x0103, .wIndex = 0x8002 },
-       { .name =  "CH1 Control Tone LINE",  .wValue = 0x0100, .wIndex = 0x8002 },
-       { .name =  "Post CH1 Fader",         .wValue = 0x0106, .wIndex = 0x8002 },
-       { .name =  "Cross Fader A",          .wValue = 0x0107, .wIndex = 0x8002 },
-       { .name =  "Cross Fader B",          .wValue = 0x0108, .wIndex = 0x8002 },
-       { .name =  "MIC",                    .wValue = 0x0109, .wIndex = 0x8002 },
-       { .name =  "AUX",                    .wValue = 0x010d, .wIndex = 0x8002 },
-       { .name =  "REC OUT",                .wValue = 0x010a, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_caplevel(u16 wvalue)
+{
+       switch (wvalue) {
+       case 0x0000:    return "-19dB";
+       case 0x0100:    return "-15dB";
+       case 0x0200:    return "-10dB";
+       case 0x0300:    return "-5dB";
+       default:        return NULL;
+       }
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch34[] = {
-       { .name =  "CH2 Control Tone PHONO", .wValue = 0x0203, .wIndex = 0x8002 },
-       { .name =  "CH2 Control Tone LINE",  .wValue = 0x0200, .wIndex = 0x8002 },
-       { .name =  "Post CH2 Fader",         .wValue = 0x0206, .wIndex = 0x8002 },
-       { .name =  "Cross Fader A",          .wValue = 0x0207, .wIndex = 0x8002 },
-       { .name =  "Cross Fader B",          .wValue = 0x0208, .wIndex = 0x8002 },
-       { .name =  "MIC",                    .wValue = 0x0209, .wIndex = 0x8002 },
-       { .name =  "AUX",                    .wValue = 0x020d, .wIndex = 0x8002 },
-       { .name =  "REC OUT",                .wValue = 0x020a, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_cap(u16 wvalue)
+{
+       switch (wvalue & 0x00ff) {
+       case SND_DJM_CAP_LINE:          return "Control Tone LINE";
+       case SND_DJM_CAP_CDLINE:        return "Control Tone CD/LINE";
+       case SND_DJM_CAP_DIGITAL:       return "Control Tone DIGITAL";
+       case SND_DJM_CAP_PHONO:         return "Control Tone PHONO";
+       case SND_DJM_CAP_PFADER:        return "Post Fader";
+       case SND_DJM_CAP_XFADERA:       return "Cross Fader A";
+       case SND_DJM_CAP_XFADERB:       return "Cross Fader B";
+       case SND_DJM_CAP_MIC:           return "Mic";
+       case SND_DJM_CAP_RECOUT:        return "Rec Out";
+       case SND_DJM_CAP_AUX:           return "Aux";
+       case SND_DJM_CAP_NONE:          return "None";
+       case SND_DJM_CAP_CH1PFADER:     return "Post Fader Ch1";
+       case SND_DJM_CAP_CH2PFADER:     return "Post Fader Ch2";
+       case SND_DJM_CAP_CH3PFADER:     return "Post Fader Ch3";
+       case SND_DJM_CAP_CH4PFADER:     return "Post Fader Ch4";
+       default:                        return NULL;
+       }
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch56[] = {
-       { .name =  "REC OUT",                .wValue = 0x030a, .wIndex = 0x8002 },
-       { .name =  "Post CH1 Fader",         .wValue = 0x0311, .wIndex = 0x8002 },
-       { .name =  "Post CH2 Fader",         .wValue = 0x0312, .wIndex = 0x8002 },
-       { .name =  "Cross Fader A",          .wValue = 0x0307, .wIndex = 0x8002 },
-       { .name =  "Cross Fader B",          .wValue = 0x0308, .wIndex = 0x8002 },
-       { .name =  "MIC",                    .wValue = 0x0309, .wIndex = 0x8002 },
-       { .name =  "AUX",                    .wValue = 0x030d, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_pb(u16 wvalue)
+{
+       switch (wvalue & 0x00ff) {
+       case SND_DJM_PB_CH1:    return "Ch1";
+       case SND_DJM_PB_CH2:    return "Ch2";
+       case SND_DJM_PB_AUX:    return "Aux";
+       default:                return NULL;
+       }
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_12[] = {
-       { .name =  "CH1",                    .wValue = 0x0100, .wIndex = 0x8016 },
-       { .name =  "CH2",                    .wValue = 0x0101, .wIndex = 0x8016 },
-       { .name =  "AUX",                    .wValue = 0x0104, .wIndex = 0x8016 }
+static const char *snd_djm_get_label(u16 wvalue, u16 windex)
+{
+       switch (windex) {
+       case SND_DJM_WINDEX_CAPLVL:     return snd_djm_get_label_caplevel(wvalue);
+       case SND_DJM_WINDEX_CAP:        return snd_djm_get_label_cap(wvalue);
+       case SND_DJM_WINDEX_PB:         return snd_djm_get_label_pb(wvalue);
+       default:                        return NULL;
+       }
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_34[] = {
-       { .name =  "CH1",                    .wValue = 0x0200, .wIndex = 0x8016 },
-       { .name =  "CH2",                    .wValue = 0x0201, .wIndex = 0x8016 },
-       { .name =  "AUX",                    .wValue = 0x0204, .wIndex = 0x8016 }
+
+// DJM-250MK2
+static const u16 snd_djm_opts_cap_level[] = {
+       0x0000, 0x0100, 0x0200, 0x0300 };
+
+static const u16 snd_djm_opts_250mk2_cap1[] = {
+       0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a };
+
+static const u16 snd_djm_opts_250mk2_cap2[] = {
+       0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a };
+
+static const u16 snd_djm_opts_250mk2_cap3[] = {
+       0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d };
+
+static const u16 snd_djm_opts_250mk2_pb1[] = { 0x0100, 0x0101, 0x0104 };
+static const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 };
+static const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 };
+
+static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = {
+       SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+       SND_DJM_CTL("Ch1 Input",   250mk2_cap1, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch2 Input",   250mk2_cap2, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch3 Input",   250mk2_cap3, 0, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch1 Output",   250mk2_pb1, 0, SND_DJM_WINDEX_PB),
+       SND_DJM_CTL("Ch2 Output",   250mk2_pb2, 1, SND_DJM_WINDEX_PB),
+       SND_DJM_CTL("Ch3 Output",   250mk2_pb3, 2, SND_DJM_WINDEX_PB)
 };
 
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_56[] = {
-       { .name =  "CH1",                    .wValue = 0x0300, .wIndex = 0x8016 },
-       { .name =  "CH2",                    .wValue = 0x0301, .wIndex = 0x8016 },
-       { .name =  "AUX",                    .wValue = 0x0304, .wIndex = 0x8016 }
+
+// DJM-750
+static const u16 snd_djm_opts_750_cap1[] = {
+       0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f };
+static const u16 snd_djm_opts_750_cap2[] = {
+       0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f };
+static const u16 snd_djm_opts_750_cap3[] = {
+       0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f };
+static const u16 snd_djm_opts_750_cap4[] = {
+       0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f };
+
+static const struct snd_djm_ctl snd_djm_ctls_750[] = {
+       SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+       SND_DJM_CTL("Ch1 Input",   750_cap1, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch2 Input",   750_cap2, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch3 Input",   750_cap3, 0, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch4 Input",   750_cap4, 0, SND_DJM_WINDEX_CAP)
 };
 
-struct snd_pioneer_djm_option_group {
-       const char *name;
-       const struct snd_pioneer_djm_option *options;
-       const size_t count;
-       const u16 default_value;
+
+// DJM-900NXS2
+static const u16 snd_djm_opts_900nxs2_cap1[] = {
+       0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a };
+static const u16 snd_djm_opts_900nxs2_cap2[] = {
+       0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a };
+static const u16 snd_djm_opts_900nxs2_cap3[] = {
+       0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a };
+static const u16 snd_djm_opts_900nxs2_cap4[] = {
+       0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a };
+static const u16 snd_djm_opts_900nxs2_cap5[] = {
+       0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 };
+
+static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = {
+       SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+       SND_DJM_CTL("Ch1 Input",   900nxs2_cap1, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch2 Input",   900nxs2_cap2, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch3 Input",   900nxs2_cap3, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch4 Input",   900nxs2_cap4, 2, SND_DJM_WINDEX_CAP),
+       SND_DJM_CTL("Ch5 Input",   900nxs2_cap5, 3, SND_DJM_WINDEX_CAP)
 };
 
-#define snd_pioneer_djm_option_group_item(_name, suffix, _default_value) { \
-       .name = _name, \
-       .options = snd_pioneer_djm_options_##suffix, \
-       .count = ARRAY_SIZE(snd_pioneer_djm_options_##suffix), \
-       .default_value = _default_value }
-
-static const struct snd_pioneer_djm_option_group snd_pioneer_djm_option_groups[] = {
-       snd_pioneer_djm_option_group_item("Master Capture Level Capture Switch", capture_level, 0),
-       snd_pioneer_djm_option_group_item("Capture 1-2 Capture Switch",          capture_ch12,  2),
-       snd_pioneer_djm_option_group_item("Capture 3-4 Capture Switch",          capture_ch34,  2),
-       snd_pioneer_djm_option_group_item("Capture 5-6 Capture Switch",          capture_ch56,  0),
-       snd_pioneer_djm_option_group_item("Playback 1-2 Playback Switch",        playback_12,   0),
-       snd_pioneer_djm_option_group_item("Playback 3-4 Playback Switch",        playback_34,   1),
-       snd_pioneer_djm_option_group_item("Playback 5-6 Playback Switch",        playback_56,   2)
+
+static const struct snd_djm_device snd_djm_devices[] = {
+       SND_DJM_DEVICE(250mk2),
+       SND_DJM_DEVICE(750),
+       SND_DJM_DEVICE(900nxs2)
 };
 
-// layout of the kcontrol->private_value:
-#define SND_PIONEER_DJM_VALUE_MASK 0x0000ffff
-#define SND_PIONEER_DJM_GROUP_MASK 0xffff0000
-#define SND_PIONEER_DJM_GROUP_SHIFT 16
 
-static int snd_pioneer_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info)
+static int snd_djm_controls_info(struct snd_kcontrol *kctl,
+                               struct snd_ctl_elem_info *info)
 {
-       u16 group_index = kctl->private_value >> SND_PIONEER_DJM_GROUP_SHIFT;
-       size_t count;
+       unsigned long private_value = kctl->private_value;
+       u8 device_idx = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+       u8 ctl_idx = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
+       const struct snd_djm_device *device = &snd_djm_devices[device_idx];
        const char *name;
-       const struct snd_pioneer_djm_option_group *group;
+       const struct snd_djm_ctl *ctl;
+       size_t noptions;
 
-       if (group_index >= ARRAY_SIZE(snd_pioneer_djm_option_groups))
+       if (ctl_idx >= device->ncontrols)
+               return -EINVAL;
+
+       ctl = &device->controls[ctl_idx];
+       noptions = ctl->noptions;
+       if (info->value.enumerated.item >= noptions)
+               info->value.enumerated.item = noptions - 1;
+
+       name = snd_djm_get_label(ctl->options[info->value.enumerated.item],
+                               ctl->wIndex);
+       if (!name)
                return -EINVAL;
 
-       group = &snd_pioneer_djm_option_groups[group_index];
-       count = group->count;
-       if (info->value.enumerated.item >= count)
-               info->value.enumerated.item = count - 1;
-       name = group->options[info->value.enumerated.item].name;
        strlcpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
        info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        info->count = 1;
-       info->value.enumerated.items = count;
+       info->value.enumerated.items = noptions;
        return 0;
 }
 
-static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u16 group, u16 value)
+static int snd_djm_controls_update(struct usb_mixer_interface *mixer,
+                               u8 device_idx, u8 group, u16 value)
 {
        int err;
+       const struct snd_djm_device *device = &snd_djm_devices[device_idx];
 
-       if (group >= ARRAY_SIZE(snd_pioneer_djm_option_groups)
-                       || value >= snd_pioneer_djm_option_groups[group].count)
+       if ((group >= device->ncontrols) || value >= device->controls[group].noptions)
                return -EINVAL;
 
        err = snd_usb_lock_shutdown(mixer->chip);
@@ -2748,63 +2858,76 @@ static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u1
                mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0),
                USB_REQ_SET_FEATURE,
                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               snd_pioneer_djm_option_groups[group].options[value].wValue,
-               snd_pioneer_djm_option_groups[group].options[value].wIndex,
+               device->controls[group].options[value],
+               device->controls[group].wIndex,
                NULL, 0);
 
        snd_usb_unlock_shutdown(mixer->chip);
        return err;
 }
 
-static int snd_pioneer_djm_controls_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
+static int snd_djm_controls_get(struct snd_kcontrol *kctl,
+                               struct snd_ctl_elem_value *elem)
 {
-       elem->value.enumerated.item[0] = kctl->private_value & SND_PIONEER_DJM_VALUE_MASK;
+       elem->value.enumerated.item[0] = kctl->private_value & SND_DJM_VALUE_MASK;
        return 0;
 }
 
-static int snd_pioneer_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
+static int snd_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
 {
        struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
        struct usb_mixer_interface *mixer = list->mixer;
        unsigned long private_value = kctl->private_value;
-       u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
+
+       u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+       u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
        u16 value = elem->value.enumerated.item[0];
 
-       kctl->private_value = (group << SND_PIONEER_DJM_GROUP_SHIFT) | value;
+       kctl->private_value = ((device << SND_DJM_DEVICE_SHIFT) |
+                             (group << SND_DJM_GROUP_SHIFT) |
+                             value);
 
-       return snd_pioneer_djm_controls_update(mixer, group, value);
+       return snd_djm_controls_update(mixer, device, group, value);
 }
 
-static int snd_pioneer_djm_controls_resume(struct usb_mixer_elem_list *list)
+static int snd_djm_controls_resume(struct usb_mixer_elem_list *list)
 {
        unsigned long private_value = list->kctl->private_value;
-       u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
-       u16 value = (private_value & SND_PIONEER_DJM_VALUE_MASK);
+       u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+       u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
+       u16 value = (private_value & SND_DJM_VALUE_MASK);
 
-       return snd_pioneer_djm_controls_update(list->mixer, group, value);
+       return snd_djm_controls_update(list->mixer, device, group, value);
 }
 
-static int snd_pioneer_djm_controls_create(struct usb_mixer_interface *mixer)
+static int snd_djm_controls_create(struct usb_mixer_interface *mixer,
+               const u8 device_idx)
 {
        int err, i;
-       const struct snd_pioneer_djm_option_group *group;
+       u16 value;
+
+       const struct snd_djm_device *device = &snd_djm_devices[device_idx];
+
        struct snd_kcontrol_new knew = {
                .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
                .index = 0,
-               .info = snd_pioneer_djm_controls_info,
-               .get  = snd_pioneer_djm_controls_get,
-               .put  = snd_pioneer_djm_controls_put
+               .info = snd_djm_controls_info,
+               .get  = snd_djm_controls_get,
+               .put  = snd_djm_controls_put
        };
 
-       for (i = 0; i < ARRAY_SIZE(snd_pioneer_djm_option_groups); i++) {
-               group = &snd_pioneer_djm_option_groups[i];
-               knew.name = group->name;
-               knew.private_value = (i << SND_PIONEER_DJM_GROUP_SHIFT) | group->default_value;
-               err = snd_pioneer_djm_controls_update(mixer, i, group->default_value);
+       for (i = 0; i < device->ncontrols; i++) {
+               value = device->controls[i].default_value;
+               knew.name = device->controls[i].name;
+               knew.private_value = (
+                       (device_idx << SND_DJM_DEVICE_SHIFT) |
+                       (i << SND_DJM_GROUP_SHIFT) |
+                       value);
+               err = snd_djm_controls_update(mixer, device_idx, i, value);
                if (err)
                        return err;
-               err = add_single_ctl_with_resume(mixer, 0, snd_pioneer_djm_controls_resume,
+               err = add_single_ctl_with_resume(mixer, 0, snd_djm_controls_resume,
                                                 &knew, NULL);
                if (err)
                        return err;
@@ -2917,7 +3040,13 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
                err = snd_bbfpro_controls_create(mixer);
                break;
        case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
-               err = snd_pioneer_djm_controls_create(mixer);
+               err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
+               break;
+       case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */
+               err = snd_djm_controls_create(mixer, SND_DJM_750_IDX);
+               break;
+       case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
+               err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX);
                break;
        }