10eb0d9f4SGeorgi Djakov /* 20eb0d9f4SGeorgi Djakov * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver 30eb0d9f4SGeorgi Djakov * 40eb0d9f4SGeorgi Djakov * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. 50eb0d9f4SGeorgi Djakov * 60eb0d9f4SGeorgi Djakov * This program is free software; you can redistribute it and/or modify 70eb0d9f4SGeorgi Djakov * it under the terms of the GNU General Public License version 2 and 80eb0d9f4SGeorgi Djakov * only version 2 as published by the Free Software Foundation. 90eb0d9f4SGeorgi Djakov * 100eb0d9f4SGeorgi Djakov * This program is distributed in the hope that it will be useful, 110eb0d9f4SGeorgi Djakov * but WITHOUT ANY WARRANTY; without even the implied warranty of 120eb0d9f4SGeorgi Djakov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 130eb0d9f4SGeorgi Djakov * GNU General Public License for more details. 140eb0d9f4SGeorgi Djakov * 150eb0d9f4SGeorgi Djakov */ 160eb0d9f4SGeorgi Djakov 170eb0d9f4SGeorgi Djakov #include <linux/module.h> 180eb0d9f4SGeorgi Djakov #include <linux/of_device.h> 190eb0d9f4SGeorgi Djakov #include <linux/delay.h> 20415b5a75SGeorgi Djakov #include <linux/mmc/mmc.h> 2167e6db11SPramod Gurav #include <linux/pm_runtime.h> 22415b5a75SGeorgi Djakov #include <linux/slab.h> 230eb0d9f4SGeorgi Djakov 240eb0d9f4SGeorgi Djakov #include "sdhci-pltfm.h" 250eb0d9f4SGeorgi Djakov 263a3ad3e9SGeorgi Djakov #define CORE_MCI_VERSION 0x50 273a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_SHIFT 28 283a3ad3e9SGeorgi Djakov #define CORE_VERSION_MAJOR_MASK (0xf << CORE_VERSION_MAJOR_SHIFT) 293a3ad3e9SGeorgi Djakov #define CORE_VERSION_MINOR_MASK 0xff 303a3ad3e9SGeorgi Djakov 310eb0d9f4SGeorgi Djakov #define CORE_HC_MODE 0x78 320eb0d9f4SGeorgi Djakov #define HC_MODE_EN 0x1 330eb0d9f4SGeorgi Djakov #define CORE_POWER 0x0 340eb0d9f4SGeorgi Djakov #define CORE_SW_RST BIT(7) 35ff06ce41SVenkat Gopalakrishnan #define FF_CLK_SW_RST_DIS BIT(13) 360eb0d9f4SGeorgi Djakov 37ad81d387SGeorgi Djakov #define CORE_PWRCTL_STATUS 0xdc 38ad81d387SGeorgi Djakov #define CORE_PWRCTL_MASK 0xe0 39ad81d387SGeorgi Djakov #define CORE_PWRCTL_CLEAR 0xe4 40ad81d387SGeorgi Djakov #define CORE_PWRCTL_CTL 0xe8 41ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_OFF BIT(0) 42ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_ON BIT(1) 43ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_LOW BIT(2) 44ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_HIGH BIT(3) 45ad81d387SGeorgi Djakov #define CORE_PWRCTL_BUS_SUCCESS BIT(0) 46ad81d387SGeorgi Djakov #define CORE_PWRCTL_IO_SUCCESS BIT(2) 47ad81d387SGeorgi Djakov #define REQ_BUS_OFF BIT(0) 48ad81d387SGeorgi Djakov #define REQ_BUS_ON BIT(1) 49ad81d387SGeorgi Djakov #define REQ_IO_LOW BIT(2) 50ad81d387SGeorgi Djakov #define REQ_IO_HIGH BIT(3) 51ad81d387SGeorgi Djakov #define INT_MASK 0xf 52415b5a75SGeorgi Djakov #define MAX_PHASES 16 53415b5a75SGeorgi Djakov #define CORE_DLL_LOCK BIT(7) 54415b5a75SGeorgi Djakov #define CORE_DLL_EN BIT(16) 55415b5a75SGeorgi Djakov #define CORE_CDR_EN BIT(17) 56415b5a75SGeorgi Djakov #define CORE_CK_OUT_EN BIT(18) 57415b5a75SGeorgi Djakov #define CORE_CDR_EXT_EN BIT(19) 58415b5a75SGeorgi Djakov #define CORE_DLL_PDN BIT(29) 59415b5a75SGeorgi Djakov #define CORE_DLL_RST BIT(30) 60415b5a75SGeorgi Djakov #define CORE_DLL_CONFIG 0x100 61415b5a75SGeorgi Djakov #define CORE_DLL_STATUS 0x108 62415b5a75SGeorgi Djakov 6383736352SVenkat Gopalakrishnan #define CORE_DLL_CONFIG_2 0x1b4 6483736352SVenkat Gopalakrishnan #define CORE_FLL_CYCLE_CNT BIT(18) 6583736352SVenkat Gopalakrishnan #define CORE_DLL_CLOCK_DISABLE BIT(21) 6683736352SVenkat Gopalakrishnan 67415b5a75SGeorgi Djakov #define CORE_VENDOR_SPEC 0x10c 68415b5a75SGeorgi Djakov #define CORE_CLK_PWRSAVE BIT(1) 69ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_DFLT (2 << 8) 70ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_HS400 (3 << 8) 71ff06ce41SVenkat Gopalakrishnan #define CORE_HC_MCLK_SEL_MASK (3 << 8) 72ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_EN BIT(18) 73ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_HS400 (6 << 19) 74ff06ce41SVenkat Gopalakrishnan #define CORE_HC_SELECT_IN_MASK (7 << 19) 75415b5a75SGeorgi Djakov 763a3ad3e9SGeorgi Djakov #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c 773a3ad3e9SGeorgi Djakov 7880031bdeSRitesh Harjani #define SDHCI_MSM_MIN_CLOCK 400000 79ff06ce41SVenkat Gopalakrishnan #define CORE_FREQ_100MHZ (100 * 1000 * 1000) 8080031bdeSRitesh Harjani 81415b5a75SGeorgi Djakov #define CDR_SELEXT_SHIFT 20 82415b5a75SGeorgi Djakov #define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT) 83415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_SHIFT 24 84415b5a75SGeorgi Djakov #define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT) 85415b5a75SGeorgi Djakov 8667e6db11SPramod Gurav #define MSM_MMC_AUTOSUSPEND_DELAY_MS 50 870eb0d9f4SGeorgi Djakov struct sdhci_msm_host { 880eb0d9f4SGeorgi Djakov struct platform_device *pdev; 890eb0d9f4SGeorgi Djakov void __iomem *core_mem; /* MSM SDCC mapped address */ 90ad81d387SGeorgi Djakov int pwr_irq; /* power irq */ 910eb0d9f4SGeorgi Djakov struct clk *clk; /* main SD/MMC bus clock */ 920eb0d9f4SGeorgi Djakov struct clk *pclk; /* SDHC peripheral bus clock */ 930eb0d9f4SGeorgi Djakov struct clk *bus_clk; /* SDHC bus voter clock */ 9483736352SVenkat Gopalakrishnan struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/ 95edc609fdSRitesh Harjani unsigned long clk_rate; 960eb0d9f4SGeorgi Djakov struct mmc_host *mmc; 9783736352SVenkat Gopalakrishnan bool use_14lpp_dll_reset; 98ff06ce41SVenkat Gopalakrishnan bool tuning_done; 99ff06ce41SVenkat Gopalakrishnan bool calibration_done; 1000eb0d9f4SGeorgi Djakov }; 1010eb0d9f4SGeorgi Djakov 1020eb0d9f4SGeorgi Djakov /* Platform specific tuning */ 103415b5a75SGeorgi Djakov static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) 104415b5a75SGeorgi Djakov { 105415b5a75SGeorgi Djakov u32 wait_cnt = 50; 106415b5a75SGeorgi Djakov u8 ck_out_en; 107415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 108415b5a75SGeorgi Djakov 109415b5a75SGeorgi Djakov /* Poll for CK_OUT_EN bit. max. poll time = 50us */ 110415b5a75SGeorgi Djakov ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & 111415b5a75SGeorgi Djakov CORE_CK_OUT_EN); 112415b5a75SGeorgi Djakov 113415b5a75SGeorgi Djakov while (ck_out_en != poll) { 114415b5a75SGeorgi Djakov if (--wait_cnt == 0) { 115415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n", 116415b5a75SGeorgi Djakov mmc_hostname(mmc), poll); 117415b5a75SGeorgi Djakov return -ETIMEDOUT; 118415b5a75SGeorgi Djakov } 119415b5a75SGeorgi Djakov udelay(1); 120415b5a75SGeorgi Djakov 121415b5a75SGeorgi Djakov ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & 122415b5a75SGeorgi Djakov CORE_CK_OUT_EN); 123415b5a75SGeorgi Djakov } 124415b5a75SGeorgi Djakov 125415b5a75SGeorgi Djakov return 0; 126415b5a75SGeorgi Djakov } 127415b5a75SGeorgi Djakov 128415b5a75SGeorgi Djakov static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) 129415b5a75SGeorgi Djakov { 130415b5a75SGeorgi Djakov int rc; 131415b5a75SGeorgi Djakov static const u8 grey_coded_phase_table[] = { 132415b5a75SGeorgi Djakov 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 133415b5a75SGeorgi Djakov 0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8 134415b5a75SGeorgi Djakov }; 135415b5a75SGeorgi Djakov unsigned long flags; 136415b5a75SGeorgi Djakov u32 config; 137415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 138415b5a75SGeorgi Djakov 139415b5a75SGeorgi Djakov spin_lock_irqsave(&host->lock, flags); 140415b5a75SGeorgi Djakov 141415b5a75SGeorgi Djakov config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 142415b5a75SGeorgi Djakov config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN); 143415b5a75SGeorgi Djakov config |= (CORE_CDR_EXT_EN | CORE_DLL_EN); 144415b5a75SGeorgi Djakov writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 145415b5a75SGeorgi Djakov 146415b5a75SGeorgi Djakov /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */ 147415b5a75SGeorgi Djakov rc = msm_dll_poll_ck_out_en(host, 0); 148415b5a75SGeorgi Djakov if (rc) 149415b5a75SGeorgi Djakov goto err_out; 150415b5a75SGeorgi Djakov 151415b5a75SGeorgi Djakov /* 152415b5a75SGeorgi Djakov * Write the selected DLL clock output phase (0 ... 15) 153415b5a75SGeorgi Djakov * to CDR_SELEXT bit field of DLL_CONFIG register. 154415b5a75SGeorgi Djakov */ 155415b5a75SGeorgi Djakov config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 156415b5a75SGeorgi Djakov config &= ~CDR_SELEXT_MASK; 157415b5a75SGeorgi Djakov config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT; 158415b5a75SGeorgi Djakov writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 159415b5a75SGeorgi Djakov 16029301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 16129301f40SRitesh Harjani config |= CORE_CK_OUT_EN; 16229301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 163415b5a75SGeorgi Djakov 164415b5a75SGeorgi Djakov /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */ 165415b5a75SGeorgi Djakov rc = msm_dll_poll_ck_out_en(host, 1); 166415b5a75SGeorgi Djakov if (rc) 167415b5a75SGeorgi Djakov goto err_out; 168415b5a75SGeorgi Djakov 169415b5a75SGeorgi Djakov config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 170415b5a75SGeorgi Djakov config |= CORE_CDR_EN; 171415b5a75SGeorgi Djakov config &= ~CORE_CDR_EXT_EN; 172415b5a75SGeorgi Djakov writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 173415b5a75SGeorgi Djakov goto out; 174415b5a75SGeorgi Djakov 175415b5a75SGeorgi Djakov err_out: 176415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n", 177415b5a75SGeorgi Djakov mmc_hostname(mmc), phase); 178415b5a75SGeorgi Djakov out: 179415b5a75SGeorgi Djakov spin_unlock_irqrestore(&host->lock, flags); 180415b5a75SGeorgi Djakov return rc; 181415b5a75SGeorgi Djakov } 182415b5a75SGeorgi Djakov 183415b5a75SGeorgi Djakov /* 184415b5a75SGeorgi Djakov * Find out the greatest range of consecuitive selected 185415b5a75SGeorgi Djakov * DLL clock output phases that can be used as sampling 186415b5a75SGeorgi Djakov * setting for SD3.0 UHS-I card read operation (in SDR104 187ff06ce41SVenkat Gopalakrishnan * timing mode) or for eMMC4.5 card read operation (in 188ff06ce41SVenkat Gopalakrishnan * HS400/HS200 timing mode). 189415b5a75SGeorgi Djakov * Select the 3/4 of the range and configure the DLL with the 190415b5a75SGeorgi Djakov * selected DLL clock output phase. 191415b5a75SGeorgi Djakov */ 192415b5a75SGeorgi Djakov 193415b5a75SGeorgi Djakov static int msm_find_most_appropriate_phase(struct sdhci_host *host, 194415b5a75SGeorgi Djakov u8 *phase_table, u8 total_phases) 195415b5a75SGeorgi Djakov { 196415b5a75SGeorgi Djakov int ret; 197415b5a75SGeorgi Djakov u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} }; 198415b5a75SGeorgi Djakov u8 phases_per_row[MAX_PHASES] = { 0 }; 199415b5a75SGeorgi Djakov int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0; 200415b5a75SGeorgi Djakov int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0; 201415b5a75SGeorgi Djakov bool phase_0_found = false, phase_15_found = false; 202415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 203415b5a75SGeorgi Djakov 204415b5a75SGeorgi Djakov if (!total_phases || (total_phases > MAX_PHASES)) { 205415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n", 206415b5a75SGeorgi Djakov mmc_hostname(mmc), total_phases); 207415b5a75SGeorgi Djakov return -EINVAL; 208415b5a75SGeorgi Djakov } 209415b5a75SGeorgi Djakov 210415b5a75SGeorgi Djakov for (cnt = 0; cnt < total_phases; cnt++) { 211415b5a75SGeorgi Djakov ranges[row_index][col_index] = phase_table[cnt]; 212415b5a75SGeorgi Djakov phases_per_row[row_index] += 1; 213415b5a75SGeorgi Djakov col_index++; 214415b5a75SGeorgi Djakov 215415b5a75SGeorgi Djakov if ((cnt + 1) == total_phases) { 216415b5a75SGeorgi Djakov continue; 217415b5a75SGeorgi Djakov /* check if next phase in phase_table is consecutive or not */ 218415b5a75SGeorgi Djakov } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) { 219415b5a75SGeorgi Djakov row_index++; 220415b5a75SGeorgi Djakov col_index = 0; 221415b5a75SGeorgi Djakov } 222415b5a75SGeorgi Djakov } 223415b5a75SGeorgi Djakov 224415b5a75SGeorgi Djakov if (row_index >= MAX_PHASES) 225415b5a75SGeorgi Djakov return -EINVAL; 226415b5a75SGeorgi Djakov 227415b5a75SGeorgi Djakov /* Check if phase-0 is present in first valid window? */ 228415b5a75SGeorgi Djakov if (!ranges[0][0]) { 229415b5a75SGeorgi Djakov phase_0_found = true; 230415b5a75SGeorgi Djakov phase_0_raw_index = 0; 231415b5a75SGeorgi Djakov /* Check if cycle exist between 2 valid windows */ 232415b5a75SGeorgi Djakov for (cnt = 1; cnt <= row_index; cnt++) { 233415b5a75SGeorgi Djakov if (phases_per_row[cnt]) { 234415b5a75SGeorgi Djakov for (i = 0; i < phases_per_row[cnt]; i++) { 235415b5a75SGeorgi Djakov if (ranges[cnt][i] == 15) { 236415b5a75SGeorgi Djakov phase_15_found = true; 237415b5a75SGeorgi Djakov phase_15_raw_index = cnt; 238415b5a75SGeorgi Djakov break; 239415b5a75SGeorgi Djakov } 240415b5a75SGeorgi Djakov } 241415b5a75SGeorgi Djakov } 242415b5a75SGeorgi Djakov } 243415b5a75SGeorgi Djakov } 244415b5a75SGeorgi Djakov 245415b5a75SGeorgi Djakov /* If 2 valid windows form cycle then merge them as single window */ 246415b5a75SGeorgi Djakov if (phase_0_found && phase_15_found) { 247415b5a75SGeorgi Djakov /* number of phases in raw where phase 0 is present */ 248415b5a75SGeorgi Djakov u8 phases_0 = phases_per_row[phase_0_raw_index]; 249415b5a75SGeorgi Djakov /* number of phases in raw where phase 15 is present */ 250415b5a75SGeorgi Djakov u8 phases_15 = phases_per_row[phase_15_raw_index]; 251415b5a75SGeorgi Djakov 252415b5a75SGeorgi Djakov if (phases_0 + phases_15 >= MAX_PHASES) 253415b5a75SGeorgi Djakov /* 254415b5a75SGeorgi Djakov * If there are more than 1 phase windows then total 255415b5a75SGeorgi Djakov * number of phases in both the windows should not be 256415b5a75SGeorgi Djakov * more than or equal to MAX_PHASES. 257415b5a75SGeorgi Djakov */ 258415b5a75SGeorgi Djakov return -EINVAL; 259415b5a75SGeorgi Djakov 260415b5a75SGeorgi Djakov /* Merge 2 cyclic windows */ 261415b5a75SGeorgi Djakov i = phases_15; 262415b5a75SGeorgi Djakov for (cnt = 0; cnt < phases_0; cnt++) { 263415b5a75SGeorgi Djakov ranges[phase_15_raw_index][i] = 264415b5a75SGeorgi Djakov ranges[phase_0_raw_index][cnt]; 265415b5a75SGeorgi Djakov if (++i >= MAX_PHASES) 266415b5a75SGeorgi Djakov break; 267415b5a75SGeorgi Djakov } 268415b5a75SGeorgi Djakov 269415b5a75SGeorgi Djakov phases_per_row[phase_0_raw_index] = 0; 270415b5a75SGeorgi Djakov phases_per_row[phase_15_raw_index] = phases_15 + phases_0; 271415b5a75SGeorgi Djakov } 272415b5a75SGeorgi Djakov 273415b5a75SGeorgi Djakov for (cnt = 0; cnt <= row_index; cnt++) { 274415b5a75SGeorgi Djakov if (phases_per_row[cnt] > curr_max) { 275415b5a75SGeorgi Djakov curr_max = phases_per_row[cnt]; 276415b5a75SGeorgi Djakov selected_row_index = cnt; 277415b5a75SGeorgi Djakov } 278415b5a75SGeorgi Djakov } 279415b5a75SGeorgi Djakov 280415b5a75SGeorgi Djakov i = (curr_max * 3) / 4; 281415b5a75SGeorgi Djakov if (i) 282415b5a75SGeorgi Djakov i--; 283415b5a75SGeorgi Djakov 284415b5a75SGeorgi Djakov ret = ranges[selected_row_index][i]; 285415b5a75SGeorgi Djakov 286415b5a75SGeorgi Djakov if (ret >= MAX_PHASES) { 287415b5a75SGeorgi Djakov ret = -EINVAL; 288415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n", 289415b5a75SGeorgi Djakov mmc_hostname(mmc), ret); 290415b5a75SGeorgi Djakov } 291415b5a75SGeorgi Djakov 292415b5a75SGeorgi Djakov return ret; 293415b5a75SGeorgi Djakov } 294415b5a75SGeorgi Djakov 295415b5a75SGeorgi Djakov static inline void msm_cm_dll_set_freq(struct sdhci_host *host) 296415b5a75SGeorgi Djakov { 297415b5a75SGeorgi Djakov u32 mclk_freq = 0, config; 298415b5a75SGeorgi Djakov 299415b5a75SGeorgi Djakov /* Program the MCLK value to MCLK_FREQ bit field */ 300415b5a75SGeorgi Djakov if (host->clock <= 112000000) 301415b5a75SGeorgi Djakov mclk_freq = 0; 302415b5a75SGeorgi Djakov else if (host->clock <= 125000000) 303415b5a75SGeorgi Djakov mclk_freq = 1; 304415b5a75SGeorgi Djakov else if (host->clock <= 137000000) 305415b5a75SGeorgi Djakov mclk_freq = 2; 306415b5a75SGeorgi Djakov else if (host->clock <= 150000000) 307415b5a75SGeorgi Djakov mclk_freq = 3; 308415b5a75SGeorgi Djakov else if (host->clock <= 162000000) 309415b5a75SGeorgi Djakov mclk_freq = 4; 310415b5a75SGeorgi Djakov else if (host->clock <= 175000000) 311415b5a75SGeorgi Djakov mclk_freq = 5; 312415b5a75SGeorgi Djakov else if (host->clock <= 187000000) 313415b5a75SGeorgi Djakov mclk_freq = 6; 314415b5a75SGeorgi Djakov else if (host->clock <= 200000000) 315415b5a75SGeorgi Djakov mclk_freq = 7; 316415b5a75SGeorgi Djakov 317415b5a75SGeorgi Djakov config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 318415b5a75SGeorgi Djakov config &= ~CMUX_SHIFT_PHASE_MASK; 319415b5a75SGeorgi Djakov config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT; 320415b5a75SGeorgi Djakov writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 321415b5a75SGeorgi Djakov } 322415b5a75SGeorgi Djakov 323415b5a75SGeorgi Djakov /* Initialize the DLL (Programmable Delay Line) */ 324415b5a75SGeorgi Djakov static int msm_init_cm_dll(struct sdhci_host *host) 325415b5a75SGeorgi Djakov { 326415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 32783736352SVenkat Gopalakrishnan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 32883736352SVenkat Gopalakrishnan struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 329415b5a75SGeorgi Djakov int wait_cnt = 50; 330415b5a75SGeorgi Djakov unsigned long flags; 33129301f40SRitesh Harjani u32 config; 332415b5a75SGeorgi Djakov 333415b5a75SGeorgi Djakov spin_lock_irqsave(&host->lock, flags); 334415b5a75SGeorgi Djakov 335415b5a75SGeorgi Djakov /* 336415b5a75SGeorgi Djakov * Make sure that clock is always enabled when DLL 337415b5a75SGeorgi Djakov * tuning is in progress. Keeping PWRSAVE ON may 338415b5a75SGeorgi Djakov * turn off the clock. 339415b5a75SGeorgi Djakov */ 34029301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); 34129301f40SRitesh Harjani config &= ~CORE_CLK_PWRSAVE; 34229301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); 343415b5a75SGeorgi Djakov 34483736352SVenkat Gopalakrishnan if (msm_host->use_14lpp_dll_reset) { 34583736352SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 34683736352SVenkat Gopalakrishnan config &= ~CORE_CK_OUT_EN; 34783736352SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 34883736352SVenkat Gopalakrishnan 34983736352SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); 35083736352SVenkat Gopalakrishnan config |= CORE_DLL_CLOCK_DISABLE; 35183736352SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); 35283736352SVenkat Gopalakrishnan } 35383736352SVenkat Gopalakrishnan 35429301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 35529301f40SRitesh Harjani config |= CORE_DLL_RST; 35629301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 357415b5a75SGeorgi Djakov 35829301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 35929301f40SRitesh Harjani config |= CORE_DLL_PDN; 36029301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 361415b5a75SGeorgi Djakov msm_cm_dll_set_freq(host); 362415b5a75SGeorgi Djakov 36383736352SVenkat Gopalakrishnan if (msm_host->use_14lpp_dll_reset && 36483736352SVenkat Gopalakrishnan !IS_ERR_OR_NULL(msm_host->xo_clk)) { 36583736352SVenkat Gopalakrishnan u32 mclk_freq = 0; 36683736352SVenkat Gopalakrishnan 36783736352SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); 36883736352SVenkat Gopalakrishnan config &= CORE_FLL_CYCLE_CNT; 36983736352SVenkat Gopalakrishnan if (config) 37083736352SVenkat Gopalakrishnan mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8), 37183736352SVenkat Gopalakrishnan clk_get_rate(msm_host->xo_clk)); 37283736352SVenkat Gopalakrishnan else 37383736352SVenkat Gopalakrishnan mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4), 37483736352SVenkat Gopalakrishnan clk_get_rate(msm_host->xo_clk)); 37583736352SVenkat Gopalakrishnan 37683736352SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); 37783736352SVenkat Gopalakrishnan config &= ~(0xFF << 10); 37883736352SVenkat Gopalakrishnan config |= mclk_freq << 10; 37983736352SVenkat Gopalakrishnan 38083736352SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); 38183736352SVenkat Gopalakrishnan /* wait for 5us before enabling DLL clock */ 38283736352SVenkat Gopalakrishnan udelay(5); 38383736352SVenkat Gopalakrishnan } 38483736352SVenkat Gopalakrishnan 38529301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 38629301f40SRitesh Harjani config &= ~CORE_DLL_RST; 38729301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 388415b5a75SGeorgi Djakov 38929301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 39029301f40SRitesh Harjani config &= ~CORE_DLL_PDN; 39129301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 392415b5a75SGeorgi Djakov 39383736352SVenkat Gopalakrishnan if (msm_host->use_14lpp_dll_reset) { 39483736352SVenkat Gopalakrishnan msm_cm_dll_set_freq(host); 39583736352SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); 39683736352SVenkat Gopalakrishnan config &= ~CORE_DLL_CLOCK_DISABLE; 39783736352SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); 39883736352SVenkat Gopalakrishnan } 39983736352SVenkat Gopalakrishnan 40029301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 40129301f40SRitesh Harjani config |= CORE_DLL_EN; 40229301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 403415b5a75SGeorgi Djakov 40429301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 40529301f40SRitesh Harjani config |= CORE_CK_OUT_EN; 40629301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 407415b5a75SGeorgi Djakov 408415b5a75SGeorgi Djakov /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ 409415b5a75SGeorgi Djakov while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) & 410415b5a75SGeorgi Djakov CORE_DLL_LOCK)) { 411415b5a75SGeorgi Djakov /* max. wait for 50us sec for LOCK bit to be set */ 412415b5a75SGeorgi Djakov if (--wait_cnt == 0) { 413415b5a75SGeorgi Djakov dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n", 414415b5a75SGeorgi Djakov mmc_hostname(mmc)); 415415b5a75SGeorgi Djakov spin_unlock_irqrestore(&host->lock, flags); 416415b5a75SGeorgi Djakov return -ETIMEDOUT; 417415b5a75SGeorgi Djakov } 418415b5a75SGeorgi Djakov udelay(1); 419415b5a75SGeorgi Djakov } 420415b5a75SGeorgi Djakov 421415b5a75SGeorgi Djakov spin_unlock_irqrestore(&host->lock, flags); 422415b5a75SGeorgi Djakov return 0; 423415b5a75SGeorgi Djakov } 424415b5a75SGeorgi Djakov 4250eb0d9f4SGeorgi Djakov static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) 4260eb0d9f4SGeorgi Djakov { 427415b5a75SGeorgi Djakov int tuning_seq_cnt = 3; 42833d73935SUlf Hansson u8 phase, tuned_phases[16], tuned_phase_cnt = 0; 429415b5a75SGeorgi Djakov int rc; 430415b5a75SGeorgi Djakov struct mmc_host *mmc = host->mmc; 431415b5a75SGeorgi Djakov struct mmc_ios ios = host->mmc->ios; 432415b5a75SGeorgi Djakov 4330eb0d9f4SGeorgi Djakov /* 434415b5a75SGeorgi Djakov * Tuning is required for SDR104, HS200 and HS400 cards and 435415b5a75SGeorgi Djakov * if clock frequency is greater than 100MHz in these modes. 4360eb0d9f4SGeorgi Djakov */ 437ff06ce41SVenkat Gopalakrishnan if (host->clock <= CORE_FREQ_100MHZ || 438ff06ce41SVenkat Gopalakrishnan !(ios.timing == MMC_TIMING_MMC_HS400 || 439ff06ce41SVenkat Gopalakrishnan ios.timing == MMC_TIMING_MMC_HS200 || 440ff06ce41SVenkat Gopalakrishnan ios.timing == MMC_TIMING_UHS_SDR104)) 4410eb0d9f4SGeorgi Djakov return 0; 442415b5a75SGeorgi Djakov 443415b5a75SGeorgi Djakov retry: 444415b5a75SGeorgi Djakov /* First of all reset the tuning block */ 445415b5a75SGeorgi Djakov rc = msm_init_cm_dll(host); 446415b5a75SGeorgi Djakov if (rc) 44733d73935SUlf Hansson return rc; 448415b5a75SGeorgi Djakov 449415b5a75SGeorgi Djakov phase = 0; 450415b5a75SGeorgi Djakov do { 451415b5a75SGeorgi Djakov /* Set the phase in delay line hw block */ 452415b5a75SGeorgi Djakov rc = msm_config_cm_dll_phase(host, phase); 453415b5a75SGeorgi Djakov if (rc) 45433d73935SUlf Hansson return rc; 455415b5a75SGeorgi Djakov 4569979dbe5SChaotian Jing rc = mmc_send_tuning(mmc, opcode, NULL); 45733d73935SUlf Hansson if (!rc) { 458415b5a75SGeorgi Djakov /* Tuning is successful at this tuning point */ 459415b5a75SGeorgi Djakov tuned_phases[tuned_phase_cnt++] = phase; 460415b5a75SGeorgi Djakov dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", 461415b5a75SGeorgi Djakov mmc_hostname(mmc), phase); 462415b5a75SGeorgi Djakov } 463415b5a75SGeorgi Djakov } while (++phase < ARRAY_SIZE(tuned_phases)); 464415b5a75SGeorgi Djakov 465415b5a75SGeorgi Djakov if (tuned_phase_cnt) { 466415b5a75SGeorgi Djakov rc = msm_find_most_appropriate_phase(host, tuned_phases, 467415b5a75SGeorgi Djakov tuned_phase_cnt); 468415b5a75SGeorgi Djakov if (rc < 0) 46933d73935SUlf Hansson return rc; 470415b5a75SGeorgi Djakov else 471415b5a75SGeorgi Djakov phase = rc; 472415b5a75SGeorgi Djakov 473415b5a75SGeorgi Djakov /* 474415b5a75SGeorgi Djakov * Finally set the selected phase in delay 475415b5a75SGeorgi Djakov * line hw block. 476415b5a75SGeorgi Djakov */ 477415b5a75SGeorgi Djakov rc = msm_config_cm_dll_phase(host, phase); 478415b5a75SGeorgi Djakov if (rc) 47933d73935SUlf Hansson return rc; 480415b5a75SGeorgi Djakov dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", 481415b5a75SGeorgi Djakov mmc_hostname(mmc), phase); 482415b5a75SGeorgi Djakov } else { 483415b5a75SGeorgi Djakov if (--tuning_seq_cnt) 484415b5a75SGeorgi Djakov goto retry; 485415b5a75SGeorgi Djakov /* Tuning failed */ 486415b5a75SGeorgi Djakov dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", 487415b5a75SGeorgi Djakov mmc_hostname(mmc)); 488415b5a75SGeorgi Djakov rc = -EIO; 489415b5a75SGeorgi Djakov } 490415b5a75SGeorgi Djakov 491ff06ce41SVenkat Gopalakrishnan if (!rc) 492ff06ce41SVenkat Gopalakrishnan msm_host->tuning_done = true; 493415b5a75SGeorgi Djakov return rc; 4940eb0d9f4SGeorgi Djakov } 4950eb0d9f4SGeorgi Djakov 496ee320674SRitesh Harjani static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, 497ee320674SRitesh Harjani unsigned int uhs) 498ee320674SRitesh Harjani { 499ee320674SRitesh Harjani struct mmc_host *mmc = host->mmc; 500ff06ce41SVenkat Gopalakrishnan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 501ff06ce41SVenkat Gopalakrishnan struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 502ee320674SRitesh Harjani u16 ctrl_2; 503ff06ce41SVenkat Gopalakrishnan u32 config; 504ee320674SRitesh Harjani 505ee320674SRitesh Harjani ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 506ee320674SRitesh Harjani /* Select Bus Speed Mode for host */ 507ee320674SRitesh Harjani ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 508ee320674SRitesh Harjani switch (uhs) { 509ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR12: 510ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR12; 511ee320674SRitesh Harjani break; 512ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR25: 513ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 514ee320674SRitesh Harjani break; 515ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR50: 516ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR50; 517ee320674SRitesh Harjani break; 518ff06ce41SVenkat Gopalakrishnan case MMC_TIMING_MMC_HS400: 519ee320674SRitesh Harjani case MMC_TIMING_MMC_HS200: 520ee320674SRitesh Harjani case MMC_TIMING_UHS_SDR104: 521ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_SDR104; 522ee320674SRitesh Harjani break; 523ee320674SRitesh Harjani case MMC_TIMING_UHS_DDR50: 524ee320674SRitesh Harjani case MMC_TIMING_MMC_DDR52: 525ee320674SRitesh Harjani ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 526ee320674SRitesh Harjani break; 527ee320674SRitesh Harjani } 528ee320674SRitesh Harjani 529ee320674SRitesh Harjani /* 530ee320674SRitesh Harjani * When clock frequency is less than 100MHz, the feedback clock must be 531ee320674SRitesh Harjani * provided and DLL must not be used so that tuning can be skipped. To 532ee320674SRitesh Harjani * provide feedback clock, the mode selection can be any value less 533ee320674SRitesh Harjani * than 3'b011 in bits [2:0] of HOST CONTROL2 register. 534ee320674SRitesh Harjani */ 535ff06ce41SVenkat Gopalakrishnan if (host->clock <= CORE_FREQ_100MHZ) { 536ff06ce41SVenkat Gopalakrishnan if (uhs == MMC_TIMING_MMC_HS400 || 537ee320674SRitesh Harjani uhs == MMC_TIMING_MMC_HS200 || 538ff06ce41SVenkat Gopalakrishnan uhs == MMC_TIMING_UHS_SDR104) 539ee320674SRitesh Harjani ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 540ff06ce41SVenkat Gopalakrishnan /* 541ff06ce41SVenkat Gopalakrishnan * DLL is not required for clock <= 100MHz 542ff06ce41SVenkat Gopalakrishnan * Thus, make sure DLL it is disabled when not required 543ff06ce41SVenkat Gopalakrishnan */ 544ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 545ff06ce41SVenkat Gopalakrishnan config |= CORE_DLL_RST; 546ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 547ff06ce41SVenkat Gopalakrishnan 548ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 549ff06ce41SVenkat Gopalakrishnan config |= CORE_DLL_PDN; 550ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 551ff06ce41SVenkat Gopalakrishnan 552ff06ce41SVenkat Gopalakrishnan /* 553ff06ce41SVenkat Gopalakrishnan * The DLL needs to be restored and CDCLP533 recalibrated 554ff06ce41SVenkat Gopalakrishnan * when the clock frequency is set back to 400MHz. 555ff06ce41SVenkat Gopalakrishnan */ 556ff06ce41SVenkat Gopalakrishnan msm_host->calibration_done = false; 557ff06ce41SVenkat Gopalakrishnan } 558ee320674SRitesh Harjani 559ee320674SRitesh Harjani dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", 560ee320674SRitesh Harjani mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); 561ee320674SRitesh Harjani sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 562ee320674SRitesh Harjani } 563ee320674SRitesh Harjani 564ad81d387SGeorgi Djakov static void sdhci_msm_voltage_switch(struct sdhci_host *host) 565ad81d387SGeorgi Djakov { 566ad81d387SGeorgi Djakov struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 567ad81d387SGeorgi Djakov struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 568ad81d387SGeorgi Djakov u32 irq_status, irq_ack = 0; 569ad81d387SGeorgi Djakov 570ad81d387SGeorgi Djakov irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); 571ad81d387SGeorgi Djakov irq_status &= INT_MASK; 572ad81d387SGeorgi Djakov 573ad81d387SGeorgi Djakov writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR); 574ad81d387SGeorgi Djakov 575ad81d387SGeorgi Djakov if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF)) 576ad81d387SGeorgi Djakov irq_ack |= CORE_PWRCTL_BUS_SUCCESS; 577ad81d387SGeorgi Djakov if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH)) 578ad81d387SGeorgi Djakov irq_ack |= CORE_PWRCTL_IO_SUCCESS; 579ad81d387SGeorgi Djakov 580ad81d387SGeorgi Djakov /* 581ad81d387SGeorgi Djakov * The driver has to acknowledge the interrupt, switch voltages and 582ad81d387SGeorgi Djakov * report back if it succeded or not to this register. The voltage 583ad81d387SGeorgi Djakov * switches are handled by the sdhci core, so just report success. 584ad81d387SGeorgi Djakov */ 585ad81d387SGeorgi Djakov writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); 586ad81d387SGeorgi Djakov } 587ad81d387SGeorgi Djakov 588ad81d387SGeorgi Djakov static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) 589ad81d387SGeorgi Djakov { 590ad81d387SGeorgi Djakov struct sdhci_host *host = (struct sdhci_host *)data; 591ad81d387SGeorgi Djakov 592ad81d387SGeorgi Djakov sdhci_msm_voltage_switch(host); 593ad81d387SGeorgi Djakov 594ad81d387SGeorgi Djakov return IRQ_HANDLED; 595ad81d387SGeorgi Djakov } 596ad81d387SGeorgi Djakov 59780031bdeSRitesh Harjani static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host) 59880031bdeSRitesh Harjani { 59980031bdeSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 60080031bdeSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 60180031bdeSRitesh Harjani 60280031bdeSRitesh Harjani return clk_round_rate(msm_host->clk, ULONG_MAX); 60380031bdeSRitesh Harjani } 60480031bdeSRitesh Harjani 60580031bdeSRitesh Harjani static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host) 60680031bdeSRitesh Harjani { 60780031bdeSRitesh Harjani return SDHCI_MSM_MIN_CLOCK; 60880031bdeSRitesh Harjani } 60980031bdeSRitesh Harjani 610edc609fdSRitesh Harjani /** 611edc609fdSRitesh Harjani * __sdhci_msm_set_clock - sdhci_msm clock control. 612edc609fdSRitesh Harjani * 613edc609fdSRitesh Harjani * Description: 614edc609fdSRitesh Harjani * MSM controller does not use internal divider and 615edc609fdSRitesh Harjani * instead directly control the GCC clock as per 616edc609fdSRitesh Harjani * HW recommendation. 617edc609fdSRitesh Harjani **/ 618edc609fdSRitesh Harjani void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) 619edc609fdSRitesh Harjani { 620edc609fdSRitesh Harjani u16 clk; 621edc609fdSRitesh Harjani /* 622edc609fdSRitesh Harjani * Keep actual_clock as zero - 623edc609fdSRitesh Harjani * - since there is no divider used so no need of having actual_clock. 624edc609fdSRitesh Harjani * - MSM controller uses SDCLK for data timeout calculation. If 625edc609fdSRitesh Harjani * actual_clock is zero, host->clock is taken for calculation. 626edc609fdSRitesh Harjani */ 627edc609fdSRitesh Harjani host->mmc->actual_clock = 0; 628edc609fdSRitesh Harjani 629edc609fdSRitesh Harjani sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 630edc609fdSRitesh Harjani 631edc609fdSRitesh Harjani if (clock == 0) 632edc609fdSRitesh Harjani return; 633edc609fdSRitesh Harjani 634edc609fdSRitesh Harjani /* 635edc609fdSRitesh Harjani * MSM controller do not use clock divider. 636edc609fdSRitesh Harjani * Thus read SDHCI_CLOCK_CONTROL and only enable 637edc609fdSRitesh Harjani * clock with no divider value programmed. 638edc609fdSRitesh Harjani */ 639edc609fdSRitesh Harjani clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 640edc609fdSRitesh Harjani sdhci_enable_clk(host, clk); 641edc609fdSRitesh Harjani } 642edc609fdSRitesh Harjani 643edc609fdSRitesh Harjani /* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */ 644edc609fdSRitesh Harjani static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) 645edc609fdSRitesh Harjani { 646edc609fdSRitesh Harjani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 647edc609fdSRitesh Harjani struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 648b12d44dbSRitesh Harjani struct mmc_ios curr_ios = host->mmc->ios; 649ff06ce41SVenkat Gopalakrishnan u32 config; 650edc609fdSRitesh Harjani int rc; 651edc609fdSRitesh Harjani 652edc609fdSRitesh Harjani if (!clock) { 653edc609fdSRitesh Harjani msm_host->clk_rate = clock; 654edc609fdSRitesh Harjani goto out; 655edc609fdSRitesh Harjani } 656edc609fdSRitesh Harjani 657edc609fdSRitesh Harjani spin_unlock_irq(&host->lock); 658b12d44dbSRitesh Harjani /* 659b12d44dbSRitesh Harjani * The SDHC requires internal clock frequency to be double the 660b12d44dbSRitesh Harjani * actual clock that will be set for DDR mode. The controller 661b12d44dbSRitesh Harjani * uses the faster clock(100/400MHz) for some of its parts and 662b12d44dbSRitesh Harjani * send the actual required clock (50/200MHz) to the card. 663b12d44dbSRitesh Harjani */ 664b12d44dbSRitesh Harjani if (curr_ios.timing == MMC_TIMING_UHS_DDR50 || 665b12d44dbSRitesh Harjani curr_ios.timing == MMC_TIMING_MMC_DDR52 || 666b12d44dbSRitesh Harjani curr_ios.timing == MMC_TIMING_MMC_HS400) 667b12d44dbSRitesh Harjani clock *= 2; 668ff06ce41SVenkat Gopalakrishnan /* 669ff06ce41SVenkat Gopalakrishnan * In general all timing modes are controlled via UHS mode select in 670ff06ce41SVenkat Gopalakrishnan * Host Control2 register. eMMC specific HS200/HS400 doesn't have 671ff06ce41SVenkat Gopalakrishnan * their respective modes defined here, hence we use these values. 672ff06ce41SVenkat Gopalakrishnan * 673ff06ce41SVenkat Gopalakrishnan * HS200 - SDR104 (Since they both are equivalent in functionality) 674ff06ce41SVenkat Gopalakrishnan * HS400 - This involves multiple configurations 675ff06ce41SVenkat Gopalakrishnan * Initially SDR104 - when tuning is required as HS200 676ff06ce41SVenkat Gopalakrishnan * Then when switching to DDR @ 400MHz (HS400) we use 677ff06ce41SVenkat Gopalakrishnan * the vendor specific HC_SELECT_IN to control the mode. 678ff06ce41SVenkat Gopalakrishnan * 679ff06ce41SVenkat Gopalakrishnan * In addition to controlling the modes we also need to select the 680ff06ce41SVenkat Gopalakrishnan * correct input clock for DLL depending on the mode. 681ff06ce41SVenkat Gopalakrishnan * 682ff06ce41SVenkat Gopalakrishnan * HS400 - divided clock (free running MCLK/2) 683ff06ce41SVenkat Gopalakrishnan * All other modes - default (free running MCLK) 684ff06ce41SVenkat Gopalakrishnan */ 685ff06ce41SVenkat Gopalakrishnan if (curr_ios.timing == MMC_TIMING_MMC_HS400) { 686ff06ce41SVenkat Gopalakrishnan /* Select the divided clock (free running MCLK/2) */ 687ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); 688ff06ce41SVenkat Gopalakrishnan config &= ~CORE_HC_MCLK_SEL_MASK; 689ff06ce41SVenkat Gopalakrishnan config |= CORE_HC_MCLK_SEL_HS400; 690ff06ce41SVenkat Gopalakrishnan 691ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); 692ff06ce41SVenkat Gopalakrishnan /* 693ff06ce41SVenkat Gopalakrishnan * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC 694ff06ce41SVenkat Gopalakrishnan * register 695ff06ce41SVenkat Gopalakrishnan */ 696ff06ce41SVenkat Gopalakrishnan if (msm_host->tuning_done && !msm_host->calibration_done) { 697ff06ce41SVenkat Gopalakrishnan /* 698ff06ce41SVenkat Gopalakrishnan * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN 699ff06ce41SVenkat Gopalakrishnan * field in VENDOR_SPEC_FUNC 700ff06ce41SVenkat Gopalakrishnan */ 701ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); 702ff06ce41SVenkat Gopalakrishnan config |= CORE_HC_SELECT_IN_HS400; 703ff06ce41SVenkat Gopalakrishnan config |= CORE_HC_SELECT_IN_EN; 704ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); 705ff06ce41SVenkat Gopalakrishnan } 706ff06ce41SVenkat Gopalakrishnan } else { 707ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); 708ff06ce41SVenkat Gopalakrishnan config &= ~CORE_HC_MCLK_SEL_MASK; 709ff06ce41SVenkat Gopalakrishnan config |= CORE_HC_MCLK_SEL_DFLT; 710ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); 711ff06ce41SVenkat Gopalakrishnan 712ff06ce41SVenkat Gopalakrishnan /* 713ff06ce41SVenkat Gopalakrishnan * Disable HC_SELECT_IN to be able to use the UHS mode select 714ff06ce41SVenkat Gopalakrishnan * configuration from Host Control2 register for all other 715ff06ce41SVenkat Gopalakrishnan * modes. 716ff06ce41SVenkat Gopalakrishnan * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field 717ff06ce41SVenkat Gopalakrishnan * in VENDOR_SPEC_FUNC 718ff06ce41SVenkat Gopalakrishnan */ 719ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); 720ff06ce41SVenkat Gopalakrishnan config &= ~CORE_HC_SELECT_IN_EN; 721ff06ce41SVenkat Gopalakrishnan config &= ~CORE_HC_SELECT_IN_MASK; 722ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); 723ff06ce41SVenkat Gopalakrishnan } 724ff06ce41SVenkat Gopalakrishnan 725ff06ce41SVenkat Gopalakrishnan /* 726ff06ce41SVenkat Gopalakrishnan * Make sure above writes impacting free running MCLK are completed 727ff06ce41SVenkat Gopalakrishnan * before changing the clk_rate at GCC. 728ff06ce41SVenkat Gopalakrishnan */ 729ff06ce41SVenkat Gopalakrishnan wmb(); 730edc609fdSRitesh Harjani 731edc609fdSRitesh Harjani rc = clk_set_rate(msm_host->clk, clock); 732edc609fdSRitesh Harjani if (rc) { 733b12d44dbSRitesh Harjani pr_err("%s: Failed to set clock at rate %u at timing %d\n", 734b12d44dbSRitesh Harjani mmc_hostname(host->mmc), clock, 735b12d44dbSRitesh Harjani curr_ios.timing); 736edc609fdSRitesh Harjani goto out_lock; 737edc609fdSRitesh Harjani } 738edc609fdSRitesh Harjani msm_host->clk_rate = clock; 739b12d44dbSRitesh Harjani pr_debug("%s: Setting clock at rate %lu at timing %d\n", 740b12d44dbSRitesh Harjani mmc_hostname(host->mmc), clk_get_rate(msm_host->clk), 741b12d44dbSRitesh Harjani curr_ios.timing); 742edc609fdSRitesh Harjani 743edc609fdSRitesh Harjani out_lock: 744edc609fdSRitesh Harjani spin_lock_irq(&host->lock); 745edc609fdSRitesh Harjani out: 746edc609fdSRitesh Harjani __sdhci_msm_set_clock(host, clock); 747edc609fdSRitesh Harjani } 748edc609fdSRitesh Harjani 7490eb0d9f4SGeorgi Djakov static const struct of_device_id sdhci_msm_dt_match[] = { 7500eb0d9f4SGeorgi Djakov { .compatible = "qcom,sdhci-msm-v4" }, 7510eb0d9f4SGeorgi Djakov {}, 7520eb0d9f4SGeorgi Djakov }; 7530eb0d9f4SGeorgi Djakov 7540eb0d9f4SGeorgi Djakov MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); 7550eb0d9f4SGeorgi Djakov 756a50396a4SJisheng Zhang static const struct sdhci_ops sdhci_msm_ops = { 7570eb0d9f4SGeorgi Djakov .platform_execute_tuning = sdhci_msm_execute_tuning, 758ed1761d7SStephen Boyd .reset = sdhci_reset, 759edc609fdSRitesh Harjani .set_clock = sdhci_msm_set_clock, 76080031bdeSRitesh Harjani .get_min_clock = sdhci_msm_get_min_clock, 76180031bdeSRitesh Harjani .get_max_clock = sdhci_msm_get_max_clock, 762ed1761d7SStephen Boyd .set_bus_width = sdhci_set_bus_width, 763ee320674SRitesh Harjani .set_uhs_signaling = sdhci_msm_set_uhs_signaling, 764ad81d387SGeorgi Djakov .voltage_switch = sdhci_msm_voltage_switch, 7650eb0d9f4SGeorgi Djakov }; 7660eb0d9f4SGeorgi Djakov 767a50396a4SJisheng Zhang static const struct sdhci_pltfm_data sdhci_msm_pdata = { 768a50396a4SJisheng Zhang .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | 7699718f84bSGeorgi Djakov SDHCI_QUIRK_NO_CARD_NO_RESET | 770a0e31428SRitesh Harjani SDHCI_QUIRK_SINGLE_POWER_WRITE | 771a0e31428SRitesh Harjani SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 772a0e31428SRitesh Harjani .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 773a50396a4SJisheng Zhang .ops = &sdhci_msm_ops, 774a50396a4SJisheng Zhang }; 775a50396a4SJisheng Zhang 7760eb0d9f4SGeorgi Djakov static int sdhci_msm_probe(struct platform_device *pdev) 7770eb0d9f4SGeorgi Djakov { 7780eb0d9f4SGeorgi Djakov struct sdhci_host *host; 7790eb0d9f4SGeorgi Djakov struct sdhci_pltfm_host *pltfm_host; 7800eb0d9f4SGeorgi Djakov struct sdhci_msm_host *msm_host; 7810eb0d9f4SGeorgi Djakov struct resource *core_memres; 7820eb0d9f4SGeorgi Djakov int ret; 7833a3ad3e9SGeorgi Djakov u16 host_version, core_minor; 78429301f40SRitesh Harjani u32 core_version, config; 7853a3ad3e9SGeorgi Djakov u8 core_major; 7860eb0d9f4SGeorgi Djakov 7876f699531SJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host)); 7880eb0d9f4SGeorgi Djakov if (IS_ERR(host)) 7890eb0d9f4SGeorgi Djakov return PTR_ERR(host); 7900eb0d9f4SGeorgi Djakov 7910eb0d9f4SGeorgi Djakov pltfm_host = sdhci_priv(host); 7926f699531SJisheng Zhang msm_host = sdhci_pltfm_priv(pltfm_host); 7930eb0d9f4SGeorgi Djakov msm_host->mmc = host->mmc; 7940eb0d9f4SGeorgi Djakov msm_host->pdev = pdev; 7950eb0d9f4SGeorgi Djakov 7960eb0d9f4SGeorgi Djakov ret = mmc_of_parse(host->mmc); 7970eb0d9f4SGeorgi Djakov if (ret) 7980eb0d9f4SGeorgi Djakov goto pltfm_free; 7990eb0d9f4SGeorgi Djakov 8000eb0d9f4SGeorgi Djakov sdhci_get_of_property(pdev); 8010eb0d9f4SGeorgi Djakov 8020eb0d9f4SGeorgi Djakov /* Setup SDCC bus voter clock. */ 8030eb0d9f4SGeorgi Djakov msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus"); 8040eb0d9f4SGeorgi Djakov if (!IS_ERR(msm_host->bus_clk)) { 8050eb0d9f4SGeorgi Djakov /* Vote for max. clk rate for max. performance */ 8060eb0d9f4SGeorgi Djakov ret = clk_set_rate(msm_host->bus_clk, INT_MAX); 8070eb0d9f4SGeorgi Djakov if (ret) 8080eb0d9f4SGeorgi Djakov goto pltfm_free; 8090eb0d9f4SGeorgi Djakov ret = clk_prepare_enable(msm_host->bus_clk); 8100eb0d9f4SGeorgi Djakov if (ret) 8110eb0d9f4SGeorgi Djakov goto pltfm_free; 8120eb0d9f4SGeorgi Djakov } 8130eb0d9f4SGeorgi Djakov 8140eb0d9f4SGeorgi Djakov /* Setup main peripheral bus clock */ 8150eb0d9f4SGeorgi Djakov msm_host->pclk = devm_clk_get(&pdev->dev, "iface"); 8160eb0d9f4SGeorgi Djakov if (IS_ERR(msm_host->pclk)) { 8170eb0d9f4SGeorgi Djakov ret = PTR_ERR(msm_host->pclk); 8182801b95eSColin Ian King dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret); 8190eb0d9f4SGeorgi Djakov goto bus_clk_disable; 8200eb0d9f4SGeorgi Djakov } 8210eb0d9f4SGeorgi Djakov 8220eb0d9f4SGeorgi Djakov ret = clk_prepare_enable(msm_host->pclk); 8230eb0d9f4SGeorgi Djakov if (ret) 8240eb0d9f4SGeorgi Djakov goto bus_clk_disable; 8250eb0d9f4SGeorgi Djakov 8260eb0d9f4SGeorgi Djakov /* Setup SDC MMC clock */ 8270eb0d9f4SGeorgi Djakov msm_host->clk = devm_clk_get(&pdev->dev, "core"); 8280eb0d9f4SGeorgi Djakov if (IS_ERR(msm_host->clk)) { 8290eb0d9f4SGeorgi Djakov ret = PTR_ERR(msm_host->clk); 8300eb0d9f4SGeorgi Djakov dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret); 8310eb0d9f4SGeorgi Djakov goto pclk_disable; 8320eb0d9f4SGeorgi Djakov } 8330eb0d9f4SGeorgi Djakov 83483736352SVenkat Gopalakrishnan /* 83583736352SVenkat Gopalakrishnan * xo clock is needed for FLL feature of cm_dll. 83683736352SVenkat Gopalakrishnan * In case if xo clock is not mentioned in DT, warn and proceed. 83783736352SVenkat Gopalakrishnan */ 83883736352SVenkat Gopalakrishnan msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo"); 83983736352SVenkat Gopalakrishnan if (IS_ERR(msm_host->xo_clk)) { 84083736352SVenkat Gopalakrishnan ret = PTR_ERR(msm_host->xo_clk); 84183736352SVenkat Gopalakrishnan dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret); 84283736352SVenkat Gopalakrishnan } 84383736352SVenkat Gopalakrishnan 844951b8c87SIvan T. Ivanov /* Vote for maximum clock rate for maximum performance */ 845951b8c87SIvan T. Ivanov ret = clk_set_rate(msm_host->clk, INT_MAX); 846951b8c87SIvan T. Ivanov if (ret) 847951b8c87SIvan T. Ivanov dev_warn(&pdev->dev, "core clock boost failed\n"); 848951b8c87SIvan T. Ivanov 8490eb0d9f4SGeorgi Djakov ret = clk_prepare_enable(msm_host->clk); 8500eb0d9f4SGeorgi Djakov if (ret) 8510eb0d9f4SGeorgi Djakov goto pclk_disable; 8520eb0d9f4SGeorgi Djakov 8530eb0d9f4SGeorgi Djakov core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1); 8540eb0d9f4SGeorgi Djakov msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres); 8550eb0d9f4SGeorgi Djakov 8560eb0d9f4SGeorgi Djakov if (IS_ERR(msm_host->core_mem)) { 8570eb0d9f4SGeorgi Djakov dev_err(&pdev->dev, "Failed to remap registers\n"); 8580eb0d9f4SGeorgi Djakov ret = PTR_ERR(msm_host->core_mem); 8590eb0d9f4SGeorgi Djakov goto clk_disable; 8600eb0d9f4SGeorgi Djakov } 8610eb0d9f4SGeorgi Djakov 86229301f40SRitesh Harjani config = readl_relaxed(msm_host->core_mem + CORE_POWER); 86329301f40SRitesh Harjani config |= CORE_SW_RST; 86429301f40SRitesh Harjani writel_relaxed(config, msm_host->core_mem + CORE_POWER); 8650eb0d9f4SGeorgi Djakov 8660eb0d9f4SGeorgi Djakov /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */ 8670eb0d9f4SGeorgi Djakov usleep_range(1000, 5000); 8680eb0d9f4SGeorgi Djakov if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) { 8690eb0d9f4SGeorgi Djakov dev_err(&pdev->dev, "Stuck in reset\n"); 8700eb0d9f4SGeorgi Djakov ret = -ETIMEDOUT; 8710eb0d9f4SGeorgi Djakov goto clk_disable; 8720eb0d9f4SGeorgi Djakov } 8730eb0d9f4SGeorgi Djakov 8740eb0d9f4SGeorgi Djakov /* Set HC_MODE_EN bit in HC_MODE register */ 8750eb0d9f4SGeorgi Djakov writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); 8760eb0d9f4SGeorgi Djakov 877ff06ce41SVenkat Gopalakrishnan config = readl_relaxed(msm_host->core_mem + CORE_HC_MODE); 878ff06ce41SVenkat Gopalakrishnan config |= FF_CLK_SW_RST_DIS; 879ff06ce41SVenkat Gopalakrishnan writel_relaxed(config, msm_host->core_mem + CORE_HC_MODE); 880ff06ce41SVenkat Gopalakrishnan 8810eb0d9f4SGeorgi Djakov host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); 8820eb0d9f4SGeorgi Djakov dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", 8830eb0d9f4SGeorgi Djakov host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> 8840eb0d9f4SGeorgi Djakov SDHCI_VENDOR_VER_SHIFT)); 8850eb0d9f4SGeorgi Djakov 8863a3ad3e9SGeorgi Djakov core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION); 8873a3ad3e9SGeorgi Djakov core_major = (core_version & CORE_VERSION_MAJOR_MASK) >> 8883a3ad3e9SGeorgi Djakov CORE_VERSION_MAJOR_SHIFT; 8893a3ad3e9SGeorgi Djakov core_minor = core_version & CORE_VERSION_MINOR_MASK; 8903a3ad3e9SGeorgi Djakov dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n", 8913a3ad3e9SGeorgi Djakov core_version, core_major, core_minor); 8923a3ad3e9SGeorgi Djakov 89383736352SVenkat Gopalakrishnan if (core_major == 1 && core_minor >= 0x42) 89483736352SVenkat Gopalakrishnan msm_host->use_14lpp_dll_reset = true; 89583736352SVenkat Gopalakrishnan 8963a3ad3e9SGeorgi Djakov /* 8973a3ad3e9SGeorgi Djakov * Support for some capabilities is not advertised by newer 8983a3ad3e9SGeorgi Djakov * controller versions and must be explicitly enabled. 8993a3ad3e9SGeorgi Djakov */ 9003a3ad3e9SGeorgi Djakov if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { 90129301f40SRitesh Harjani config = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES); 90229301f40SRitesh Harjani config |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; 90329301f40SRitesh Harjani writel_relaxed(config, host->ioaddr + 9043a3ad3e9SGeorgi Djakov CORE_VENDOR_SPEC_CAPABILITIES0); 9053a3ad3e9SGeorgi Djakov } 9063a3ad3e9SGeorgi Djakov 907ad81d387SGeorgi Djakov /* Setup IRQ for handling power/voltage tasks with PMIC */ 908ad81d387SGeorgi Djakov msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); 909ad81d387SGeorgi Djakov if (msm_host->pwr_irq < 0) { 910ad81d387SGeorgi Djakov dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n", 911ad81d387SGeorgi Djakov msm_host->pwr_irq); 912d1f63f0cSWei Yongjun ret = msm_host->pwr_irq; 913ad81d387SGeorgi Djakov goto clk_disable; 914ad81d387SGeorgi Djakov } 915ad81d387SGeorgi Djakov 916ad81d387SGeorgi Djakov ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, 917ad81d387SGeorgi Djakov sdhci_msm_pwr_irq, IRQF_ONESHOT, 918ad81d387SGeorgi Djakov dev_name(&pdev->dev), host); 919ad81d387SGeorgi Djakov if (ret) { 920ad81d387SGeorgi Djakov dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret); 921ad81d387SGeorgi Djakov goto clk_disable; 922ad81d387SGeorgi Djakov } 923ad81d387SGeorgi Djakov 92467e6db11SPramod Gurav pm_runtime_get_noresume(&pdev->dev); 92567e6db11SPramod Gurav pm_runtime_set_active(&pdev->dev); 92667e6db11SPramod Gurav pm_runtime_enable(&pdev->dev); 92767e6db11SPramod Gurav pm_runtime_set_autosuspend_delay(&pdev->dev, 92867e6db11SPramod Gurav MSM_MMC_AUTOSUSPEND_DELAY_MS); 92967e6db11SPramod Gurav pm_runtime_use_autosuspend(&pdev->dev); 93067e6db11SPramod Gurav 9310eb0d9f4SGeorgi Djakov ret = sdhci_add_host(host); 9320eb0d9f4SGeorgi Djakov if (ret) 93367e6db11SPramod Gurav goto pm_runtime_disable; 93467e6db11SPramod Gurav 93567e6db11SPramod Gurav pm_runtime_mark_last_busy(&pdev->dev); 93667e6db11SPramod Gurav pm_runtime_put_autosuspend(&pdev->dev); 9370eb0d9f4SGeorgi Djakov 9380eb0d9f4SGeorgi Djakov return 0; 9390eb0d9f4SGeorgi Djakov 94067e6db11SPramod Gurav pm_runtime_disable: 94167e6db11SPramod Gurav pm_runtime_disable(&pdev->dev); 94267e6db11SPramod Gurav pm_runtime_set_suspended(&pdev->dev); 94367e6db11SPramod Gurav pm_runtime_put_noidle(&pdev->dev); 9440eb0d9f4SGeorgi Djakov clk_disable: 9450eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->clk); 9460eb0d9f4SGeorgi Djakov pclk_disable: 9470eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->pclk); 9480eb0d9f4SGeorgi Djakov bus_clk_disable: 9490eb0d9f4SGeorgi Djakov if (!IS_ERR(msm_host->bus_clk)) 9500eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->bus_clk); 9510eb0d9f4SGeorgi Djakov pltfm_free: 9520eb0d9f4SGeorgi Djakov sdhci_pltfm_free(pdev); 9530eb0d9f4SGeorgi Djakov return ret; 9540eb0d9f4SGeorgi Djakov } 9550eb0d9f4SGeorgi Djakov 9560eb0d9f4SGeorgi Djakov static int sdhci_msm_remove(struct platform_device *pdev) 9570eb0d9f4SGeorgi Djakov { 9580eb0d9f4SGeorgi Djakov struct sdhci_host *host = platform_get_drvdata(pdev); 9590eb0d9f4SGeorgi Djakov struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9606f699531SJisheng Zhang struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 9610eb0d9f4SGeorgi Djakov int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 9620eb0d9f4SGeorgi Djakov 0xffffffff); 9630eb0d9f4SGeorgi Djakov 9640eb0d9f4SGeorgi Djakov sdhci_remove_host(host, dead); 96567e6db11SPramod Gurav 96667e6db11SPramod Gurav pm_runtime_get_sync(&pdev->dev); 96767e6db11SPramod Gurav pm_runtime_disable(&pdev->dev); 96867e6db11SPramod Gurav pm_runtime_put_noidle(&pdev->dev); 96967e6db11SPramod Gurav 9700eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->clk); 9710eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->pclk); 9720eb0d9f4SGeorgi Djakov if (!IS_ERR(msm_host->bus_clk)) 9730eb0d9f4SGeorgi Djakov clk_disable_unprepare(msm_host->bus_clk); 9746f699531SJisheng Zhang sdhci_pltfm_free(pdev); 9750eb0d9f4SGeorgi Djakov return 0; 9760eb0d9f4SGeorgi Djakov } 9770eb0d9f4SGeorgi Djakov 97867e6db11SPramod Gurav #ifdef CONFIG_PM 97967e6db11SPramod Gurav static int sdhci_msm_runtime_suspend(struct device *dev) 98067e6db11SPramod Gurav { 98167e6db11SPramod Gurav struct sdhci_host *host = dev_get_drvdata(dev); 98267e6db11SPramod Gurav struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 98367e6db11SPramod Gurav struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 98467e6db11SPramod Gurav 98567e6db11SPramod Gurav clk_disable_unprepare(msm_host->clk); 98667e6db11SPramod Gurav clk_disable_unprepare(msm_host->pclk); 98767e6db11SPramod Gurav 98867e6db11SPramod Gurav return 0; 98967e6db11SPramod Gurav } 99067e6db11SPramod Gurav 99167e6db11SPramod Gurav static int sdhci_msm_runtime_resume(struct device *dev) 99267e6db11SPramod Gurav { 99367e6db11SPramod Gurav struct sdhci_host *host = dev_get_drvdata(dev); 99467e6db11SPramod Gurav struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 99567e6db11SPramod Gurav struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 99667e6db11SPramod Gurav int ret; 99767e6db11SPramod Gurav 99867e6db11SPramod Gurav ret = clk_prepare_enable(msm_host->clk); 99967e6db11SPramod Gurav if (ret) { 100067e6db11SPramod Gurav dev_err(dev, "clk_enable failed for core_clk: %d\n", ret); 100167e6db11SPramod Gurav return ret; 100267e6db11SPramod Gurav } 100367e6db11SPramod Gurav ret = clk_prepare_enable(msm_host->pclk); 100467e6db11SPramod Gurav if (ret) { 100567e6db11SPramod Gurav dev_err(dev, "clk_enable failed for iface_clk: %d\n", ret); 100667e6db11SPramod Gurav clk_disable_unprepare(msm_host->clk); 100767e6db11SPramod Gurav return ret; 100867e6db11SPramod Gurav } 100967e6db11SPramod Gurav 101067e6db11SPramod Gurav return 0; 101167e6db11SPramod Gurav } 101267e6db11SPramod Gurav #endif 101367e6db11SPramod Gurav 101467e6db11SPramod Gurav static const struct dev_pm_ops sdhci_msm_pm_ops = { 101567e6db11SPramod Gurav SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 101667e6db11SPramod Gurav pm_runtime_force_resume) 101767e6db11SPramod Gurav SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, 101867e6db11SPramod Gurav sdhci_msm_runtime_resume, 101967e6db11SPramod Gurav NULL) 102067e6db11SPramod Gurav }; 102167e6db11SPramod Gurav 10220eb0d9f4SGeorgi Djakov static struct platform_driver sdhci_msm_driver = { 10230eb0d9f4SGeorgi Djakov .probe = sdhci_msm_probe, 10240eb0d9f4SGeorgi Djakov .remove = sdhci_msm_remove, 10250eb0d9f4SGeorgi Djakov .driver = { 10260eb0d9f4SGeorgi Djakov .name = "sdhci_msm", 10270eb0d9f4SGeorgi Djakov .of_match_table = sdhci_msm_dt_match, 102867e6db11SPramod Gurav .pm = &sdhci_msm_pm_ops, 10290eb0d9f4SGeorgi Djakov }, 10300eb0d9f4SGeorgi Djakov }; 10310eb0d9f4SGeorgi Djakov 10320eb0d9f4SGeorgi Djakov module_platform_driver(sdhci_msm_driver); 10330eb0d9f4SGeorgi Djakov 10340eb0d9f4SGeorgi Djakov MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver"); 10350eb0d9f4SGeorgi Djakov MODULE_LICENSE("GPL v2"); 1036