]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'srini/qcomlt-4.4-wcnss-q6v5-sync' into release/qcomlt-4.4
authorNicolas Dechesne <nicolas.dechesne@linaro.org>
Thu, 23 Jun 2016 13:39:23 +0000 (15:39 +0200)
committerNicolas Dechesne <nicolas.dechesne@linaro.org>
Thu, 23 Jun 2016 13:39:23 +0000 (15:39 +0200)
drivers/mmc/host/sdhci-msm.c
drivers/regulator/qcom_smd-regulator.c

index edb71cb9e5f7361b68f52ddae00df515e68e3dd4..68184c7f80895ac87df6d5e31397640cc6724414 100644 (file)
 
 #define CORE_HC_MODE           0x78
 #define HC_MODE_EN             0x1
+
 #define CORE_POWER             0x0
 #define CORE_SW_RST            BIT(7)
 
+#define CORE_PWRCTL_STATUS     0xdc
+#define CORE_PWRCTL_MASK       0xe0
+#define CORE_PWRCTL_CLEAR      0xe4
+#define CORE_PWRCTL_CTL                0xe8
+
+#define CORE_PWRCTL_BUS_OFF    BIT(0)
+#define CORE_PWRCTL_BUS_ON     BIT(1)
+#define CORE_PWRCTL_IO_LOW     BIT(2)
+#define CORE_PWRCTL_IO_HIGH    BIT(3)
+#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
+#define CORE_PWRCTL_IO_SUCCESS BIT(2)
+#define REQ_BUS_OFF            BIT(0)
+#define REQ_BUS_ON             BIT(1)
+#define REQ_IO_LOW             BIT(2)
+#define REQ_IO_HIGH            BIT(3)
+
+#define INT_MASK               0xf
 #define MAX_PHASES             16
 #define CORE_DLL_LOCK          BIT(7)
 #define CORE_DLL_EN            BIT(16)
 struct sdhci_msm_host {
        struct platform_device *pdev;
        void __iomem *core_mem; /* MSM SDCC mapped address */
+       int pwr_irq;            /* power irq */
        struct clk *clk;        /* main SD/MMC bus clock */
        struct clk *pclk;       /* SDHC peripheral bus clock */
        struct clk *bus_clk;    /* SDHC bus voter clock */
        struct mmc_host *mmc;
-       struct sdhci_pltfm_data sdhci_msm_pdata;
 };
 
 /* Platform specific tuning */
@@ -411,6 +429,39 @@ retry:
        return rc;
 }
 
+static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       u32 irq_status, irq_ack = 0;
+
+       irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+       irq_status &= INT_MASK;
+
+       writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+
+       if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+               irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+       if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
+               irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+
+       /*
+        * The driver has to acknowledge the interrupt, switch voltages and
+        * report back if it succeded or not to this register. The voltage
+        * switches are handled by the sdhci core, so just report success.
+        */
+       writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+}
+
+static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
+{
+       struct sdhci_host *host = (struct sdhci_host *)data;
+
+       sdhci_msm_voltage_switch(host);
+
+       return IRQ_HANDLED;
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
        { .compatible = "qcom,sdhci-msm-v4" },
        {},
@@ -418,12 +469,20 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
 
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
-static struct sdhci_ops sdhci_msm_ops = {
+static const struct sdhci_ops sdhci_msm_ops = {
        .platform_execute_tuning = sdhci_msm_execute_tuning,
        .reset = sdhci_reset,
        .set_clock = sdhci_set_clock,
        .set_bus_width = sdhci_set_bus_width,
        .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .voltage_switch = sdhci_msm_voltage_switch,
+};
+
+static const struct sdhci_pltfm_data sdhci_msm_pdata = {
+       .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                 SDHCI_QUIRK_SINGLE_POWER_WRITE |
+                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       .ops = &sdhci_msm_ops,
 };
 
 static int sdhci_msm_probe(struct platform_device *pdev)
@@ -437,17 +496,12 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        u32 core_version, caps;
        u8 core_major;
 
-       msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
-       if (!msm_host)
-               return -ENOMEM;
-
-       msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
-       host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
+       host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
        if (IS_ERR(host))
                return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
-       pltfm_host->priv = msm_host;
+       msm_host = sdhci_pltfm_priv(pltfm_host);
        msm_host->mmc = host->mmc;
        msm_host->pdev = pdev;
 
@@ -522,10 +576,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        /* Set HC_MODE_EN bit in HC_MODE register */
        writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
-       host->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
-       host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-       host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
-
        host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
        dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
                host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
@@ -549,6 +599,22 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                               CORE_VENDOR_SPEC_CAPABILITIES0);
        }
 
+       /* Setup IRQ for handling power/voltage tasks with PMIC */
+       msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+       if (msm_host->pwr_irq < 0) {
+               dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
+                       msm_host->pwr_irq);
+               goto clk_disable;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
+                                       sdhci_msm_pwr_irq, IRQF_ONESHOT,
+                                       dev_name(&pdev->dev), host);
+       if (ret) {
+               dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
+               goto clk_disable;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto clk_disable;
@@ -571,16 +637,16 @@ static int sdhci_msm_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_msm_host *msm_host = pltfm_host->priv;
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
        int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
                    0xffffffff);
 
        sdhci_remove_host(host, dead);
-       sdhci_pltfm_free(pdev);
        clk_disable_unprepare(msm_host->clk);
        clk_disable_unprepare(msm_host->pclk);
        if (!IS_ERR(msm_host->bus_clk))
                clk_disable_unprepare(msm_host->bus_clk);
+       sdhci_pltfm_free(pdev);
        return 0;
 }
 
index e310300beaead5ef3384db13b67aa6f6aa8baecc..9faef1de185655447ca8ed9df91ea23c00b1c005 100644 (file)
@@ -192,6 +192,18 @@ static const struct regulator_ops rpm_smps_ldo_ops = {
        .enable = rpm_reg_enable,
        .disable = rpm_reg_disable,
        .is_enabled = rpm_reg_is_enabled,
+       .list_voltage = regulator_list_voltage_linear_range,
+
+       .get_voltage = rpm_reg_get_voltage,
+       .set_voltage = rpm_reg_set_voltage,
+
+       .set_load = rpm_reg_set_load,
+};
+
+static const struct regulator_ops rpm_smps_ldo_ops_fixed = {
+       .enable = rpm_reg_enable,
+       .disable = rpm_reg_disable,
+       .is_enabled = rpm_reg_is_enabled,
 
        .get_voltage = rpm_reg_get_voltage,
        .set_voltage = rpm_reg_set_voltage,
@@ -299,7 +311,7 @@ static const struct regulator_desc pm8941_nldo = {
 static const struct regulator_desc pm8941_lnldo = {
        .fixed_uV = 1740000,
        .n_voltages = 1,
-       .ops = &rpm_smps_ldo_ops,
+       .ops = &rpm_smps_ldo_ops_fixed,
 };
 
 static const struct regulator_desc pm8941_switch = {