|
@@ -176,6 +176,74 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
|
|
|
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
|
|
|
};
|
|
|
|
|
|
+/* O2Micro extra registers */
|
|
|
+#define O2_SD_LOCK_WP 0xD3
|
|
|
+#define O2_SD_MULTI_VCC3V 0xEE
|
|
|
+#define O2_SD_CLKREQ 0xEC
|
|
|
+#define O2_SD_CAPS 0xE0
|
|
|
+#define O2_SD_ADMA1 0xE2
|
|
|
+#define O2_SD_ADMA2 0xE7
|
|
|
+#define O2_SD_INF_MOD 0xF1
|
|
|
+
|
|
|
+static int o2_probe(struct sdhci_pci_chip *chip)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ u8 scratch;
|
|
|
+
|
|
|
+ switch (chip->pdev->device) {
|
|
|
+ case PCI_DEVICE_ID_O2_8220:
|
|
|
+ case PCI_DEVICE_ID_O2_8221:
|
|
|
+ case PCI_DEVICE_ID_O2_8320:
|
|
|
+ case PCI_DEVICE_ID_O2_8321:
|
|
|
+ /* This extra setup is required due to broken ADMA. */
|
|
|
+ ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ scratch &= 0x7f;
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
|
|
|
+
|
|
|
+ /* Set Multi 3 to VCC3V# */
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
|
|
|
+
|
|
|
+ /* Disable CLK_REQ# support after media DET */
|
|
|
+ ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ scratch |= 0x20;
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
|
|
|
+
|
|
|
+ /* Choose capabilities, enable SDMA. We have to write 0x01
|
|
|
+ * to the capabilities register first to unlock it.
|
|
|
+ */
|
|
|
+ ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ scratch |= 0x01;
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
|
|
|
+
|
|
|
+ /* Disable ADMA1/2 */
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
|
|
|
+
|
|
|
+ /* Disable the infinite transfer mode */
|
|
|
+ ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ scratch |= 0x08;
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
|
|
|
+
|
|
|
+ /* Lock WP */
|
|
|
+ ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ scratch |= 0x80;
|
|
|
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
|
|
|
{
|
|
|
u8 scratch;
|
|
@@ -339,6 +407,10 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static const struct sdhci_pci_fixes sdhci_o2 = {
|
|
|
+ .probe = o2_probe,
|
|
|
+};
|
|
|
+
|
|
|
static const struct sdhci_pci_fixes sdhci_jmicron = {
|
|
|
.probe = jmicron_probe,
|
|
|
|
|
@@ -589,6 +661,46 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
|
|
|
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
|
|
|
},
|
|
|
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_O2,
|
|
|
+ .device = PCI_DEVICE_ID_O2_8120,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_O2,
|
|
|
+ .device = PCI_DEVICE_ID_O2_8220,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_O2,
|
|
|
+ .device = PCI_DEVICE_ID_O2_8221,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_O2,
|
|
|
+ .device = PCI_DEVICE_ID_O2_8320,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_O2,
|
|
|
+ .device = PCI_DEVICE_ID_O2_8321,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = (kernel_ulong_t)&sdhci_o2,
|
|
|
+ },
|
|
|
+
|
|
|
{ /* Generic SD host controller */
|
|
|
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
|
|
|
},
|