Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Hans de Goede <hdegoede@redhat.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
Message-ID: <20241118210049.311079-1-hdegoede@redhat.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Hans de Goede and committed by
Ulf Hansson
7f0fa47c 40384c84

+73
+72
drivers/mmc/host/sdhci-pci-core.c
··· 21 21 #include <linux/io.h> 22 22 #include <linux/iopoll.h> 23 23 #include <linux/gpio.h> 24 + #include <linux/gpio/machine.h> 24 25 #include <linux/pm_runtime.h> 25 26 #include <linux/pm_qos.h> 26 27 #include <linux/debugfs.h> ··· 1237 1236 .priv_size = sizeof(struct intel_host), 1238 1237 }; 1239 1238 1239 + /* DMI quirks for devices with missing or broken CD GPIO info */ 1240 + static const struct gpiod_lookup_table vexia_edu_atla10_cd_gpios = { 1241 + .dev_id = "0000:00:12.0", 1242 + .table = { 1243 + GPIO_LOOKUP("INT33FC:00", 38, "cd", GPIO_ACTIVE_HIGH), 1244 + { } 1245 + }, 1246 + }; 1247 + 1248 + static const struct dmi_system_id sdhci_intel_byt_cd_gpio_override[] = { 1249 + { 1250 + /* Vexia Edu Atla 10 tablet 9V version */ 1251 + .matches = { 1252 + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 1253 + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), 1254 + /* Above strings are too generic, also match on BIOS date */ 1255 + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), 1256 + }, 1257 + .driver_data = (void *)&vexia_edu_atla10_cd_gpios, 1258 + }, 1259 + { } 1260 + }; 1261 + 1240 1262 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { 1241 1263 #ifdef CONFIG_PM_SLEEP 1242 1264 .resume = byt_resume, ··· 1278 1254 .add_host = byt_add_host, 1279 1255 .remove_slot = byt_remove_slot, 1280 1256 .ops = &sdhci_intel_byt_ops, 1257 + .cd_gpio_override = sdhci_intel_byt_cd_gpio_override, 1281 1258 .priv_size = sizeof(struct intel_host), 1282 1259 }; 1283 1260 ··· 2080 2055 * * 2081 2056 \*****************************************************************************/ 2082 2057 2058 + static struct gpiod_lookup_table *sdhci_pci_add_gpio_lookup_table( 2059 + struct sdhci_pci_chip *chip) 2060 + { 2061 + struct gpiod_lookup_table *cd_gpio_lookup_table; 2062 + const struct dmi_system_id *dmi_id = NULL; 2063 + size_t count; 2064 + 2065 + if (chip->fixes && chip->fixes->cd_gpio_override) 2066 + dmi_id = dmi_first_match(chip->fixes->cd_gpio_override); 2067 + 2068 + if (!dmi_id) 2069 + return NULL; 2070 + 2071 + cd_gpio_lookup_table = dmi_id->driver_data; 2072 + for (count = 0; cd_gpio_lookup_table->table[count].key; count++) 2073 + ; 2074 + 2075 + cd_gpio_lookup_table = kmemdup(dmi_id->driver_data, 2076 + /* count + 1 terminating entry */ 2077 + struct_size(cd_gpio_lookup_table, table, count + 1), 2078 + GFP_KERNEL); 2079 + if (!cd_gpio_lookup_table) 2080 + return ERR_PTR(-ENOMEM); 2081 + 2082 + gpiod_add_lookup_table(cd_gpio_lookup_table); 2083 + return cd_gpio_lookup_table; 2084 + } 2085 + 2086 + static void sdhci_pci_remove_gpio_lookup_table(struct gpiod_lookup_table *lookup_table) 2087 + { 2088 + if (lookup_table) { 2089 + gpiod_remove_lookup_table(lookup_table); 2090 + kfree(lookup_table); 2091 + } 2092 + } 2093 + 2083 2094 static struct sdhci_pci_slot *sdhci_pci_probe_slot( 2084 2095 struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, 2085 2096 int slotno) ··· 2191 2130 device_init_wakeup(&pdev->dev, true); 2192 2131 2193 2132 if (slot->cd_idx >= 0) { 2133 + struct gpiod_lookup_table *cd_gpio_lookup_table; 2134 + 2135 + cd_gpio_lookup_table = sdhci_pci_add_gpio_lookup_table(chip); 2136 + if (IS_ERR(cd_gpio_lookup_table)) { 2137 + ret = PTR_ERR(cd_gpio_lookup_table); 2138 + goto remove; 2139 + } 2140 + 2194 2141 ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, 2195 2142 slot->cd_override_level, 0); 2143 + 2144 + sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table); 2145 + 2196 2146 if (ret && ret != -EPROBE_DEFER) 2197 2147 ret = mmc_gpiod_request_cd(host->mmc, NULL, 2198 2148 slot->cd_idx,
+1
drivers/mmc/host/sdhci-pci.h
··· 157 157 #endif 158 158 159 159 const struct sdhci_ops *ops; 160 + const struct dmi_system_id *cd_gpio_override; 160 161 size_t priv_size; 161 162 }; 162 163