Commit 8b06f753 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Increase the timeout period of the ACMD41 command
   - Add card entry for quirks to debugfs
   - Add mmc_gpiod_set_cd_config() function
   - Store owner from SDIO modules with sdio_register_driver()

  MMC host:
   - atmel-mci: Some cleanups and a switch to use dev_err_probe()
   - renesas_sdhi:
      - Add support for RZ/G2L, RZ/G3S and RZ/V2M variants
      - Set the SDBUF after reset
   - sdhci: Add support for "Tuning Error" interrupts
   - sdhci-acpi:
      - Add quirk to enable pull-up on the card-detect GPIO on Asus
        T100TA
      - Disable write protect detection on Toshiba WT10-A
      - Fix Lenovo Yoga Tablet 2 Pro 1380 sdcard slot not working
   - sdhci_am654:
      - Re-work and fix the tuning support for multiple speed-modes
      - Add tuning algorithm for delay chain
   - sdhci-esdhc-imx: Add NXP S32G3 support
   - sdhci-of-dwcmshc:
      - Add tuning support for Sophgo CV1800B and SG200X
      - Implement SDHCI CQE support
   - sdhci-pci-gli: Use the proper pci_set_power_state() instead of
     PMCSR writes"

  MEMSTICK:
   - Convert a couple of drivers to use the ->remove_new() callback"

* tag 'mmc-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (59 commits)
  mmc: renesas_sdhi: Add compatible string for RZ/G2L family, RZ/G3S, and RZ/V2M SoCs
  dt-bindings: mmc: renesas,sdhi: Document RZ/G2L family compatibility
  dt-bindings: mmc: renesas,sdhi: Group single const value items into an enum list
  mmc: renesas_sdhi: Set the SDBUF after reset
  mmc: core: Increase the timeout period of the ACMD41 command
  mmc: core: Convert to use __mmc_poll_for_busy() SD_APP_OP_COND too
  mmc: atmel-mci: Switch to use dev_err_probe()
  mmc: atmel-mci: Incapsulate used to be a platform data into host structure
  mmc: atmel-mci: Replace platform device pointer by generic one
  mmc: atmel-mci: Use temporary variable for struct device
  mmc: atmel-mci: Get rid of platform data leftovers
  mmc: sdhci-of-dwcmshc: Add tuning support for Sophgo CV1800B and SG200X
  mmc: sdhci-of-dwcmshc: Remove useless "&" of th1520_execute_tuning
  mmc: sdhci-s3c: Choose sdhci_ops based on variant
  mmc: sdhci_am654: Constify struct sdhci_ops
  mmc: sdhci-sprd: Constify struct sdhci_ops
  mmc: sdhci-omap: Constify struct sdhci_ops
  mmc: sdhci-esdhc-mcf: Constify struct sdhci_ops
  mmc: slot-gpio: Use irq_handler_t type
  mmc: sdhci-acpi: Add quirk to enable pull-up on the card-detect GPIO on Asus T100TA
  ...
