]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mfd/rtsx_pcr.c
Merge remote-tracking branch 'mfd-lj/for-mfd-next'
[karo-tx-linux.git] / drivers / mfd / rtsx_pcr.c
index dd186c4103c1e4f6ad9dc690879fa161489a8b2c..11e20afbdcacb7d31e49798db6d2dfbf0504afd8 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/pci.h>
@@ -73,6 +72,9 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
                pcr->state = PDEV_STAT_RUN;
                if (pcr->ops->enable_auto_blink)
                        pcr->ops->enable_auto_blink(pcr);
+
+               if (pcr->aspm_en)
+                       rtsx_pci_write_config_byte(pcr, LCTLR, 0);
        }
 
        mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
@@ -717,7 +719,7 @@ int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
                [RTSX_MS_CARD] = MS_EXIST
        };
 
-       if (!pcr->ms_pmos) {
+       if (!(pcr->flags & PCR_MS_PMOS)) {
                /* When using single PMOS, accessing card is not permitted
                 * if the existing card is not the designated one.
                 */
@@ -918,9 +920,27 @@ static void rtsx_pci_idle_work(struct work_struct *work)
        if (pcr->ops->turn_off_led)
                pcr->ops->turn_off_led(pcr);
 
+       if (pcr->aspm_en)
+               rtsx_pci_write_config_byte(pcr, LCTLR, pcr->aspm_en);
+
        mutex_unlock(&pcr->pcr_mutex);
 }
 
+static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       if (pcr->ops->turn_off_led)
+               pcr->ops->turn_off_led(pcr);
+
+       rtsx_pci_writel(pcr, RTSX_BIER, 0);
+       pcr->bier = 0;
+
+       rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08);
+       rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
+
+       if (pcr->ops->force_power_down)
+               pcr->ops->force_power_down(pcr, pm_state);
+}
+
 static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
 {
        int err;
@@ -951,13 +971,11 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00);
        /* Disable card clock */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0);
-       /* Reset ASPM state to default value */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
        /* Reset delink mode */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0);
        /* Card driving select */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-                       0x07, DRIVER_TYPE_D);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL,
+                       0xFF, pcr->card_drive_sel);
        /* Enable SSC Clock */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1,
                        0xFF, SSC_8X_EN | SSC_SEL_4M);
@@ -982,13 +1000,13 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
         *      0: ELBI interrupt flag[31:22] & [7:0] only can be write clear
         */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0);
-       /* Force CLKREQ# PIN to drive 0 to request clock */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
 
        err = rtsx_pci_send_cmd(pcr, 100);
        if (err < 0)
                return err;
 
+       rtsx_pci_write_config_byte(pcr, LCTLR, 0);
+
        /* Enable clk_request_n to enable clock power management */
        rtsx_pci_write_config_byte(pcr, 0x81, 1);
        /* Enter L1 when host tx idle */
@@ -1053,6 +1071,18 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
        if (!pcr->slots)
                return -ENOMEM;
 
+       if (pcr->ops->fetch_vendor_settings)
+               pcr->ops->fetch_vendor_settings(pcr);
+
+       dev_dbg(&(pcr->pci->dev), "pcr->aspm_en = 0x%x\n", pcr->aspm_en);
+       dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_1v8 = 0x%x\n",
+                       pcr->sd30_drive_sel_1v8);
+       dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_3v3 = 0x%x\n",
+                       pcr->sd30_drive_sel_3v3);
+       dev_dbg(&(pcr->pci->dev), "pcr->card_drive_sel = 0x%x\n",
+                       pcr->card_drive_sel);
+       dev_dbg(&(pcr->pci->dev), "pcr->flags = 0x%x\n", pcr->flags);
+
        pcr->state = PDEV_STAT_IDLE;
        err = rtsx_pci_init_hw(pcr);
        if (err < 0) {
@@ -1119,7 +1149,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
        pcr->remap_addr = ioremap_nocache(base, len);
        if (!pcr->remap_addr) {
                ret = -ENOMEM;
-               goto free_host;
+               goto free_handle;
        }
 
        pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev),
@@ -1179,8 +1209,6 @@ disable_msi:
                        pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
 unmap:
        iounmap(pcr->remap_addr);
-free_host:
-       dev_set_drvdata(&pcidev->dev, NULL);
 free_handle:
        kfree(handle);
 free_pcr:
@@ -1212,7 +1240,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
                pci_disable_msi(pcr->pci);
        iounmap(pcr->remap_addr);
 
-       dev_set_drvdata(&pcidev->dev, NULL);
        pci_release_regions(pcidev);
        pci_disable_device(pcidev);
 
@@ -1235,7 +1262,6 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
 {
        struct pcr_handle *handle;
        struct rtsx_pcr *pcr;
-       int ret = 0;
 
        dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
@@ -1247,14 +1273,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
 
        mutex_lock(&pcr->pcr_mutex);
 
-       if (pcr->ops->turn_off_led)
-               pcr->ops->turn_off_led(pcr);
-
-       rtsx_pci_writel(pcr, RTSX_BIER, 0);
-       pcr->bier = 0;
-
-       rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08);
-       rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02);
+       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
        pci_save_state(pcidev);
        pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
@@ -1262,7 +1281,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
        pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
 
        mutex_unlock(&pcr->pcr_mutex);
-       return ret;
+       return 0;
 }
 
 static int rtsx_pci_resume(struct pci_dev *pcidev)
@@ -1300,10 +1319,25 @@ out:
        return ret;
 }
 
+static void rtsx_pci_shutdown(struct pci_dev *pcidev)
+{
+       struct pcr_handle *handle;
+       struct rtsx_pcr *pcr;
+
+       dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+
+       handle = pci_get_drvdata(pcidev);
+       pcr = handle->pcr;
+       rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+
+       pci_disable_device(pcidev);
+}
+
 #else /* CONFIG_PM */
 
 #define rtsx_pci_suspend NULL
 #define rtsx_pci_resume NULL
+#define rtsx_pci_shutdown NULL
 
 #endif /* CONFIG_PM */
 
@@ -1314,6 +1348,7 @@ static struct pci_driver rtsx_pci_driver = {
        .remove = rtsx_pci_remove,
        .suspend = rtsx_pci_suspend,
        .resume = rtsx_pci_resume,
+       .shutdown = rtsx_pci_shutdown,
 };
 module_pci_driver(rtsx_pci_driver);