| @@ -21,6 +21,7 @@ · 20 unmodified lines |
| 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> |
| @@ -1236,6 +1237,29 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { · 1209 unmodified lines |
| 1236 | 1237 | .priv_size = sizeof(struct intel_host), |
| 1237 | 1238 | }; |
| 1238 | 1239 | |
| 1240 | +/* DMI quirks for devices with missing or broken CD GPIO info */ |
| 1241 | +static const struct gpiod_lookup_table vexia_edu_atla10_cd_gpios = { |
| 1242 | + .dev_id = "0000:00:12.0", |
| 1243 | + .table = { |
| 1244 | + GPIO_LOOKUP("INT33FC:00", 38, "cd", GPIO_ACTIVE_HIGH), |
| 1245 | + { } |
| 1246 | + }, |
| 1247 | +}; |
| 1248 | + |
| 1249 | +static const struct dmi_system_id sdhci_intel_byt_cd_gpio_override[] = { |
| 1250 | + { |
| 1251 | + /* Vexia Edu Atla 10 tablet 9V version */ |
| 1252 | + .matches = { |
| 1253 | + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), |
| 1254 | + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), |
| 1255 | + /* Above strings are too generic, also match on BIOS date */ |
| 1256 | + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), |
| 1257 | + }, |
| 1258 | + .driver_data = (void *)&vexia_edu_atla10_cd_gpios, |
| 1259 | + }, |
| 1260 | + { } |
| 1261 | +}; |
| 1262 | + |
| 1239 | 1263 | static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { |
| 1240 | 1264 | #ifdef CONFIG_PM_SLEEP |
| 1241 | 1265 | .resume = byt_resume, |
| @@ -1254,6 +1278,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { · 12 unmodified lines |
| 1254 | 1278 | .add_host = byt_add_host, |
| 1255 | 1279 | .remove_slot = byt_remove_slot, |
| 1256 | 1280 | .ops = &sdhci_intel_byt_ops, |
| 1281 | + .cd_gpio_override = sdhci_intel_byt_cd_gpio_override, |
| 1257 | 1282 | .priv_size = sizeof(struct intel_host), |
| 1258 | 1283 | }; |
| 1259 | 1284 | |
| @@ -2055,6 +2080,42 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { · 795 unmodified lines |
| 2055 | 2080 | * * |
| 2056 | 2081 | \*****************************************************************************/ |
| 2057 | 2082 | |
| 2083 | +static struct gpiod_lookup_table *sdhci_pci_add_gpio_lookup_table( |
| 2084 | + struct sdhci_pci_chip *chip) |
| 2085 | +{ |
| 2086 | + struct gpiod_lookup_table *cd_gpio_lookup_table; |
| 2087 | + const struct dmi_system_id *dmi_id = NULL; |
| 2088 | + size_t count; |
| 2089 | + |
| 2090 | + if (chip->fixes && chip->fixes->cd_gpio_override) |
| 2091 | + dmi_id = dmi_first_match(chip->fixes->cd_gpio_override); |
| 2092 | + |
| 2093 | + if (!dmi_id) |
| 2094 | + return NULL; |
| 2095 | + |
| 2096 | + cd_gpio_lookup_table = dmi_id->driver_data; |
| 2097 | + for (count = 0; cd_gpio_lookup_table->table[count].key; count++) |
| 2098 | + ; |
| 2099 | + |
| 2100 | + cd_gpio_lookup_table = kmemdup(dmi_id->driver_data, |
| 2101 | + /* count + 1 terminating entry */ |
| 2102 | + struct_size(cd_gpio_lookup_table, table, count + 1), |
| 2103 | + GFP_KERNEL); |
| 2104 | + if (!cd_gpio_lookup_table) |
| 2105 | + return ERR_PTR(-ENOMEM); |
| 2106 | + |
| 2107 | + gpiod_add_lookup_table(cd_gpio_lookup_table); |
| 2108 | + return cd_gpio_lookup_table; |
| 2109 | +} |
| 2110 | + |
| 2111 | +static void sdhci_pci_remove_gpio_lookup_table(struct gpiod_lookup_table *lookup_table) |
| 2112 | +{ |
| 2113 | + if (lookup_table) { |
| 2114 | + gpiod_remove_lookup_table(lookup_table); |
| 2115 | + kfree(lookup_table); |
| 2116 | + } |
| 2117 | +} |
| 2118 | + |
| 2058 | 2119 | static struct sdhci_pci_slot *sdhci_pci_probe_slot( |
| 2059 | 2120 | struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, |
| 2060 | 2121 | int slotno) |
| @@ -2130,8 +2191,19 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( · 69 unmodified lines |
| 2130 | 2191 | device_init_wakeup(&pdev->dev, true); |
| 2131 | 2192 | |
| 2132 | 2193 | if (slot->cd_idx >= 0) { |
| 2194 | + struct gpiod_lookup_table *cd_gpio_lookup_table; |
| 2195 | + |
| 2196 | + cd_gpio_lookup_table = sdhci_pci_add_gpio_lookup_table(chip); |
| 2197 | + if (IS_ERR(cd_gpio_lookup_table)) { |
| 2198 | + ret = PTR_ERR(cd_gpio_lookup_table); |
| 2199 | + goto remove; |
| 2200 | + } |
| 2201 | + |
| 2133 | 2202 | ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, |
| 2134 | 2203 | slot->cd_override_level, 0); |
| 2204 | + |
| 2205 | + sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table); |
| 2206 | + |
| 2135 | 2207 | if (ret && ret != -EPROBE_DEFER) |
| 2136 | 2208 | ret = mmc_gpiod_request_cd(host->mmc, NULL, |
| 2137 | 2209 | slot->cd_idx, |