parents 8b35a3bb 35eea0de
...@@ -91,6 +91,9 @@ properties: ...@@ -91,6 +91,9 @@ properties:
- enum: - enum:
- fsl,imxrt1170-usdhc - fsl,imxrt1170-usdhc
- const: fsl,imxrt1050-usdhc - const: fsl,imxrt1050-usdhc
- items:
- const: nxp,s32g3-usdhc
- const: nxp,s32g2-usdhc
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -12,16 +12,13 @@ maintainers: ...@@ -12,16 +12,13 @@ maintainers:
properties: properties:
compatible: compatible:
oneOf: oneOf:
- items: - enum:
- const: renesas,sdhi-sh73a0 # R-Mobile APE6 - renesas,sdhi-mmc-r8a77470 # RZ/G1C
- items: - renesas,sdhi-r7s72100 # RZ/A1H
- const: renesas,sdhi-r7s72100 # RZ/A1H - renesas,sdhi-r7s9210 # SH-Mobile AG5
- items: - renesas,sdhi-r8a73a4 # R-Mobile APE6
- const: renesas,sdhi-r7s9210 # SH-Mobile AG5 - renesas,sdhi-r8a7740 # R-Mobile A1
- items: - renesas,sdhi-sh73a0 # R-Mobile APE6
- const: renesas,sdhi-r8a73a4 # R-Mobile APE6
- items:
- const: renesas,sdhi-r8a7740 # R-Mobile A1
- items: - items:
- enum: - enum:
- renesas,sdhi-r8a7778 # R-Car M1 - renesas,sdhi-r8a7778 # R-Car M1
...@@ -40,8 +37,6 @@ properties: ...@@ -40,8 +37,6 @@ properties:
- renesas,sdhi-r8a7793 # R-Car M2-N - renesas,sdhi-r8a7793 # R-Car M2-N
- renesas,sdhi-r8a7794 # R-Car E2 - renesas,sdhi-r8a7794 # R-Car E2
- const: renesas,rcar-gen2-sdhi # R-Car Gen2 and RZ/G1 - const: renesas,rcar-gen2-sdhi # R-Car Gen2 and RZ/G1
- items:
- const: renesas,sdhi-mmc-r8a77470 # RZ/G1C (SDHI/MMC IP)
- items: - items:
- enum: - enum:
- renesas,sdhi-r8a774a1 # RZ/G2M - renesas,sdhi-r8a774a1 # RZ/G2M
...@@ -56,11 +51,6 @@ properties: ...@@ -56,11 +51,6 @@ properties:
- renesas,sdhi-r8a77980 # R-Car V3H - renesas,sdhi-r8a77980 # R-Car V3H
- renesas,sdhi-r8a77990 # R-Car E3 - renesas,sdhi-r8a77990 # R-Car E3
- renesas,sdhi-r8a77995 # R-Car D3 - renesas,sdhi-r8a77995 # R-Car D3
- renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L
- renesas,sdhi-r9a08g045 # RZ/G3S
- renesas,sdhi-r9a09g011 # RZ/V2M
- const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2 - const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2
- items: - items:
- enum: - enum:
...@@ -69,6 +59,14 @@ properties: ...@@ -69,6 +59,14 @@ properties:
- renesas,sdhi-r8a779g0 # R-Car V4H - renesas,sdhi-r8a779g0 # R-Car V4H
- renesas,sdhi-r8a779h0 # R-Car V4M - renesas,sdhi-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-sdhi # R-Car Gen4 - const: renesas,rcar-gen4-sdhi # R-Car Gen4
- items:
- enum:
- renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L
- renesas,sdhi-r9a08g045 # RZ/G3S
- renesas,sdhi-r9a09g011 # RZ/V2M
- const: renesas,rzg2l-sdhi
reg: reg:
maxItems: 1 maxItems: 1
...@@ -120,12 +118,7 @@ allOf: ...@@ -120,12 +118,7 @@ allOf:
properties: properties:
compatible: compatible:
contains: contains:
enum: const: renesas,rzg2l-sdhi
- renesas,sdhi-r9a07g043
- renesas,sdhi-r9a07g044
- renesas,sdhi-r9a07g054
- renesas,sdhi-r9a08g045
- renesas,sdhi-r9a09g011
then: then:
properties: properties:
clocks: clocks:
......
...@@ -8616,7 +8616,7 @@ F: Documentation/devicetree/bindings/crypto/fsl,sec-v4.0* ...@@ -8616,7 +8616,7 @@ F: Documentation/devicetree/bindings/crypto/fsl,sec-v4.0*
F: drivers/crypto/caam/ F: drivers/crypto/caam/
FREESCALE COLDFIRE M5441X MMC DRIVER FREESCALE COLDFIRE M5441X MMC DRIVER
M: Angelo Dureghello <angelo.dureghello@timesys.com> M: Angelo Dureghello <adureghello@baylibre.com>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
S: Maintained S: Maintained
F: drivers/mmc/host/sdhci-esdhc-mcf.c F: drivers/mmc/host/sdhci-esdhc-mcf.c
......
...@@ -1736,7 +1736,6 @@ static struct sdio_driver bt_mrvl_sdio = { ...@@ -1736,7 +1736,6 @@ static struct sdio_driver bt_mrvl_sdio = {
.probe = btmrvl_sdio_probe, .probe = btmrvl_sdio_probe,
.remove = btmrvl_sdio_remove, .remove = btmrvl_sdio_remove,
.drv = { .drv = {
.owner = THIS_MODULE,
.coredump = btmrvl_sdio_coredump, .coredump = btmrvl_sdio_coredump,
.pm = &btmrvl_sdio_pm_ops, .pm = &btmrvl_sdio_pm_ops,
} }
......
...@@ -1519,7 +1519,6 @@ static struct sdio_driver btmtksdio_driver = { ...@@ -1519,7 +1519,6 @@ static struct sdio_driver btmtksdio_driver = {
.remove = btmtksdio_remove, .remove = btmtksdio_remove,
.id_table = btmtksdio_table, .id_table = btmtksdio_table,
.drv = { .drv = {
.owner = THIS_MODULE,
.pm = BTMTKSDIO_PM_OPS, .pm = BTMTKSDIO_PM_OPS,
} }
}; };
......
...@@ -574,16 +574,13 @@ static int rtsx_pci_ms_drv_probe(struct platform_device *pdev) ...@@ -574,16 +574,13 @@ static int rtsx_pci_ms_drv_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int rtsx_pci_ms_drv_remove(struct platform_device *pdev) static void rtsx_pci_ms_drv_remove(struct platform_device *pdev)
{ {
struct realtek_pci_ms *host = platform_get_drvdata(pdev); struct realtek_pci_ms *host = platform_get_drvdata(pdev);
struct rtsx_pcr *pcr; struct rtsx_pcr *pcr;
struct memstick_host *msh; struct memstick_host *msh;
int rc; int rc;
if (!host)
return 0;
pcr = host->pcr; pcr = host->pcr;
pcr->slots[RTSX_MS_CARD].p_dev = NULL; pcr->slots[RTSX_MS_CARD].p_dev = NULL;
pcr->slots[RTSX_MS_CARD].card_event = NULL; pcr->slots[RTSX_MS_CARD].card_event = NULL;
...@@ -613,8 +610,6 @@ static int rtsx_pci_ms_drv_remove(struct platform_device *pdev) ...@@ -613,8 +610,6 @@ static int rtsx_pci_ms_drv_remove(struct platform_device *pdev)
dev_dbg(&(pdev->dev), dev_dbg(&(pdev->dev),
": Realtek PCI-E Memstick controller has been removed\n"); ": Realtek PCI-E Memstick controller has been removed\n");
return 0;
} }
static struct platform_device_id rtsx_pci_ms_ids[] = { static struct platform_device_id rtsx_pci_ms_ids[] = {
...@@ -628,7 +623,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids); ...@@ -628,7 +623,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids);
static struct platform_driver rtsx_pci_ms_driver = { static struct platform_driver rtsx_pci_ms_driver = {
.probe = rtsx_pci_ms_drv_probe, .probe = rtsx_pci_ms_drv_probe,
.remove = rtsx_pci_ms_drv_remove, .remove_new = rtsx_pci_ms_drv_remove,
.id_table = rtsx_pci_ms_ids, .id_table = rtsx_pci_ms_ids,
.suspend = rtsx_pci_ms_suspend, .suspend = rtsx_pci_ms_suspend,
.resume = rtsx_pci_ms_resume, .resume = rtsx_pci_ms_resume,
......
...@@ -805,7 +805,7 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev) ...@@ -805,7 +805,7 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
return err; return err;
} }
static int rtsx_usb_ms_drv_remove(struct platform_device *pdev) static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{ {
struct rtsx_usb_ms *host = platform_get_drvdata(pdev); struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
struct memstick_host *msh = host->msh; struct memstick_host *msh = host->msh;
...@@ -840,8 +840,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev) ...@@ -840,8 +840,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
": Realtek USB Memstick controller has been removed\n"); ": Realtek USB Memstick controller has been removed\n");
memstick_free_host(msh); memstick_free_host(msh);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
return 0;
} }
static struct platform_device_id rtsx_usb_ms_ids[] = { static struct platform_device_id rtsx_usb_ms_ids[] = {
...@@ -855,7 +853,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids); ...@@ -855,7 +853,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids);
static struct platform_driver rtsx_usb_ms_driver = { static struct platform_driver rtsx_usb_ms_driver = {
.probe = rtsx_usb_ms_drv_probe, .probe = rtsx_usb_ms_drv_probe,
.remove = rtsx_usb_ms_drv_remove, .remove_new = rtsx_usb_ms_drv_remove,
.id_table = rtsx_usb_ms_ids, .id_table = rtsx_usb_ms_ids,
.driver = { .driver = {
.name = "rtsx_usb_ms", .name = "rtsx_usb_ms",
......
...@@ -234,7 +234,7 @@ static ssize_t power_ro_lock_show(struct device *dev, ...@@ -234,7 +234,7 @@ static ssize_t power_ro_lock_show(struct device *dev,
else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
locked = 1; locked = 1;
ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); ret = sysfs_emit(buf, "%d\n", locked);
mmc_blk_put(md); mmc_blk_put(md);
...@@ -296,9 +296,9 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, ...@@ -296,9 +296,9 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
int ret; int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
ret = snprintf(buf, PAGE_SIZE, "%d\n", ret = sysfs_emit(buf, "%d\n",
get_disk_ro(dev_to_disk(dev)) ^ get_disk_ro(dev_to_disk(dev)) ^
md->read_only); md->read_only);
mmc_blk_put(md); mmc_blk_put(md);
return ret; return ret;
} }
......
...@@ -351,11 +351,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) ...@@ -351,11 +351,11 @@ void mmc_add_host_debugfs(struct mmc_host *host)
root = debugfs_create_dir(mmc_hostname(host), NULL); root = debugfs_create_dir(mmc_hostname(host), NULL);
host->debugfs_root = root; host->debugfs_root = root;
debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); debugfs_create_file("ios", 0400, root, host, &mmc_ios_fops);
debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops); debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops);
debugfs_create_file("caps2", 0600, root, &host->caps2, debugfs_create_file("caps2", 0600, root, &host->caps2,
&mmc_caps2_fops); &mmc_caps2_fops);
debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host, debugfs_create_file_unsafe("clock", 0600, root, host,
&mmc_clock_fops); &mmc_clock_fops);
debugfs_create_file_unsafe("err_state", 0600, root, host, debugfs_create_file_unsafe("err_state", 0600, root, host,
...@@ -388,7 +388,8 @@ void mmc_add_card_debugfs(struct mmc_card *card) ...@@ -388,7 +388,8 @@ void mmc_add_card_debugfs(struct mmc_card *card)
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root); root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
card->debugfs_root = root; card->debugfs_root = root;
debugfs_create_x32("state", S_IRUSR, root, &card->state); debugfs_create_x32("state", 0400, root, &card->state);
debugfs_create_x32("quirks", 0400, root, &card->quirks);
} }
void mmc_remove_card_debugfs(struct mmc_card *card) void mmc_remove_card_debugfs(struct mmc_card *card)
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/pm_wakeup.h> #include <linux/pm_wakeup.h>
#include <linux/export.h> #include <linux/export.h>
......
...@@ -19,6 +19,20 @@ ...@@ -19,6 +19,20 @@
#include "sd_ops.h" #include "sd_ops.h"
#include "mmc_ops.h" #include "mmc_ops.h"
/*
* Extensive testing has shown that some specific SD cards
* require an increased command timeout to be successfully
* initialized.
*/
#define SD_APP_OP_COND_PERIOD_US (10 * 1000) /* 10ms */
#define SD_APP_OP_COND_TIMEOUT_MS 2000 /* 2s */
struct sd_app_op_cond_busy_data {
struct mmc_host *host;
u32 ocr;
struct mmc_command *cmd;
};
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{ {
int err; int err;
...@@ -115,10 +129,45 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) ...@@ -115,10 +129,45 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
return mmc_wait_for_app_cmd(card->host, card, &cmd); return mmc_wait_for_app_cmd(card->host, card, &cmd);
} }
static int sd_app_op_cond_cb(void *cb_data, bool *busy)
{
struct sd_app_op_cond_busy_data *data = cb_data;
struct mmc_host *host = data->host;
struct mmc_command *cmd = data->cmd;
u32 ocr = data->ocr;
int err;
*busy = false;
err = mmc_wait_for_app_cmd(host, NULL, cmd);
if (err)
return err;
/* If we're just probing, do a single pass. */
if (ocr == 0)
return 0;
/* Wait until reset completes. */
if (mmc_host_is_spi(host)) {
if (!(cmd->resp[0] & R1_SPI_IDLE))
return 0;
} else if (cmd->resp[0] & MMC_CARD_BUSY) {
return 0;
}
*busy = true;
return 0;
}
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{ {
struct mmc_command cmd = {}; struct mmc_command cmd = {};
int i, err = 0; struct sd_app_op_cond_busy_data cb_data = {
.host = host,
.ocr = ocr,
.cmd = &cmd
};
int err;
cmd.opcode = SD_APP_OP_COND; cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host)) if (mmc_host_is_spi(host))
...@@ -127,36 +176,16 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -127,36 +176,16 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.arg = ocr; cmd.arg = ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) { err = __mmc_poll_for_busy(host, SD_APP_OP_COND_PERIOD_US,
err = mmc_wait_for_app_cmd(host, NULL, &cmd); SD_APP_OP_COND_TIMEOUT_MS, &sd_app_op_cond_cb,
if (err) &cb_data);
break; if (err)
return err;
/* if we're just probing, do a single pass */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (mmc_host_is_spi(host)) {
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
} else {
if (cmd.resp[0] & MMC_CARD_BUSY)
break;
}
err = -ETIMEDOUT;
mmc_delay(10);
}
if (!i)
pr_err("%s: card never left busy state\n", mmc_hostname(host));
if (rocr && !mmc_host_is_spi(host)) if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0]; *rocr = cmd.resp[0];
return err; return 0;
} }
static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits, static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
......
...@@ -265,16 +265,19 @@ void sdio_unregister_bus(void) ...@@ -265,16 +265,19 @@ void sdio_unregister_bus(void)
} }
/** /**
* sdio_register_driver - register a function driver * __sdio_register_driver - register a function driver
* @drv: SDIO function driver * @drv: SDIO function driver
* @owner: owning module/driver
*/ */
int sdio_register_driver(struct sdio_driver *drv) int __sdio_register_driver(struct sdio_driver *drv, struct module *owner)
{ {
drv->drv.name = drv->name; drv->drv.name = drv->name;
drv->drv.bus = &sdio_bus_type; drv->drv.bus = &sdio_bus_type;
drv->drv.owner = owner;
return driver_register(&drv->drv); return driver_register(&drv->drv);
} }
EXPORT_SYMBOL_GPL(sdio_register_driver); EXPORT_SYMBOL_GPL(__sdio_register_driver);
/** /**
* sdio_unregister_driver - unregister a function driver * sdio_unregister_driver - unregister a function driver
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
struct mmc_gpio { struct mmc_gpio {
struct gpio_desc *ro_gpio; struct gpio_desc *ro_gpio;
struct gpio_desc *cd_gpio; struct gpio_desc *cd_gpio;
irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); irq_handler_t cd_gpio_isr;
char *ro_label; char *ro_label;
char *cd_label; char *cd_label;
u32 cd_debounce_delay_ms; u32 cd_debounce_delay_ms;
...@@ -162,8 +162,7 @@ EXPORT_SYMBOL(mmc_gpio_set_cd_wake); ...@@ -162,8 +162,7 @@ EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
/* Register an alternate interrupt service routine for /* Register an alternate interrupt service routine for
* the card-detect GPIO. * the card-detect GPIO.
*/ */
void mmc_gpio_set_cd_isr(struct mmc_host *host, void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr)
irqreturn_t (*isr)(int irq, void *dev_id))
{ {
struct mmc_gpio *ctx = host->slot.handler_priv; struct mmc_gpio *ctx = host->slot.handler_priv;
...@@ -221,6 +220,26 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, ...@@ -221,6 +220,26 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
} }
EXPORT_SYMBOL(mmc_gpiod_request_cd); EXPORT_SYMBOL(mmc_gpiod_request_cd);
/**
* mmc_gpiod_set_cd_config - set config for card-detection GPIO
* @host: mmc host
* @config: Generic pinconf config (from pinconf_to_config_packed())
*
* This can be used by mmc host drivers to fixup a card-detection GPIO's config
* (e.g. set PIN_CONFIG_BIAS_PULL_UP) after acquiring the GPIO descriptor
* through mmc_gpiod_request_cd().
*
* Returns:
* 0 on success, or a negative errno value on error.
*/
int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
return gpiod_set_config(ctx->cd_gpio, config);
}
EXPORT_SYMBOL(mmc_gpiod_set_cd_config);
bool mmc_can_gpio_cd(struct mmc_host *host) bool mmc_can_gpio_cd(struct mmc_host *host)
{ {
struct mmc_gpio *ctx = host->slot.handler_priv; struct mmc_gpio *ctx = host->slot.handler_priv;
......
...@@ -233,6 +233,7 @@ config MMC_SDHCI_OF_DWCMSHC ...@@ -233,6 +233,7 @@ config MMC_SDHCI_OF_DWCMSHC
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on OF depends on OF
depends on COMMON_CLK depends on COMMON_CLK
select MMC_CQHCI
help help
This selects Synopsys DesignWare Cores Mobile Storage Controller This selects Synopsys DesignWare Cores Mobile Storage Controller
support. support.
......
This diff is collapsed.
...@@ -474,8 +474,8 @@ static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq) ...@@ -474,8 +474,8 @@ static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq)
return sg_count; return sg_count;
} }
static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
bool dma64) bool dma64)
{ {
__le32 *attr = (__le32 __force *)desc; __le32 *attr = (__le32 __force *)desc;
...@@ -495,6 +495,7 @@ static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, ...@@ -495,6 +495,7 @@ static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
dataddr[0] = cpu_to_le32(addr); dataddr[0] = cpu_to_le32(addr);
} }
} }
EXPORT_SYMBOL(cqhci_set_tran_desc);
static int cqhci_prep_tran_desc(struct mmc_request *mrq, static int cqhci_prep_tran_desc(struct mmc_request *mrq,
struct cqhci_host *cq_host, int tag) struct cqhci_host *cq_host, int tag)
...@@ -522,7 +523,11 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq, ...@@ -522,7 +523,11 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq,
if ((i+1) == sg_count) if ((i+1) == sg_count)
end = true; end = true;
cqhci_set_tran_desc(desc, addr, len, end, dma64); if (cq_host->ops->set_tran_desc)
cq_host->ops->set_tran_desc(cq_host, &desc, addr, len, end, dma64);
else
cqhci_set_tran_desc(desc, addr, len, end, dma64);
desc += cq_host->trans_desc_len; desc += cq_host->trans_desc_len;
} }
......
...@@ -293,6 +293,9 @@ struct cqhci_host_ops { ...@@ -293,6 +293,9 @@ struct cqhci_host_ops {
int (*program_key)(struct cqhci_host *cq_host, int (*program_key)(struct cqhci_host *cq_host,
const union cqhci_crypto_cfg_entry *cfg, int slot); const union cqhci_crypto_cfg_entry *cfg, int slot);
#endif #endif
void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc,
dma_addr_t addr, int len, bool end, bool dma64);
}; };
static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
...@@ -318,6 +321,7 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, ...@@ -318,6 +321,7 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64);
struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev);
int cqhci_deactivate(struct mmc_host *mmc); int cqhci_deactivate(struct mmc_host *mmc);
void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64);
static inline int cqhci_suspend(struct mmc_host *mmc) static inline int cqhci_suspend(struct mmc_host *mmc)
{ {
return cqhci_deactivate(mmc); return cqhci_deactivate(mmc);
......
...@@ -1337,7 +1337,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) ...@@ -1337,7 +1337,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev)
return ret; return ret;
} }
static void __exit davinci_mmcsd_remove(struct platform_device *pdev) static void davinci_mmcsd_remove(struct platform_device *pdev)
{ {
struct mmc_davinci_host *host = platform_get_drvdata(pdev); struct mmc_davinci_host *host = platform_get_drvdata(pdev);
...@@ -1392,7 +1392,7 @@ static struct platform_driver davinci_mmcsd_driver = { ...@@ -1392,7 +1392,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.of_match_table = davinci_mmc_dt_ids, .of_match_table = davinci_mmc_dt_ids,
}, },
.probe = davinci_mmcsd_probe, .probe = davinci_mmcsd_probe,
.remove_new = __exit_p(davinci_mmcsd_remove), .remove_new = davinci_mmcsd_remove,
.id_table = davinci_mmc_devtype, .id_table = davinci_mmc_devtype,
}; };
......
...@@ -87,7 +87,6 @@ static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot, ...@@ -87,7 +87,6 @@ static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot,
goto tuning_out; goto tuning_out;
prev_err = err; prev_err = err;
err = 0;
} }
tuning_out: tuning_out:
......
...@@ -133,7 +133,6 @@ static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot, ...@@ -133,7 +133,6 @@ static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot,
goto tuning_out; goto tuning_out;
prev_err = err; prev_err = err;
err = 0;
} }
tuning_out: tuning_out:
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h> #include <linux/pm.h>
......
...@@ -589,6 +589,9 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve) ...@@ -589,6 +589,9 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
priv->needs_adjust_hs400 = false; priv->needs_adjust_hs400 = false;
renesas_sdhi_set_clock(host, host->clk_cache); renesas_sdhi_set_clock(host, host->clk_cache);
/* Ensure default value for this driver. */
renesas_sdhi_sdbuf_width(host, 16);
} else if (priv->scc_ctl) { } else if (priv->scc_ctl) {
renesas_sdhi_scc_reset(host, priv); renesas_sdhi_scc_reset(host, priv);
} }
......
...@@ -210,7 +210,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = { ...@@ -210,7 +210,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = {
.manual_tap_correction = true, .manual_tap_correction = true,
}; };
static const struct renesas_sdhi_quirks sdhi_quirks_r9a09g011 = { static const struct renesas_sdhi_quirks sdhi_quirks_rzg2l = {
.fixed_addr_mode = true, .fixed_addr_mode = true,
.hs400_disabled = true, .hs400_disabled = true,
}; };
...@@ -255,9 +255,9 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = { ...@@ -255,9 +255,9 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = {
.quirks = &sdhi_quirks_r8a77990, .quirks = &sdhi_quirks_r8a77990,
}; };
static const struct renesas_sdhi_of_data_with_quirks of_r9a09g011_compatible = { static const struct renesas_sdhi_of_data_with_quirks of_rzg2l_compatible = {
.of_data = &of_data_rcar_gen3, .of_data = &of_data_rcar_gen3,
.quirks = &sdhi_quirks_r9a09g011, .quirks = &sdhi_quirks_rzg2l,
}; };
static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = { static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = {
...@@ -283,7 +283,8 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { ...@@ -283,7 +283,8 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, }, { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, },
{ .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
{ .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
{ .compatible = "renesas,sdhi-r9a09g011", .data = &of_r9a09g011_compatible, }, { .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
{}, {},
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -80,6 +81,8 @@ struct sdhci_acpi_host { ...@@ -80,6 +81,8 @@ struct sdhci_acpi_host {
enum { enum {
DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP = BIT(0), DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP = BIT(0),
DMI_QUIRK_SD_NO_WRITE_PROTECT = BIT(1), DMI_QUIRK_SD_NO_WRITE_PROTECT = BIT(1),
DMI_QUIRK_SD_CD_ACTIVE_HIGH = BIT(2),
DMI_QUIRK_SD_CD_ENABLE_PULL_UP = BIT(3),
}; };
static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c) static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
...@@ -719,7 +722,28 @@ static const struct acpi_device_id sdhci_acpi_ids[] = { ...@@ -719,7 +722,28 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
}; };
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
/* Please keep this list sorted alphabetically */
static const struct dmi_system_id sdhci_acpi_quirks[] = { static const struct dmi_system_id sdhci_acpi_quirks[] = {
{
/*
* The Acer Aspire Switch 10 (SW5-012) microSD slot always
* reports the card being write-protected even though microSD
* cards do not have a write-protect switch at all.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
},
{
/* Asus T100TA, needs pull-up for cd but DSDT GpioInt has NoPull set */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = (void *)DMI_QUIRK_SD_CD_ENABLE_PULL_UP,
},
{ {
/* /*
* The Lenovo Miix 320-10ICR has a bug in the _PS0 method of * The Lenovo Miix 320-10ICR has a bug in the _PS0 method of
...@@ -736,15 +760,23 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = { ...@@ -736,15 +760,23 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = {
}, },
{ {
/* /*
* The Acer Aspire Switch 10 (SW5-012) microSD slot always * Lenovo Yoga Tablet 2 Pro 1380F/L (13" Android version) this
* reports the card being write-protected even though microSD * has broken WP reporting and an inverted CD signal.
* cards do not have a write-protect switch at all. * Note this has more or less the same BIOS as the Lenovo Yoga
* Tablet 2 830F/L or 1050F/L (8" and 10" Android), but unlike
* the 830 / 1050 models which share the same mainboard this
* model has a different mainboard and the inverted CD and
* broken WP are unique to this board.
*/ */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
/* Full match so as to NOT match the 830/1050 BIOS */
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21.X64.0005.R00.1504101516"),
}, },
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT, .driver_data = (void *)(DMI_QUIRK_SD_NO_WRITE_PROTECT |
DMI_QUIRK_SD_CD_ACTIVE_HIGH),
}, },
{ {
/* /*
...@@ -757,6 +789,17 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = { ...@@ -757,6 +789,17 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = {
}, },
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT, .driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
}, },
{
/*
* The Toshiba WT10-A's microSD slot always reports the card being
* write-protected.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "TOSHIBA WT10-A"),
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
},
{} /* Terminating entry */ {} /* Terminating entry */
}; };
...@@ -866,12 +909,18 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -866,12 +909,18 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL); bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
if (quirks & DMI_QUIRK_SD_CD_ACTIVE_HIGH)
host->mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0); err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0);
if (err) { if (err) {
if (err == -EPROBE_DEFER) if (err == -EPROBE_DEFER)
goto err_free; goto err_free;
dev_warn(dev, "failed to setup card detect gpio\n"); dev_warn(dev, "failed to setup card detect gpio\n");
c->use_runtime_pm = false; c->use_runtime_pm = false;
} else if (quirks & DMI_QUIRK_SD_CD_ENABLE_PULL_UP) {
mmc_gpiod_set_cd_config(host->mmc,
PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP, 20000));
} }
if (quirks & DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP) if (quirks & DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP)
......
...@@ -335,7 +335,7 @@ static void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host, ...@@ -335,7 +335,7 @@ static void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host,
data->blksz * data->blocks); data->blksz * data->blocks);
} }
static struct sdhci_ops sdhci_esdhc_ops = { static const struct sdhci_ops sdhci_esdhc_ops = {
.reset = esdhc_mcf_reset, .reset = esdhc_mcf_reset,
.set_clock = esdhc_mcf_pltfm_set_clock, .set_clock = esdhc_mcf_pltfm_set_clock,
.get_max_clock = esdhc_mcf_pltfm_get_max_clock, .get_max_clock = esdhc_mcf_pltfm_get_max_clock,
......
This diff is collapsed.
...@@ -925,7 +925,7 @@ static void sdhci_omap_set_timeout(struct sdhci_host *host, ...@@ -925,7 +925,7 @@ static void sdhci_omap_set_timeout(struct sdhci_host *host,
__sdhci_set_timeout(host, cmd); __sdhci_set_timeout(host, cmd);
} }
static struct sdhci_ops sdhci_omap_ops = { static const struct sdhci_ops sdhci_omap_ops = {
.set_clock = sdhci_omap_set_clock, .set_clock = sdhci_omap_set_clock,
.set_power = sdhci_omap_set_power, .set_power = sdhci_omap_set_power,
.enable_dma = sdhci_omap_enable_dma, .enable_dma = sdhci_omap_enable_dma,
......
...@@ -25,12 +25,6 @@ ...@@ -25,12 +25,6 @@
#define GLI_9750_WT_EN_ON 0x1 #define GLI_9750_WT_EN_ON 0x1
#define GLI_9750_WT_EN_OFF 0x0 #define GLI_9750_WT_EN_OFF 0x0
#define PCI_GLI_9750_PM_CTRL 0xFC
#define PCI_GLI_9750_PM_STATE GENMASK(1, 0)
#define PCI_GLI_9750_CORRERR_MASK 0x214
#define PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12)
#define SDHCI_GLI_9750_CFG2 0x848 #define SDHCI_GLI_9750_CFG2 0x848
#define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24)
#define GLI_9750_CFG2_L1DLY_VALUE 0x1F #define GLI_9750_CFG2_L1DLY_VALUE 0x1F
...@@ -152,12 +146,6 @@ ...@@ -152,12 +146,6 @@
#define PCI_GLI_9755_MISC 0x78 #define PCI_GLI_9755_MISC 0x78
#define PCI_GLI_9755_MISC_SSC_OFF BIT(26) #define PCI_GLI_9755_MISC_SSC_OFF BIT(26)
#define PCI_GLI_9755_PM_CTRL 0xFC
#define PCI_GLI_9755_PM_STATE GENMASK(1, 0)
#define PCI_GLI_9755_CORRERR_MASK 0x214
#define PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12)
#define SDHCI_GLI_9767_GM_BURST_SIZE 0x510 #define SDHCI_GLI_9767_GM_BURST_SIZE 0x510
#define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8) #define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8)
...@@ -547,6 +535,7 @@ static void gl9750_hw_setting(struct sdhci_host *host) ...@@ -547,6 +535,7 @@ static void gl9750_hw_setting(struct sdhci_host *host)
{ {
struct sdhci_pci_slot *slot = sdhci_priv(host); struct sdhci_pci_slot *slot = sdhci_priv(host);
struct pci_dev *pdev; struct pci_dev *pdev;
int aer;
u32 value; u32 value;
pdev = slot->chip->pdev; pdev = slot->chip->pdev;
...@@ -561,16 +550,16 @@ static void gl9750_hw_setting(struct sdhci_host *host) ...@@ -561,16 +550,16 @@ static void gl9750_hw_setting(struct sdhci_host *host)
sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); sdhci_writel(host, value, SDHCI_GLI_9750_CFG2);
/* toggle PM state to allow GL9750 to enter ASPM L1.2 */ /* toggle PM state to allow GL9750 to enter ASPM L1.2 */
pci_read_config_dword(pdev, PCI_GLI_9750_PM_CTRL, &value); pci_set_power_state(pdev, PCI_D3hot);
value |= PCI_GLI_9750_PM_STATE; pci_set_power_state(pdev, PCI_D0);
pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value);
value &= ~PCI_GLI_9750_PM_STATE;
pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value);
/* mask the replay timer timeout of AER */ /* mask the replay timer timeout of AER */
pci_read_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, &value); aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
value |= PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT; if (aer) {
pci_write_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, value); pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value);
value |= PCI_ERR_COR_REP_TIMER;
pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value);
}
gl9750_wt_off(host); gl9750_wt_off(host);
} }
...@@ -745,6 +734,7 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -745,6 +734,7 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock)
static void gl9755_hw_setting(struct sdhci_pci_slot *slot) static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
{ {
struct pci_dev *pdev = slot->chip->pdev; struct pci_dev *pdev = slot->chip->pdev;
int aer;
u32 value; u32 value;
gl9755_wt_on(pdev); gl9755_wt_on(pdev);
...@@ -775,16 +765,16 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) ...@@ -775,16 +765,16 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value); pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value);
/* toggle PM state to allow GL9755 to enter ASPM L1.2 */ /* toggle PM state to allow GL9755 to enter ASPM L1.2 */
pci_read_config_dword(pdev, PCI_GLI_9755_PM_CTRL, &value); pci_set_power_state(pdev, PCI_D3hot);
value |= PCI_GLI_9755_PM_STATE; pci_set_power_state(pdev, PCI_D0);
pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value);
value &= ~PCI_GLI_9755_PM_STATE;
pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value);
/* mask the replay timer timeout of AER */ /* mask the replay timer timeout of AER */
pci_read_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, &value); aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
value |= PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT; if (aer) {
pci_write_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, value); pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value);
value |= PCI_ERR_COR_REP_TIMER;
pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value);
}
gl9755_wt_off(pdev); gl9755_wt_off(pdev);
} }
......
...@@ -17,10 +17,8 @@ ...@@ -17,10 +17,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -132,14 +130,16 @@ struct sdhci_s3c { ...@@ -132,14 +130,16 @@ struct sdhci_s3c {
* struct sdhci_s3c_drv_data - S3C SDHCI platform specific driver data * struct sdhci_s3c_drv_data - S3C SDHCI platform specific driver data
* @sdhci_quirks: sdhci host specific quirks. * @sdhci_quirks: sdhci host specific quirks.
* @no_divider: no or non-standard internal clock divider. * @no_divider: no or non-standard internal clock divider.
* @ops: sdhci_ops to use for this variant
* *
* Specifies platform specific configuration of sdhci controller. * Specifies platform specific configuration of sdhci controller.
* Note: A structure for driver specific platform data is used for future * Note: A structure for driver specific platform data is used for future
* expansion of its usage. * expansion of its usage.
*/ */
struct sdhci_s3c_drv_data { struct sdhci_s3c_drv_data {
unsigned int sdhci_quirks; unsigned int sdhci_quirks;
bool no_divider; bool no_divider;
const struct sdhci_ops *ops;
}; };
static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
...@@ -414,7 +414,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -414,7 +414,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
} }
static struct sdhci_ops sdhci_s3c_ops = { static const struct sdhci_ops sdhci_s3c_ops_s3c6410 = {
.get_max_clock = sdhci_s3c_get_max_clk, .get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock, .set_clock = sdhci_s3c_set_clock,
.get_min_clock = sdhci_s3c_get_min_clock, .get_min_clock = sdhci_s3c_get_min_clock,
...@@ -423,6 +423,15 @@ static struct sdhci_ops sdhci_s3c_ops = { ...@@ -423,6 +423,15 @@ static struct sdhci_ops sdhci_s3c_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_ops sdhci_s3c_ops_exynos4 __maybe_unused = {
.get_max_clock = sdhci_cmu_get_max_clock,
.set_clock = sdhci_cmu_set_clock,
.get_min_clock = sdhci_cmu_get_min_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
#ifdef CONFIG_OF #ifdef CONFIG_OF
static int sdhci_s3c_parse_dt(struct device *dev, static int sdhci_s3c_parse_dt(struct device *dev,
struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) struct sdhci_host *host, struct s3c_sdhci_platdata *pdata)
...@@ -446,7 +455,7 @@ static int sdhci_s3c_parse_dt(struct device *dev, ...@@ -446,7 +455,7 @@ static int sdhci_s3c_parse_dt(struct device *dev,
return 0; return 0;
} }
if (of_get_named_gpio(node, "cd-gpios", 0)) if (of_property_present(node, "cd-gpios"))
return 0; return 0;
/* assuming internal card detect that will be configured by pinctrl */ /* assuming internal card detect that will be configured by pinctrl */
...@@ -562,7 +571,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -562,7 +571,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
pdata->cfg_gpio(pdev, pdata->max_width); pdata->cfg_gpio(pdev, pdata->max_width);
host->hw_name = "samsung-hsmmc"; host->hw_name = "samsung-hsmmc";
host->ops = &sdhci_s3c_ops; host->ops = &sdhci_s3c_ops_s3c6410;
host->quirks = 0; host->quirks = 0;
host->quirks2 = 0; host->quirks2 = 0;
host->irq = irq; host->irq = irq;
...@@ -572,6 +581,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -572,6 +581,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
if (drv_data) { if (drv_data) {
host->quirks |= drv_data->sdhci_quirks; host->quirks |= drv_data->sdhci_quirks;
host->ops = drv_data->ops;
sc->no_divider = drv_data->no_divider; sc->no_divider = drv_data->no_divider;
} }
...@@ -619,16 +629,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -619,16 +629,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
/* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
/*
* If controller does not have internal clock divider,
* we can use overriding functions instead of default.
*/
if (sc->no_divider) {
sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
}
/* It supports additional host capabilities if needed */ /* It supports additional host capabilities if needed */
if (pdata->host_caps) if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps; host->mmc->caps |= pdata->host_caps;
...@@ -760,6 +760,7 @@ MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); ...@@ -760,6 +760,7 @@ MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { static const struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
.no_divider = true, .no_divider = true,
.ops = &sdhci_s3c_ops_exynos4,
}; };
static const struct of_device_id sdhci_s3c_dt_match[] = { static const struct of_device_id sdhci_s3c_dt_match[] = {
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -440,7 +439,7 @@ static void sdhci_sprd_set_power(struct sdhci_host *host, unsigned char mode, ...@@ -440,7 +439,7 @@ static void sdhci_sprd_set_power(struct sdhci_host *host, unsigned char mode,
} }
} }
static struct sdhci_ops sdhci_sprd_ops = { static const struct sdhci_ops sdhci_sprd_ops = {
.read_l = sdhci_sprd_readl, .read_l = sdhci_sprd_readl,
.write_l = sdhci_sprd_writel, .write_l = sdhci_sprd_writel,
.write_w = sdhci_sprd_writew, .write_w = sdhci_sprd_writew,
......
...@@ -3439,12 +3439,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) ...@@ -3439,12 +3439,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
host->data->error = -EILSEQ; host->data->error = -EILSEQ;
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC); sdhci_err_stats_inc(host, DAT_CRC);
} else if ((intmask & SDHCI_INT_DATA_CRC) && } else if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) &&
SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
!= MMC_BUS_TEST_R) { != MMC_BUS_TEST_R) {
host->data->error = -EILSEQ; host->data->error = -EILSEQ;
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC); sdhci_err_stats_inc(host, DAT_CRC);
if (intmask & SDHCI_INT_TUNING_ERROR) {
u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
}
} else if (intmask & SDHCI_INT_ADMA_ERROR) { } else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc), pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
intmask); intmask);
...@@ -3979,7 +3985,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, ...@@ -3979,7 +3985,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
} else } else
*cmd_error = 0; *cmd_error = 0;
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) { if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) {
*data_error = -EILSEQ; *data_error = -EILSEQ;
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC); sdhci_err_stats_inc(host, DAT_CRC);
......
...@@ -158,6 +158,7 @@ ...@@ -158,6 +158,7 @@
#define SDHCI_INT_BUS_POWER 0x00800000 #define SDHCI_INT_BUS_POWER 0x00800000
#define SDHCI_INT_AUTO_CMD_ERR 0x01000000 #define SDHCI_INT_AUTO_CMD_ERR 0x01000000
#define SDHCI_INT_ADMA_ERROR 0x02000000 #define SDHCI_INT_ADMA_ERROR 0x02000000
#define SDHCI_INT_TUNING_ERROR 0x04000000
#define SDHCI_INT_NORMAL_MASK 0x00007FFF #define SDHCI_INT_NORMAL_MASK 0x00007FFF
#define SDHCI_INT_ERROR_MASK 0xFFFF8000 #define SDHCI_INT_ERROR_MASK 0xFFFF8000
...@@ -169,7 +170,7 @@ ...@@ -169,7 +170,7 @@
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
SDHCI_INT_BLK_GAP) SDHCI_INT_BLK_GAP | SDHCI_INT_TUNING_ERROR)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1) #define SDHCI_INT_ALL_MASK ((unsigned int)-1)
#define SDHCI_CQE_INT_ERR_MASK ( \ #define SDHCI_CQE_INT_ERR_MASK ( \
......
...@@ -141,18 +141,26 @@ static const struct timing_data td[] = { ...@@ -141,18 +141,26 @@ static const struct timing_data td[] = {
struct sdhci_am654_data { struct sdhci_am654_data {
struct regmap *base; struct regmap *base;
int otap_del_sel[ARRAY_SIZE(td)]; u32 otap_del_sel[ARRAY_SIZE(td)];
int itap_del_sel[ARRAY_SIZE(td)]; u32 itap_del_sel[ARRAY_SIZE(td)];
u32 itap_del_ena[ARRAY_SIZE(td)];
int clkbuf_sel; int clkbuf_sel;
int trm_icp; int trm_icp;
int drv_strength; int drv_strength;
int strb_sel; int strb_sel;
u32 flags; u32 flags;
u32 quirks; u32 quirks;
bool dll_enable;
#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
}; };
struct window {
u8 start;
u8 end;
u8 length;
};
struct sdhci_am654_driver_data { struct sdhci_am654_driver_data {
const struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
u32 flags; u32 flags;
...@@ -232,11 +240,13 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) ...@@ -232,11 +240,13 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock)
} }
static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654, static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654,
u32 itapdly) u32 itapdly, u32 enable)
{ {
/* Set ITAPCHGWIN before writing to ITAPDLY */ /* Set ITAPCHGWIN before writing to ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK,
1 << ITAPCHGWIN_SHIFT); 1 << ITAPCHGWIN_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK,
enable << ITAPDLYENA_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK, regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK,
itapdly << ITAPDLYSEL_SHIFT); itapdly << ITAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
...@@ -253,8 +263,8 @@ static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654, ...@@ -253,8 +263,8 @@ static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654,
mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK;
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val); regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val);
sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing],
sdhci_am654->itap_del_sel[timing]); sdhci_am654->itap_del_ena[timing]);
} }
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
...@@ -263,19 +273,17 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -263,19 +273,17 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
unsigned char timing = host->mmc->ios.timing; unsigned char timing = host->mmc->ios.timing;
u32 otap_del_sel; u32 otap_del_sel;
u32 otap_del_ena;
u32 mask, val; u32 mask, val;
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
sdhci_set_clock(host, clock); sdhci_set_clock(host, clock);
/* Setup DLL Output TAP delay */ /* Setup Output TAP delay */
otap_del_sel = sdhci_am654->otap_del_sel[timing]; otap_del_sel = sdhci_am654->otap_del_sel[timing];
otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (otap_del_ena << OTAPDLYENA_SHIFT) | val = (0x1 << OTAPDLYENA_SHIFT) |
(otap_del_sel << OTAPDLYSEL_SHIFT); (otap_del_sel << OTAPDLYSEL_SHIFT);
/* Write to STRBSEL for HS400 speed mode */ /* Write to STRBSEL for HS400 speed mode */
...@@ -290,10 +298,21 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -290,10 +298,21 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) {
sdhci_am654_setup_dll(host, clock); sdhci_am654_setup_dll(host, clock);
else sdhci_am654->dll_enable = true;
if (timing == MMC_TIMING_MMC_HS400) {
sdhci_am654->itap_del_ena[timing] = 0x1;
sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel[timing - 1];
}
sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing],
sdhci_am654->itap_del_ena[timing]);
} else {
sdhci_am654_setup_delay_chain(sdhci_am654, timing); sdhci_am654_setup_delay_chain(sdhci_am654, timing);
sdhci_am654->dll_enable = false;
}
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel); sdhci_am654->clkbuf_sel);
...@@ -306,16 +325,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, ...@@ -306,16 +325,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
unsigned char timing = host->mmc->ios.timing; unsigned char timing = host->mmc->ios.timing;
u32 otap_del_sel; u32 otap_del_sel;
u32 itap_del_ena;
u32 itap_del_sel;
u32 mask, val; u32 mask, val;
/* Setup DLL Output TAP delay */ /* Setup Output TAP delay */
otap_del_sel = sdhci_am654->otap_del_sel[timing]; otap_del_sel = sdhci_am654->otap_del_sel[timing];
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (0x1 << OTAPDLYENA_SHIFT) | val = (0x1 << OTAPDLYENA_SHIFT) |
(otap_del_sel << OTAPDLYSEL_SHIFT); (otap_del_sel << OTAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
/* Setup Input TAP delay */
itap_del_ena = sdhci_am654->itap_del_ena[timing];
itap_del_sel = sdhci_am654->itap_del_sel[timing];
mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK;
val |= (itap_del_ena << ITAPDLYENA_SHIFT) |
(itap_del_sel << ITAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK,
1 << ITAPCHGWIN_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel); sdhci_am654->clkbuf_sel);
...@@ -408,45 +440,110 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) ...@@ -408,45 +440,110 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
return 0; return 0;
} }
#define ITAP_MAX 32 #define ITAPDLY_LENGTH 32
#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1)
static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window
*fail_window, u8 num_fails, bool circular_buffer)
{
u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0;
u8 first_fail_start = 0, last_fail_end = 0;
struct device *dev = mmc_dev(host->mmc);
struct window pass_window = {0, 0, 0};
int prev_fail_end = -1;
u8 i;
if (!num_fails)
return ITAPDLY_LAST_INDEX >> 1;
if (fail_window->length == ITAPDLY_LENGTH) {
dev_err(dev, "No passing ITAPDLY, return 0\n");
return 0;
}
first_fail_start = fail_window->start;
last_fail_end = fail_window[num_fails - 1].end;
for (i = 0; i < num_fails; i++) {
start_fail = fail_window[i].start;
end_fail = fail_window[i].end;
pass_length = start_fail - (prev_fail_end + 1);
if (pass_length > pass_window.length) {
pass_window.start = prev_fail_end + 1;
pass_window.length = pass_length;
}
prev_fail_end = end_fail;
}
if (!circular_buffer)
pass_length = ITAPDLY_LAST_INDEX - last_fail_end;
else
pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start;
if (pass_length > pass_window.length) {
pass_window.start = last_fail_end + 1;
pass_window.length = pass_length;
}
if (!circular_buffer)
itap = pass_window.start + (pass_window.length >> 1);
else
itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH;
return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap;
}
static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host,
u32 opcode) u32 opcode)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; unsigned char timing = host->mmc->ios.timing;
u32 itap; struct window fail_window[ITAPDLY_LENGTH];
u8 curr_pass, itap;
u8 fail_index = 0;
u8 prev_pass = 1;
memset(fail_window, 0, sizeof(fail_window));
/* Enable ITAPDLY */ /* Enable ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, sdhci_am654->itap_del_ena[timing] = 0x1;
1 << ITAPDLYENA_SHIFT);
for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);
for (itap = 0; itap < ITAP_MAX; itap++) { curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL);
sdhci_am654_write_itapdly(sdhci_am654, itap);
cur_val = !mmc_send_tuning(host->mmc, opcode, NULL); if (!curr_pass && prev_pass)
if (cur_val && !prev_val) fail_window[fail_index].start = itap;
pass_window = itap;
if (!cur_val) if (!curr_pass) {
fail_len++; fail_window[fail_index].end = itap;
fail_window[fail_index].length++;
}
if (curr_pass && !prev_pass)
fail_index++;
prev_val = cur_val; prev_pass = curr_pass;
} }
/*
* Having determined the length of the failing window and start of if (fail_window[fail_index].length != 0)
* the passing window calculate the length of the passing window and fail_index++;
* set the final value halfway through it considering the range as a
* circular buffer itap = sdhci_am654_calculate_itap(host, fail_window, fail_index,
*/ sdhci_am654->dll_enable);
pass_len = ITAP_MAX - fail_len;
itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);
sdhci_am654_write_itapdly(sdhci_am654, itap);
/* Save ITAPDLY */
sdhci_am654->itap_del_sel[timing] = itap;
return 0; return 0;
} }
static struct sdhci_ops sdhci_am654_ops = { static const struct sdhci_ops sdhci_am654_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning, .platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
...@@ -476,7 +573,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = { ...@@ -476,7 +573,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT, .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
}; };
static struct sdhci_ops sdhci_j721e_8bit_ops = { static const struct sdhci_ops sdhci_j721e_8bit_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning, .platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
...@@ -500,7 +597,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { ...@@ -500,7 +597,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
.flags = DLL_PRESENT | DLL_CALIB, .flags = DLL_PRESENT | DLL_CALIB,
}; };
static struct sdhci_ops sdhci_j721e_4bit_ops = { static const struct sdhci_ops sdhci_j721e_4bit_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning, .platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
...@@ -590,9 +687,12 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, ...@@ -590,9 +687,12 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
host->mmc->caps2 &= ~td[i].capability; host->mmc->caps2 &= ~td[i].capability;
} }
if (td[i].itap_binding) if (td[i].itap_binding) {
device_property_read_u32(dev, td[i].itap_binding, ret = device_property_read_u32(dev, td[i].itap_binding,
&sdhci_am654->itap_del_sel[i]); &sdhci_am654->itap_del_sel[i]);
if (!ret)
sdhci_am654->itap_del_ena[i] = 0x1;
}
} }
return 0; return 0;
......
...@@ -2667,29 +2667,10 @@ static struct sdio_driver ath10k_sdio_driver = { ...@@ -2667,29 +2667,10 @@ static struct sdio_driver ath10k_sdio_driver = {
.probe = ath10k_sdio_probe, .probe = ath10k_sdio_probe,
.remove = ath10k_sdio_remove, .remove = ath10k_sdio_remove,
.drv = { .drv = {
.owner = THIS_MODULE,
.pm = ATH10K_SDIO_PM_OPS, .pm = ATH10K_SDIO_PM_OPS,
}, },
}; };
module_sdio_driver(ath10k_sdio_driver);
static int __init ath10k_sdio_init(void)
{
int ret;
ret = sdio_register_driver(&ath10k_sdio_driver);
if (ret)
pr_err("sdio driver registration failed: %d\n", ret);
return ret;
}
static void __exit ath10k_sdio_exit(void)
{
sdio_unregister_driver(&ath10k_sdio_driver);
}
module_init(ath10k_sdio_init);
module_exit(ath10k_sdio_exit);
MODULE_AUTHOR("Qualcomm Atheros"); MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices"); MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices");
......
...@@ -1238,7 +1238,6 @@ static struct sdio_driver brcmf_sdmmc_driver = { ...@@ -1238,7 +1238,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.id_table = brcmf_sdmmc_ids, .id_table = brcmf_sdmmc_ids,
.drv = { .drv = {
.owner = THIS_MODULE,
.pm = pm_sleep_ptr(&brcmf_sdio_pm_ops), .pm = pm_sleep_ptr(&brcmf_sdio_pm_ops),
.coredump = brcmf_dev_coredump, .coredump = brcmf_dev_coredump,
}, },
......
...@@ -979,7 +979,6 @@ static struct sdio_driver mwifiex_sdio = { ...@@ -979,7 +979,6 @@ static struct sdio_driver mwifiex_sdio = {
.probe = mwifiex_sdio_probe, .probe = mwifiex_sdio_probe,
.remove = mwifiex_sdio_remove, .remove = mwifiex_sdio_remove,
.drv = { .drv = {
.owner = THIS_MODULE,
.coredump = mwifiex_sdio_coredump, .coredump = mwifiex_sdio_coredump,
.pm = &mwifiex_sdio_pm_ops, .pm = &mwifiex_sdio_pm_ops,
} }
......
...@@ -267,7 +267,6 @@ struct sdio_driver wfx_sdio_driver = { ...@@ -267,7 +267,6 @@ struct sdio_driver wfx_sdio_driver = {
.probe = wfx_sdio_probe, .probe = wfx_sdio_probe,
.remove = wfx_sdio_remove, .remove = wfx_sdio_remove,
.drv = { .drv = {
.owner = THIS_MODULE,
.of_match_table = wfx_sdio_of_match, .of_match_table = wfx_sdio_of_match,
} }
}; };
...@@ -106,7 +106,10 @@ struct sdio_driver { ...@@ -106,7 +106,10 @@ struct sdio_driver {
.class = (dev_class), \ .class = (dev_class), \
.vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID .vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID
extern int sdio_register_driver(struct sdio_driver *); /* use a macro to avoid include chaining to get THIS_MODULE */
#define sdio_register_driver(drv) \
__sdio_register_driver(drv, THIS_MODULE)
extern int __sdio_register_driver(struct sdio_driver *, struct module *);
extern void sdio_unregister_driver(struct sdio_driver *); extern void sdio_unregister_driver(struct sdio_driver *);
/** /**
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#ifndef MMC_SLOT_GPIO_H #ifndef MMC_SLOT_GPIO_H
#define MMC_SLOT_GPIO_H #define MMC_SLOT_GPIO_H
#include <linux/interrupt.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/irqreturn.h>
struct mmc_host; struct mmc_host;
...@@ -21,8 +21,8 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, ...@@ -21,8 +21,8 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
unsigned int debounce); unsigned int debounce);
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
unsigned int idx, unsigned int debounce); unsigned int idx, unsigned int debounce);
void mmc_gpio_set_cd_isr(struct mmc_host *host, int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config);
irqreturn_t (*isr)(int irq, void *dev_id)); void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr);
int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on); int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on);
void mmc_gpiod_request_cd_irq(struct mmc_host *host); void mmc_gpiod_request_cd_irq(struct mmc_host *host);
bool mmc_can_gpio_cd(struct mmc_host *host); bool mmc_can_gpio_cd(struct mmc_host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment