mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
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>
This commit is contained in:
parent
40384c840e
commit
7f0fa47cee
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user