Commit 7f0fa47c authored by Hans de Goede's avatar Hans de Goede Committed by Ulf Hansson
Browse files

mmc: sdhci-pci: Add DMI quirk for missing CD GPIO on Vexia Edu Atla 10 tablet



The Vexia Edu Atla 10 tablet distributed to schools in the Spanish
Andalucía region has no ACPI fwnode associated with the SDHCI controller
for its microsd-slot and thus has no ACPI GPIO resource info.

This causes the following error to be logged and the slot to not work:
[   10.572113] sdhci-pci 0000:00:12.0: failed to setup card detect gpio

Add a DMI quirk table for providing gpiod_lookup_tables with manually
provided CD GPIO info and use this DMI table to provide the CD GPIO info
on this tablet. This fixes the microsd-slot not working.

Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
Message-ID: <20241118210049.311079-1-hdegoede@redhat.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 40384c84
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/debugfs.h>
@@ -1236,6 +1237,29 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
	.priv_size	= sizeof(struct intel_host),
};

/* DMI quirks for devices with missing or broken CD GPIO info */
static const struct gpiod_lookup_table vexia_edu_atla10_cd_gpios = {
	.dev_id = "0000:00:12.0",
	.table = {
		GPIO_LOOKUP("INT33FC:00", 38, "cd", GPIO_ACTIVE_HIGH),
		{ }
	},
};

static const struct dmi_system_id sdhci_intel_byt_cd_gpio_override[] = {
	{
		/* Vexia Edu Atla 10 tablet 9V version */
		.matches = {
			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
			DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
			/* Above strings are too generic, also match on BIOS date */
			DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
		},
		.driver_data = (void *)&vexia_edu_atla10_cd_gpios,
	},
	{ }
};

static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
#ifdef CONFIG_PM_SLEEP
	.resume		= byt_resume,
@@ -1254,6 +1278,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
	.add_host	= byt_add_host,
	.remove_slot	= byt_remove_slot,
	.ops		= &sdhci_intel_byt_ops,
	.cd_gpio_override = sdhci_intel_byt_cd_gpio_override,
	.priv_size	= sizeof(struct intel_host),
};

@@ -2055,6 +2080,42 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
 *                                                                           *
\*****************************************************************************/

static struct gpiod_lookup_table *sdhci_pci_add_gpio_lookup_table(
	struct sdhci_pci_chip *chip)
{
	struct gpiod_lookup_table *cd_gpio_lookup_table;
	const struct dmi_system_id *dmi_id = NULL;
	size_t count;

	if (chip->fixes && chip->fixes->cd_gpio_override)
		dmi_id = dmi_first_match(chip->fixes->cd_gpio_override);

	if (!dmi_id)
		return NULL;

	cd_gpio_lookup_table = dmi_id->driver_data;
	for (count = 0; cd_gpio_lookup_table->table[count].key; count++)
		;

	cd_gpio_lookup_table = kmemdup(dmi_id->driver_data,
				       /* count + 1 terminating entry */
				       struct_size(cd_gpio_lookup_table, table, count + 1),
				       GFP_KERNEL);
	if (!cd_gpio_lookup_table)
		return ERR_PTR(-ENOMEM);

	gpiod_add_lookup_table(cd_gpio_lookup_table);
	return cd_gpio_lookup_table;
}

static void sdhci_pci_remove_gpio_lookup_table(struct gpiod_lookup_table *lookup_table)
{
	if (lookup_table) {
		gpiod_remove_lookup_table(lookup_table);
		kfree(lookup_table);
	}
}

static struct sdhci_pci_slot *sdhci_pci_probe_slot(
	struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
	int slotno)
@@ -2130,8 +2191,19 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
		device_init_wakeup(&pdev->dev, true);

	if (slot->cd_idx >= 0) {
		struct gpiod_lookup_table *cd_gpio_lookup_table;

		cd_gpio_lookup_table = sdhci_pci_add_gpio_lookup_table(chip);
		if (IS_ERR(cd_gpio_lookup_table)) {
			ret = PTR_ERR(cd_gpio_lookup_table);
			goto remove;
		}

		ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx,
					   slot->cd_override_level, 0);

		sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table);

		if (ret && ret != -EPROBE_DEFER)
			ret = mmc_gpiod_request_cd(host->mmc, NULL,
						   slot->cd_idx,
+1 −0
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ struct sdhci_pci_fixes {
#endif

	const struct sdhci_ops	*ops;
	const struct dmi_system_id *cd_gpio_override;
	size_t			priv_size;
};