/* * drivers/mmc/host/sdhci-msm.c - Qualcomm MSM SDHCI Platform * driver source file * * Copyright (c) 2012-2013, The Linux Foundation. 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 version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sdhci-pltfm.h" #define SDHCI_VER_100 0x2B #define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 #define CORE_SW_RST (1 << 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 0x01 #define CORE_PWRCTL_BUS_ON (1 << 1) #define CORE_PWRCTL_IO_LOW (1 << 2) #define CORE_PWRCTL_IO_HIGH (1 << 3) #define CORE_PWRCTL_BUS_SUCCESS 0x01 #define CORE_PWRCTL_BUS_FAIL (1 << 1) #define CORE_PWRCTL_IO_SUCCESS (1 << 2) #define CORE_PWRCTL_IO_FAIL (1 << 3) #define INT_MASK 0xF #define MAX_PHASES 16 #define CORE_DLL_LOCK (1 << 7) #define CORE_DLL_EN (1 << 16) #define CORE_CDR_EN (1 << 17) #define CORE_CK_OUT_EN (1 << 18) #define CORE_CDR_EXT_EN (1 << 19) #define CORE_DLL_PDN (1 << 29) #define CORE_DLL_RST (1 << 30) #define CORE_DLL_CONFIG 0x100 #define CORE_DLL_TEST_CTL 0x104 #define CORE_DLL_STATUS 0x108 #define CORE_VENDOR_SPEC 0x10C #define CORE_CLK_PWRSAVE (1 << 1) #define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_MCI_DATA_CTRL 0x2C #define CORE_MCI_DPSM_ENABLE (1 << 0) #define CORE_TESTBUS_CONFIG 0x0CC #define CORE_TESTBUS_ENA (1 << 3) #define CORE_TESTBUS_SEL2 (1 << 4) /* * Waiting until end of potential AHB access for data: * 16 AHB cycles (160ns for 100MHz and 320ns for 50MHz) + * delay on AHB (2us) = maximum 2.32us * Taking x10 times margin */ #define CORE_AHB_DATA_DELAY_US 23 /* Waiting until end of potential AHB access for descriptor: * Single (1 AHB cycle) + delay on AHB bus = max 2us * INCR4 (4 AHB cycles) + delay on AHB bus = max 2us * Single (1 AHB cycle) + delay on AHB bus = max 2us * Total 8 us delay with margin */ #define CORE_AHB_DESC_DELAY_US 8 #define CORE_SDCC_DEBUG_REG 0x124 #define CORE_DEBUG_REG_AHB_HTRANS (3 << 12) /* 8KB descriptors */ #define SDHCI_MSM_MAX_SEGMENTS (1 << 13) #define SDHCI_MSM_MMC_CLK_GATE_DELAY 200 /* msecs */ static const u32 tuning_block_64[] = { 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE, 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777, 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF, 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7 }; static const u32 tuning_block_128[] = { 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC, 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF, 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF, 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB, 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC, 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF, 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB, 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77 }; static int disable_slots; /* root can write, others read */ module_param(disable_slots, int, S_IRUGO|S_IWUSR); /* This structure keeps information per regulator */ struct sdhci_msm_reg_data { /* voltage regulator handle */ struct regulator *reg; /* regulator name */ const char *name; /* voltage level to be set */ u32 low_vol_level; u32 high_vol_level; /* Load values for low power and high power mode */ u32 lpm_uA; u32 hpm_uA; /* is this regulator enabled? */ bool is_enabled; /* is this regulator needs to be always on? */ bool is_always_on; /* is low power mode setting required for this regulator? */ bool lpm_sup; }; /* * This structure keeps information for all the * regulators required for a SDCC slot. */ struct sdhci_msm_slot_reg_data { /* keeps VDD/VCC regulator info */ struct sdhci_msm_reg_data *vdd_data; /* keeps VDD IO regulator info */ struct sdhci_msm_reg_data *vdd_io_data; }; struct sdhci_msm_gpio { u32 no; const char *name; bool is_enabled; }; struct sdhci_msm_gpio_data { struct sdhci_msm_gpio *gpio; u8 size; }; struct sdhci_msm_pad_pull { enum msm_tlmm_pull_tgt no; u32 val; }; struct sdhci_msm_pad_pull_data { struct sdhci_msm_pad_pull *on; struct sdhci_msm_pad_pull *off; u8 size; }; struct sdhci_msm_pad_drv { enum msm_tlmm_hdrive_tgt no; u32 val; }; struct sdhci_msm_pad_drv_data { struct sdhci_msm_pad_drv *on; struct sdhci_msm_pad_drv *off; u8 size; }; struct sdhci_msm_pad_data { struct sdhci_msm_pad_pull_data *pull; struct sdhci_msm_pad_drv_data *drv; }; struct sdhci_msm_pin_data { /* * = 1 if controller pins are using gpios * = 0 if controller has dedicated MSM pads */ u8 is_gpio; bool cfg_sts; struct sdhci_msm_gpio_data *gpio_data; struct sdhci_msm_pad_data *pad_data; }; struct sdhci_msm_bus_voting_data { struct msm_bus_scale_pdata *bus_pdata; unsigned int *bw_vecs; unsigned int bw_vecs_size; }; struct sdhci_msm_pltfm_data { /* Supported UHS-I Modes */ u32 caps; /* More capabilities */ u32 caps2; unsigned long mmc_bus_width; struct sdhci_msm_slot_reg_data *vreg_data; bool nonremovable; struct sdhci_msm_pin_data *pin_data; u32 cpu_dma_latency_us; int status_gpio; /* card detection GPIO that is configured as IRQ */ struct sdhci_msm_bus_voting_data *voting_data; u32 *sup_clk_table; unsigned char sup_clk_cnt; }; struct sdhci_msm_bus_vote { uint32_t client_handle; uint32_t curr_vote; int min_bw_vote; int max_bw_vote; bool is_max_bw_needed; struct delayed_work vote_work; struct device_attribute max_bus_bw; }; 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 */ atomic_t clks_on; /* Set if clocks are enabled */ struct sdhci_msm_pltfm_data *pdata; struct mmc_host *mmc; struct sdhci_pltfm_data sdhci_msm_pdata; u32 curr_pwr_state; u32 curr_io_level; struct completion pwr_irq_completion; struct sdhci_msm_bus_vote msm_bus_vote; u32 clk_rate; /* Keeps track of current clock rate that is set */ }; enum vdd_io_level { /* set vdd_io_data->low_vol_level */ VDD_IO_LOW, /* set vdd_io_data->high_vol_level */ VDD_IO_HIGH, /* * set whatever there in voltage_level (third argument) of * sdhci_msm_set_vdd_io_vol() function. */ VDD_IO_SET_LEVEL, }; /* MSM platform specific tuning */ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) { int rc = 0; u32 wait_cnt = 50; u8 ck_out_en = 0; struct mmc_host *mmc = host->mmc; /* poll for CK_OUT_EN bit. max. poll time = 50us */ ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & CORE_CK_OUT_EN); while (ck_out_en != poll) { if (--wait_cnt == 0) { pr_err("%s: %s: CK_OUT_EN bit is not %d\n", mmc_hostname(mmc), __func__, poll); rc = -ETIMEDOUT; goto out; } udelay(1); ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & CORE_CK_OUT_EN); } out: return rc; } static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase) { int rc = 0; u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8}; unsigned long flags; u32 config; struct mmc_host *mmc = host->mmc; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); spin_lock_irqsave(&host->lock, flags); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN); config |= (CORE_CDR_EXT_EN | CORE_DLL_EN); writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */ rc = msm_dll_poll_ck_out_en(host, 0); if (rc) goto err_out; /* * Write the selected DLL clock output phase (0 ... 15) * to CDR_SELEXT bit field of DLL_CONFIG register. */ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & ~(0xF << 20)) | (grey_coded_phase_table[phase] << 20)), host->ioaddr + CORE_DLL_CONFIG); /* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG); /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */ rc = msm_dll_poll_ck_out_en(host, 1); if (rc) goto err_out; config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_CDR_EN; config &= ~CORE_CDR_EXT_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); goto out; err_out: pr_err("%s: %s: Failed to set DLL phase: %d\n", mmc_hostname(mmc), __func__, phase); out: spin_unlock_irqrestore(&host->lock, flags); pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__); return rc; } /* * Find out the greatest range of consecuitive selected * DLL clock output phases that can be used as sampling * setting for SD3.0 UHS-I card read operation (in SDR104 * timing mode) or for eMMC4.5 card read operation (in HS200 * timing mode). * Select the 3/4 of the range and configure the DLL with the * selected DLL clock output phase. */ static int msm_find_most_appropriate_phase(struct sdhci_host *host, u8 *phase_table, u8 total_phases) { int ret; u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} }; u8 phases_per_row[MAX_PHASES] = {0}; int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0; int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0; bool phase_0_found = false, phase_15_found = false; struct mmc_host *mmc = host->mmc; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); if (!total_phases || (total_phases > MAX_PHASES)) { pr_err("%s: %s: invalid argument: total_phases=%d\n", mmc_hostname(mmc), __func__, total_phases); return -EINVAL; } for (cnt = 0; cnt < total_phases; cnt++) { ranges[row_index][col_index] = phase_table[cnt]; phases_per_row[row_index] += 1; col_index++; if ((cnt + 1) == total_phases) { continue; /* check if next phase in phase_table is consecutive or not */ } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) { row_index++; col_index = 0; } } if (row_index >= MAX_PHASES) return -EINVAL; /* Check if phase-0 is present in first valid window? */ if (!ranges[0][0]) { phase_0_found = true; phase_0_raw_index = 0; /* Check if cycle exist between 2 valid windows */ for (cnt = 1; cnt <= row_index; cnt++) { if (phases_per_row[cnt]) { for (i = 0; i < phases_per_row[cnt]; i++) { if (ranges[cnt][i] == 15) { phase_15_found = true; phase_15_raw_index = cnt; break; } } } } } /* If 2 valid windows form cycle then merge them as single window */ if (phase_0_found && phase_15_found) { /* number of phases in raw where phase 0 is present */ u8 phases_0 = phases_per_row[phase_0_raw_index]; /* number of phases in raw where phase 15 is present */ u8 phases_15 = phases_per_row[phase_15_raw_index]; if (phases_0 + phases_15 >= MAX_PHASES) /* * If there are more than 1 phase windows then total * number of phases in both the windows should not be * more than or equal to MAX_PHASES. */ return -EINVAL; /* Merge 2 cyclic windows */ i = phases_15; for (cnt = 0; cnt < phases_0; cnt++) { ranges[phase_15_raw_index][i] = ranges[phase_0_raw_index][cnt]; if (++i >= MAX_PHASES) break; } phases_per_row[phase_0_raw_index] = 0; phases_per_row[phase_15_raw_index] = phases_15 + phases_0; } for (cnt = 0; cnt <= row_index; cnt++) { if (phases_per_row[cnt] > curr_max) { curr_max = phases_per_row[cnt]; selected_row_index = cnt; } } i = ((curr_max * 3) / 4); if (i) i--; ret = (int)ranges[selected_row_index][i]; if (ret >= MAX_PHASES) { ret = -EINVAL; pr_err("%s: %s: invalid phase selected=%d\n", mmc_hostname(mmc), __func__, ret); } pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__); return ret; } static inline void msm_cm_dll_set_freq(struct sdhci_host *host) { u32 mclk_freq = 0; /* Program the MCLK value to MCLK_FREQ bit field */ if (host->clock <= 112000000) mclk_freq = 0; else if (host->clock <= 125000000) mclk_freq = 1; else if (host->clock <= 137000000) mclk_freq = 2; else if (host->clock <= 150000000) mclk_freq = 3; else if (host->clock <= 162000000) mclk_freq = 4; else if (host->clock <= 175000000) mclk_freq = 5; else if (host->clock <= 187000000) mclk_freq = 6; else if (host->clock <= 200000000) mclk_freq = 7; writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & ~(7 << 24)) | (mclk_freq << 24)), host->ioaddr + CORE_DLL_CONFIG); } /* Initialize the DLL (Programmable Delay Line ) */ static int msm_init_cm_dll(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; int rc = 0; unsigned long flags; u32 wait_cnt; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); spin_lock_irqsave(&host->lock, flags); /* * Make sure that clock is always enabled when DLL * tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. So let's disable the PWRSAVE * here and re-enable it once tuning is completed. */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) & ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC); /* Write 1 to DLL_RST bit of DLL_CONFIG register */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG); /* Write 1 to DLL_PDN bit of DLL_CONFIG register */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG); msm_cm_dll_set_freq(host); /* Write 0 to DLL_RST bit of DLL_CONFIG register */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG); /* Write 0 to DLL_PDN bit of DLL_CONFIG register */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG); /* Set DLL_EN bit to 1. */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG); /* Set CK_OUT_EN bit to 1. */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG); wait_cnt = 50; /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) & CORE_DLL_LOCK)) { /* max. wait for 50us sec for LOCK bit to be set */ if (--wait_cnt == 0) { pr_err("%s: %s: DLL failed to LOCK\n", mmc_hostname(mmc), __func__); rc = -ETIMEDOUT; goto out; } /* wait for 1us before polling again */ udelay(1); } out: /* re-enable PWRSAVE */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) | CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC); spin_unlock_irqrestore(&host->lock, flags); pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__); return rc; } int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { unsigned long flags; u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0; const u32 *tuning_block_pattern = tuning_block_64; int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */ int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; /* * Tuning is required for SDR104 and HS200 cards and if clock frequency * is greater than 100MHz in these modes. */ if (host->clock <= (100 * 1000 * 1000) || !(ios.timing == MMC_TIMING_MMC_HS200 || ios.timing == MMC_TIMING_UHS_SDR104)) return 0; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); spin_lock_irqsave(&host->lock, flags); if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) && (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) { tuning_block_pattern = tuning_block_128; size = sizeof(tuning_block_128); } spin_unlock_irqrestore(&host->lock, flags); /* first of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) goto out; data_buf = kmalloc(size, GFP_KERNEL); if (!data_buf) { rc = -ENOMEM; goto out; } phase = 0; do { struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq = { .cmd = &cmd, .data = &data }; struct scatterlist sg; /* set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) goto kfree; cmd.opcode = opcode; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = size; data.blocks = 1; data.flags = MMC_DATA_READ; data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */ data.sg = &sg; data.sg_len = 1; sg_init_one(&sg, data_buf, size); memset(data_buf, 0, size); mmc_wait_for_req(mmc, &mrq); if (!cmd.error && !data.error && !memcmp(data_buf, tuning_block_pattern, size)) { /* tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; pr_debug("%s: %s: found good phase = %d\n", mmc_hostname(mmc), __func__, phase); } } while (++phase < 16); if (tuned_phase_cnt) { rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) goto kfree; else phase = (u8)rc; /* * Finally set the selected phase in delay * line hw block. */ rc = msm_config_cm_dll_phase(host, phase); if (rc) goto kfree; pr_debug("%s: %s: finally setting the tuning phase to %d\n", mmc_hostname(mmc), __func__, phase); } else { /* tuning failed */ pr_err("%s: %s: no tuning point found\n", mmc_hostname(mmc), __func__); rc = -EAGAIN; } kfree: kfree(data_buf); out: pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__); return rc; } static int sdhci_msm_setup_gpio(struct sdhci_msm_pltfm_data *pdata, bool enable) { struct sdhci_msm_gpio_data *curr; int i, ret = 0; curr = pdata->pin_data->gpio_data; for (i = 0; i < curr->size; i++) { if (!gpio_is_valid(curr->gpio[i].no)) { ret = -EINVAL; pr_err("%s: Invalid gpio = %d\n", __func__, curr->gpio[i].no); goto free_gpios; } if (enable) { ret = gpio_request(curr->gpio[i].no, curr->gpio[i].name); if (ret) { pr_err("%s: gpio_request(%d, %s) failed %d\n", __func__, curr->gpio[i].no, curr->gpio[i].name, ret); goto free_gpios; } curr->gpio[i].is_enabled = true; } else { gpio_free(curr->gpio[i].no); curr->gpio[i].is_enabled = false; } } return ret; free_gpios: for (i--; i >= 0; i--) { gpio_free(curr->gpio[i].no); curr->gpio[i].is_enabled = false; } return ret; } static int sdhci_msm_setup_pad(struct sdhci_msm_pltfm_data *pdata, bool enable) { struct sdhci_msm_pad_data *curr; int i; curr = pdata->pin_data->pad_data; for (i = 0; i < curr->drv->size; i++) { if (enable) msm_tlmm_set_hdrive(curr->drv->on[i].no, curr->drv->on[i].val); else msm_tlmm_set_hdrive(curr->drv->off[i].no, curr->drv->off[i].val); } for (i = 0; i < curr->pull->size; i++) { if (enable) msm_tlmm_set_pull(curr->pull->on[i].no, curr->pull->on[i].val); else msm_tlmm_set_pull(curr->pull->off[i].no, curr->pull->off[i].val); } return 0; } static int sdhci_msm_setup_pins(struct sdhci_msm_pltfm_data *pdata, bool enable) { int ret = 0; if (!pdata->pin_data || (pdata->pin_data->cfg_sts == enable)) return 0; if (pdata->pin_data->is_gpio) ret = sdhci_msm_setup_gpio(pdata, enable); else ret = sdhci_msm_setup_pad(pdata, enable); if (!ret) pdata->pin_data->cfg_sts = enable; return ret; } static int sdhci_msm_dt_get_array(struct device *dev, const char *prop_name, u32 **out, int *len, u32 size) { int ret = 0; struct device_node *np = dev->of_node; size_t sz; u32 *arr = NULL; if (!of_get_property(np, prop_name, len)) { ret = -EINVAL; goto out; } sz = *len = *len / sizeof(*arr); if (sz <= 0 || (size > 0 && (sz != size))) { dev_err(dev, "%s invalid size\n", prop_name); ret = -EINVAL; goto out; } arr = devm_kzalloc(dev, sz * sizeof(*arr), GFP_KERNEL); if (!arr) { dev_err(dev, "%s failed allocating memory\n", prop_name); ret = -ENOMEM; goto out; } ret = of_property_read_u32_array(np, prop_name, arr, sz); if (ret < 0) { dev_err(dev, "%s failed reading array %d\n", prop_name, ret); goto out; } *out = arr; out: if (ret) *len = 0; return ret; } #define MAX_PROP_SIZE 32 static int sdhci_msm_dt_parse_vreg_info(struct device *dev, struct sdhci_msm_reg_data **vreg_data, const char *vreg_name) { int len, ret = 0; const __be32 *prop; char prop_name[MAX_PROP_SIZE]; struct sdhci_msm_reg_data *vreg; struct device_node *np = dev->of_node; snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name); if (!of_parse_phandle(np, prop_name, 0)) { dev_err(dev, "No vreg data found for %s\n", vreg_name); ret = -EINVAL; return ret; } vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); if (!vreg) { dev_err(dev, "No memory for vreg: %s\n", vreg_name); ret = -ENOMEM; return ret; } vreg->name = vreg_name; snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-always-on", vreg_name); if (of_get_property(np, prop_name, NULL)) vreg->is_always_on = true; snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-lpm-sup", vreg_name); if (of_get_property(np, prop_name, NULL)) vreg->lpm_sup = true; snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-voltage-level", vreg_name); prop = of_get_property(np, prop_name, &len); if (!prop || (len != (2 * sizeof(__be32)))) { dev_warn(dev, "%s %s property\n", prop ? "invalid format" : "no", prop_name); } else { vreg->low_vol_level = be32_to_cpup(&prop[0]); vreg->high_vol_level = be32_to_cpup(&prop[1]); } snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-current-level", vreg_name); prop = of_get_property(np, prop_name, &len); if (!prop || (len != (2 * sizeof(__be32)))) { dev_warn(dev, "%s %s property\n", prop ? "invalid format" : "no", prop_name); } else { vreg->lpm_uA = be32_to_cpup(&prop[0]); vreg->hpm_uA = be32_to_cpup(&prop[1]); } *vreg_data = vreg; dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n", vreg->name, vreg->is_always_on ? "always_on," : "", vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level, vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA); return ret; } /* GPIO/Pad data extraction */ static int sdhci_msm_dt_get_pad_pull_info(struct device *dev, int id, struct sdhci_msm_pad_pull_data **pad_pull_data) { int ret = 0, base = 0, len, i; u32 *tmp; struct sdhci_msm_pad_pull_data *pull_data; struct sdhci_msm_pad_pull *pull; switch (id) { case 1: base = TLMM_PULL_SDC1_CLK; break; case 2: base = TLMM_PULL_SDC2_CLK; break; case 3: base = TLMM_PULL_SDC3_CLK; break; case 4: base = TLMM_PULL_SDC4_CLK; break; default: dev_err(dev, "%s: Invalid slot id\n", __func__); ret = -EINVAL; goto out; } pull_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_pull_data), GFP_KERNEL); if (!pull_data) { dev_err(dev, "No memory for msm_mmc_pad_pull_data\n"); ret = -ENOMEM; goto out; } pull_data->size = 3; /* array size for clk, cmd, data */ /* Allocate on, off configs for clk, cmd, data */ pull = devm_kzalloc(dev, 2 * pull_data->size *\ sizeof(struct sdhci_msm_pad_pull), GFP_KERNEL); if (!pull) { dev_err(dev, "No memory for msm_mmc_pad_pull\n"); ret = -ENOMEM; goto out; } pull_data->on = pull; pull_data->off = pull + pull_data->size; ret = sdhci_msm_dt_get_array(dev, "qcom,pad-pull-on", &tmp, &len, pull_data->size); if (ret) goto out; for (i = 0; i < len; i++) { pull_data->on[i].no = base + i; pull_data->on[i].val = tmp[i]; dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__, i, pull_data->on[i].val); } ret = sdhci_msm_dt_get_array(dev, "qcom,pad-pull-off", &tmp, &len, pull_data->size); if (ret) goto out; for (i = 0; i < len; i++) { pull_data->off[i].no = base + i; pull_data->off[i].val = tmp[i]; dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__, i, pull_data->off[i].val); } *pad_pull_data = pull_data; out: return ret; } static int sdhci_msm_dt_get_pad_drv_info(struct device *dev, int id, struct sdhci_msm_pad_drv_data **pad_drv_data) { int ret = 0, base = 0, len, i; u32 *tmp; struct sdhci_msm_pad_drv_data *drv_data; struct sdhci_msm_pad_drv *drv; switch (id) { case 1: base = TLMM_HDRV_SDC1_CLK; break; case 2: base = TLMM_HDRV_SDC2_CLK; break; case 3: base = TLMM_HDRV_SDC3_CLK; break; case 4: base = TLMM_HDRV_SDC4_CLK; break; default: dev_err(dev, "%s: Invalid slot id\n", __func__); ret = -EINVAL; goto out; } drv_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_drv_data), GFP_KERNEL); if (!drv_data) { dev_err(dev, "No memory for msm_mmc_pad_drv_data\n"); ret = -ENOMEM; goto out; } drv_data->size = 3; /* array size for clk, cmd, data */ /* Allocate on, off configs for clk, cmd, data */ drv = devm_kzalloc(dev, 2 * drv_data->size *\ sizeof(struct sdhci_msm_pad_drv), GFP_KERNEL); if (!drv) { dev_err(dev, "No memory msm_mmc_pad_drv\n"); ret = -ENOMEM; goto out; } drv_data->on = drv; drv_data->off = drv + drv_data->size; ret = sdhci_msm_dt_get_array(dev, "qcom,pad-drv-on", &tmp, &len, drv_data->size); if (ret) goto out; for (i = 0; i < len; i++) { drv_data->on[i].no = base + i; drv_data->on[i].val = tmp[i]; dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__, i, drv_data->on[i].val); } ret = sdhci_msm_dt_get_array(dev, "qcom,pad-drv-off", &tmp, &len, drv_data->size); if (ret) goto out; for (i = 0; i < len; i++) { drv_data->off[i].no = base + i; drv_data->off[i].val = tmp[i]; dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__, i, drv_data->off[i].val); } *pad_drv_data = drv_data; out: return ret; } #define GPIO_NAME_MAX_LEN 32 static int sdhci_msm_dt_parse_gpio_info(struct device *dev, struct sdhci_msm_pltfm_data *pdata) { int ret = 0, id = 0, cnt, i; struct sdhci_msm_pin_data *pin_data; struct device_node *np = dev->of_node; pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL); if (!pin_data) { dev_err(dev, "No memory for pin_data\n"); ret = -ENOMEM; goto out; } cnt = of_gpio_count(np); if (cnt > 0) { pin_data->is_gpio = true; pin_data->gpio_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_gpio_data), GFP_KERNEL); if (!pin_data->gpio_data) { dev_err(dev, "No memory for gpio_data\n"); ret = -ENOMEM; goto out; } pin_data->gpio_data->size = cnt; pin_data->gpio_data->gpio = devm_kzalloc(dev, cnt * sizeof(struct sdhci_msm_gpio), GFP_KERNEL); if (!pin_data->gpio_data->gpio) { dev_err(dev, "No memory for gpio\n"); ret = -ENOMEM; goto out; } for (i = 0; i < cnt; i++) { const char *name = NULL; char result[GPIO_NAME_MAX_LEN]; pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i); of_property_read_string_index(np, "qcom,gpio-names", i, &name); snprintf(result, GPIO_NAME_MAX_LEN, "%s-%s", dev_name(dev), name ? name : "?"); pin_data->gpio_data->gpio[i].name = result; dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__, pin_data->gpio_data->gpio[i].name, pin_data->gpio_data->gpio[i].no); } } else { pin_data->pad_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_data), GFP_KERNEL); if (!pin_data->pad_data) { dev_err(dev, "No memory for pin_data->pad_data\n"); ret = -ENOMEM; goto out; } ret = of_alias_get_id(np, "sdhc"); if (ret < 0) { dev_err(dev, "Failed to get slot index %d\n", ret); goto out; } id = ret; ret = sdhci_msm_dt_get_pad_pull_info( dev, id, &pin_data->pad_data->pull); if (ret) goto out; ret = sdhci_msm_dt_get_pad_drv_info( dev, id, &pin_data->pad_data->drv); if (ret) goto out; } pdata->pin_data = pin_data; out: if (ret) dev_err(dev, "%s failed with err %d\n", __func__, ret); return ret; } /* Parse platform data */ static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev) { struct sdhci_msm_pltfm_data *pdata = NULL; struct device_node *np = dev->of_node; u32 bus_width = 0; u32 cpu_dma_latency; int len, i; int clk_table_len; u32 *clk_table = NULL; enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(dev, "failed to allocate memory for platform data\n"); goto out; } pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags); if (gpio_is_valid(pdata->status_gpio) & !(flags & OF_GPIO_ACTIVE_LOW)) pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; of_property_read_u32(np, "qcom,bus-width", &bus_width); if (bus_width == 8) pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA; else if (bus_width == 4) pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA; else { dev_notice(dev, "invalid bus-width, default to 1-bit mode\n"); pdata->mmc_bus_width = 0; } if (!of_property_read_u32(np, "qcom,cpu-dma-latency-us", &cpu_dma_latency)) pdata->cpu_dma_latency_us = cpu_dma_latency; if (sdhci_msm_dt_get_array(dev, "qcom,clk-rates", &clk_table, &clk_table_len, 0)) { dev_err(dev, "failed parsing supported clock rates\n"); goto out; } if (!clk_table || !clk_table_len) { dev_err(dev, "Invalid clock table\n"); goto out; } pdata->sup_clk_table = clk_table; pdata->sup_clk_cnt = clk_table_len; pdata->vreg_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_slot_reg_data), GFP_KERNEL); if (!pdata->vreg_data) { dev_err(dev, "failed to allocate memory for vreg data\n"); goto out; } if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_data, "vdd")) { dev_err(dev, "failed parsing vdd data\n"); goto out; } if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_io_data, "vdd-io")) { dev_err(dev, "failed parsing vdd-io data\n"); goto out; } if (sdhci_msm_dt_parse_gpio_info(dev, pdata)) { dev_err(dev, "failed parsing gpio data\n"); goto out; } len = of_property_count_strings(np, "qcom,bus-speed-mode"); for (i = 0; i < len; i++) { const char *name = NULL; of_property_read_string_index(np, "qcom,bus-speed-mode", i, &name); if (!name) continue; if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v"))) pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR; else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v"))) pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR; else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v"))) pdata->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50; else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v"))) pdata->caps |= MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50; } if (of_get_property(np, "qcom,nonremovable", NULL)) pdata->nonremovable = true; return pdata; out: return NULL; } /* Returns required bandwidth in Bytes per Sec */ static unsigned int sdhci_get_bw_required(struct sdhci_host *host, struct mmc_ios *ios) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; unsigned int bw; bw = msm_host->clk_rate; /* * For DDR mode, SDCC controller clock will be at * the double rate than the actual clock that goes to card. */ if (ios->bus_width == MMC_BUS_WIDTH_4) bw /= 2; else if (ios->bus_width == MMC_BUS_WIDTH_1) bw /= 8; return bw; } static int sdhci_msm_bus_get_vote_for_bw(struct sdhci_msm_host *host, unsigned int bw) { unsigned int *table = host->pdata->voting_data->bw_vecs; unsigned int size = host->pdata->voting_data->bw_vecs_size; int i; if (host->msm_bus_vote.is_max_bw_needed && bw) return host->msm_bus_vote.max_bw_vote; for (i = 0; i < size; i++) { if (bw <= table[i]) break; } if (i && (i == size)) i--; return i; } /* * This function must be called with host lock acquired. * Caller of this function should also ensure that msm bus client * handle is not null. */ static inline int sdhci_msm_bus_set_vote(struct sdhci_msm_host *msm_host, int vote, unsigned long flags) { struct sdhci_host *host = platform_get_drvdata(msm_host->pdev); int rc = 0; if (vote != msm_host->msm_bus_vote.curr_vote) { spin_unlock_irqrestore(&host->lock, flags); rc = msm_bus_scale_client_update_request( msm_host->msm_bus_vote.client_handle, vote); spin_lock_irqsave(&host->lock, flags); if (rc) { pr_err("%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n", mmc_hostname(host->mmc), msm_host->msm_bus_vote.client_handle, vote, rc); goto out; } msm_host->msm_bus_vote.curr_vote = vote; } out: return rc; } /* * Internal work. Work to set 0 bandwidth for msm bus. */ static void sdhci_msm_bus_work(struct work_struct *work) { struct sdhci_msm_host *msm_host; struct sdhci_host *host; unsigned long flags; msm_host = container_of(work, struct sdhci_msm_host, msm_bus_vote.vote_work.work); host = platform_get_drvdata(msm_host->pdev); if (!msm_host->msm_bus_vote.client_handle) return; spin_lock_irqsave(&host->lock, flags); /* don't vote for 0 bandwidth if any request is in progress */ if (!host->mrq) { sdhci_msm_bus_set_vote(msm_host, msm_host->msm_bus_vote.min_bw_vote, flags); } else pr_warning("%s: %s: Transfer in progress. skipping bus voting to 0 bandwidth\n", mmc_hostname(host->mmc), __func__); spin_unlock_irqrestore(&host->lock, flags); } /* * This function cancels any scheduled delayed work and sets the bus * vote based on bw (bandwidth) argument. */ static void sdhci_msm_bus_cancel_work_and_set_vote(struct sdhci_host *host, unsigned int bw) { int vote; unsigned long flags; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; cancel_delayed_work_sync(&msm_host->msm_bus_vote.vote_work); spin_lock_irqsave(&host->lock, flags); vote = sdhci_msm_bus_get_vote_for_bw(msm_host, bw); sdhci_msm_bus_set_vote(msm_host, vote, flags); spin_unlock_irqrestore(&host->lock, flags); } #define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */ /* This function queues a work which will set the bandwidth requiement to 0 */ static void sdhci_msm_bus_queue_work(struct sdhci_host *host) { unsigned long flags; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; spin_lock_irqsave(&host->lock, flags); if (msm_host->msm_bus_vote.min_bw_vote != msm_host->msm_bus_vote.curr_vote) queue_delayed_work(system_nrt_wq, &msm_host->msm_bus_vote.vote_work, msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY)); spin_unlock_irqrestore(&host->lock, flags); } static int sdhci_msm_bus_register(struct sdhci_msm_host *host, struct platform_device *pdev) { int rc = 0; struct msm_bus_scale_pdata *bus_pdata; struct sdhci_msm_bus_voting_data *data; struct device *dev = &pdev->dev; data = devm_kzalloc(dev, sizeof(struct sdhci_msm_bus_voting_data), GFP_KERNEL); if (!data) { dev_err(&pdev->dev, "%s: failed to allocate memory\n", __func__); rc = -ENOMEM; goto out; } data->bus_pdata = msm_bus_cl_get_pdata(pdev); if (data->bus_pdata) { rc = sdhci_msm_dt_get_array(dev, "qcom,bus-bw-vectors-bps", &data->bw_vecs, &data->bw_vecs_size, 0); if (rc) { dev_err(&pdev->dev, "%s: Failed to get bus-bw-vectors-bps\n", __func__); goto out; } host->pdata->voting_data = data; } if (host->pdata->voting_data && host->pdata->voting_data->bus_pdata && host->pdata->voting_data->bw_vecs && host->pdata->voting_data->bw_vecs_size) { bus_pdata = host->pdata->voting_data->bus_pdata; host->msm_bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata); if (!host->msm_bus_vote.client_handle) { dev_err(&pdev->dev, "msm_bus_scale_register_client()\n"); rc = -EFAULT; goto out; } /* cache the vote index for minimum and maximum bandwidth */ host->msm_bus_vote.min_bw_vote = sdhci_msm_bus_get_vote_for_bw(host, 0); host->msm_bus_vote.max_bw_vote = sdhci_msm_bus_get_vote_for_bw(host, UINT_MAX); } else { devm_kfree(dev, data); } out: return rc; } static void sdhci_msm_bus_unregister(struct sdhci_msm_host *host) { if (host->msm_bus_vote.client_handle) msm_bus_scale_unregister_client( host->msm_bus_vote.client_handle); } static void sdhci_msm_bus_voting(struct sdhci_host *host, u32 enable) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct mmc_ios *ios = &host->mmc->ios; unsigned int bw; if (!msm_host->msm_bus_vote.client_handle) return; bw = sdhci_get_bw_required(host, ios); if (enable) { sdhci_msm_bus_cancel_work_and_set_vote(host, bw); } else { /* * If clock gating is enabled, then remove the vote * immediately because clocks will be disabled only * after SDHCI_MSM_MMC_CLK_GATE_DELAY and thus no * additional delay is required to remove the bus vote. */ if (host->mmc->clkgate_delay) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); else sdhci_msm_bus_queue_work(host); } } /* Regulator utility functions */ static int sdhci_msm_vreg_init_reg(struct device *dev, struct sdhci_msm_reg_data *vreg) { int ret = 0; /* check if regulator is already initialized? */ if (vreg->reg) goto out; /* Get the regulator handle */ vreg->reg = devm_regulator_get(dev, vreg->name); if (IS_ERR(vreg->reg)) { ret = PTR_ERR(vreg->reg); pr_err("%s: devm_regulator_get(%s) failed. ret=%d\n", __func__, vreg->name, ret); goto out; } /* sanity check */ if (!vreg->high_vol_level || !vreg->hpm_uA) { pr_err("%s: %s invalid constraints specified\n", __func__, vreg->name); ret = -EINVAL; } out: return ret; } static void sdhci_msm_vreg_deinit_reg(struct sdhci_msm_reg_data *vreg) { if (vreg->reg) devm_regulator_put(vreg->reg); } static int sdhci_msm_vreg_set_optimum_mode(struct sdhci_msm_reg_data *vreg, int uA_load) { int ret = 0; /* * regulators that do not support regulator_set_voltage also * do not support regulator_set_optimum_mode */ ret = regulator_set_optimum_mode(vreg->reg, uA_load); if (ret < 0) pr_err("%s: regulator_set_optimum_mode(reg=%s,uA_load=%d) failed. ret=%d\n", __func__, vreg->name, uA_load, ret); else /* * regulator_set_optimum_mode() can return non zero * value even for success case. */ ret = 0; return ret; } static int sdhci_msm_vreg_set_voltage(struct sdhci_msm_reg_data *vreg, int min_uV, int max_uV) { int ret = 0; ret = regulator_set_voltage(vreg->reg, min_uV, max_uV); if (ret) { pr_err("%s: regulator_set_voltage(%s)failed. min_uV=%d,max_uV=%d,ret=%d\n", __func__, vreg->name, min_uV, max_uV, ret); } return ret; } static int sdhci_msm_vreg_enable(struct sdhci_msm_reg_data *vreg) { int ret = 0; /* Put regulator in HPM (high power mode) */ ret = sdhci_msm_vreg_set_optimum_mode(vreg, vreg->hpm_uA); if (ret < 0) return ret; if (!vreg->is_enabled) { /* Set voltage level */ ret = sdhci_msm_vreg_set_voltage(vreg, vreg->high_vol_level, vreg->high_vol_level); if (ret) return ret; } ret = regulator_enable(vreg->reg); if (ret) { pr_err("%s: regulator_enable(%s) failed. ret=%d\n", __func__, vreg->name, ret); return ret; } vreg->is_enabled = true; return ret; } static int sdhci_msm_vreg_disable(struct sdhci_msm_reg_data *vreg) { int ret = 0; /* Never disable regulator marked as always_on */ if (vreg->is_enabled && !vreg->is_always_on) { ret = regulator_disable(vreg->reg); if (ret) { pr_err("%s: regulator_disable(%s) failed. ret=%d\n", __func__, vreg->name, ret); goto out; } vreg->is_enabled = false; ret = sdhci_msm_vreg_set_optimum_mode(vreg, 0); if (ret < 0) goto out; /* Set min. voltage level to 0 */ ret = sdhci_msm_vreg_set_voltage(vreg, 0, vreg->high_vol_level); if (ret) goto out; } else if (vreg->is_enabled && vreg->is_always_on) { if (vreg->lpm_sup) { /* Put always_on regulator in LPM (low power mode) */ ret = sdhci_msm_vreg_set_optimum_mode(vreg, vreg->lpm_uA); if (ret < 0) goto out; } } out: return ret; } static int sdhci_msm_setup_vreg(struct sdhci_msm_pltfm_data *pdata, bool enable, bool is_init) { int ret = 0, i; struct sdhci_msm_slot_reg_data *curr_slot; struct sdhci_msm_reg_data *vreg_table[2]; curr_slot = pdata->vreg_data; if (!curr_slot) { pr_debug("%s: vreg info unavailable,assuming the slot is powered by always on domain\n", __func__); goto out; } vreg_table[0] = curr_slot->vdd_data; vreg_table[1] = curr_slot->vdd_io_data; for (i = 0; i < ARRAY_SIZE(vreg_table); i++) { if (vreg_table[i]) { if (enable) ret = sdhci_msm_vreg_enable(vreg_table[i]); else ret = sdhci_msm_vreg_disable(vreg_table[i]); if (ret) goto out; } } out: return ret; } /* * Reset vreg by ensuring it is off during probe. A call * to enable vreg is needed to balance disable vreg */ static int sdhci_msm_vreg_reset(struct sdhci_msm_pltfm_data *pdata) { int ret; ret = sdhci_msm_setup_vreg(pdata, 1, true); if (ret) return ret; ret = sdhci_msm_setup_vreg(pdata, 0, true); return ret; } /* This init function should be called only once for each SDHC slot */ static int sdhci_msm_vreg_init(struct device *dev, struct sdhci_msm_pltfm_data *pdata, bool is_init) { int ret = 0; struct sdhci_msm_slot_reg_data *curr_slot; struct sdhci_msm_reg_data *curr_vdd_reg, *curr_vdd_io_reg; curr_slot = pdata->vreg_data; if (!curr_slot) goto out; curr_vdd_reg = curr_slot->vdd_data; curr_vdd_io_reg = curr_slot->vdd_io_data; if (!is_init) /* Deregister all regulators from regulator framework */ goto vdd_io_reg_deinit; /* * Get the regulator handle from voltage regulator framework * and then try to set the voltage level for the regulator */ if (curr_vdd_reg) { ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_reg); if (ret) goto out; } if (curr_vdd_io_reg) { ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_io_reg); if (ret) goto vdd_reg_deinit; } ret = sdhci_msm_vreg_reset(pdata); if (ret) dev_err(dev, "vreg reset failed (%d)\n", ret); goto out; vdd_io_reg_deinit: if (curr_vdd_io_reg) sdhci_msm_vreg_deinit_reg(curr_vdd_io_reg); vdd_reg_deinit: if (curr_vdd_reg) sdhci_msm_vreg_deinit_reg(curr_vdd_reg); out: return ret; } static int sdhci_msm_set_vdd_io_vol(struct sdhci_msm_pltfm_data *pdata, enum vdd_io_level level, unsigned int voltage_level) { int ret = 0; int set_level; struct sdhci_msm_reg_data *vdd_io_reg; if (!pdata->vreg_data) return ret; vdd_io_reg = pdata->vreg_data->vdd_io_data; if (vdd_io_reg && vdd_io_reg->is_enabled) { switch (level) { case VDD_IO_LOW: set_level = vdd_io_reg->low_vol_level; break; case VDD_IO_HIGH: set_level = vdd_io_reg->high_vol_level; break; case VDD_IO_SET_LEVEL: set_level = voltage_level; break; default: pr_err("%s: invalid argument level = %d", __func__, level); ret = -EINVAL; return ret; } ret = sdhci_msm_vreg_set_voltage(vdd_io_reg, set_level, set_level); } return ret; } static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) { struct sdhci_host *host = (struct sdhci_host *)data; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; u8 irq_status = 0; u8 irq_ack = 0; int ret = 0; int pwr_state = 0, io_level = 0; unsigned long flags; irq_status = readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); pr_debug("%s: Received IRQ(%d), status=0x%x\n", mmc_hostname(msm_host->mmc), irq, irq_status); /* Clear the interrupt */ writeb_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR)); /* * SDHC has core_mem and hc_mem device memory and these memory * addresses do not fall within 1KB region. Hence, any update to * core_mem address space would require an mb() to ensure this gets * completed before its next update to registers within hc_mem. */ mb(); /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { ret = sdhci_msm_setup_vreg(msm_host->pdata, true, false); if (!ret) { ret = sdhci_msm_setup_pins(msm_host->pdata, true); ret |= sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_HIGH, 0); } if (ret) irq_ack |= CORE_PWRCTL_BUS_FAIL; else irq_ack |= CORE_PWRCTL_BUS_SUCCESS; pwr_state = REQ_BUS_ON; io_level = REQ_IO_HIGH; } if (irq_status & CORE_PWRCTL_BUS_OFF) { ret = sdhci_msm_setup_vreg(msm_host->pdata, false, false); if (!ret) { ret = sdhci_msm_setup_pins(msm_host->pdata, false); ret |= sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_LOW, 0); } if (ret) irq_ack |= CORE_PWRCTL_BUS_FAIL; else irq_ack |= CORE_PWRCTL_BUS_SUCCESS; pwr_state = REQ_BUS_OFF; io_level = REQ_IO_LOW; } /* Handle IO LOW/HIGH */ if (irq_status & CORE_PWRCTL_IO_LOW) { /* Switch voltage Low */ ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_LOW, 0); if (ret) irq_ack |= CORE_PWRCTL_IO_FAIL; else irq_ack |= CORE_PWRCTL_IO_SUCCESS; io_level = REQ_IO_LOW; } if (irq_status & CORE_PWRCTL_IO_HIGH) { /* Switch voltage High */ ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_HIGH, 0); if (ret) irq_ack |= CORE_PWRCTL_IO_FAIL; else irq_ack |= CORE_PWRCTL_IO_SUCCESS; io_level = REQ_IO_HIGH; } /* ACK status to the core */ writeb_relaxed(irq_ack, (msm_host->core_mem + CORE_PWRCTL_CTL)); /* * SDHC has core_mem and hc_mem device memory and these memory * addresses do not fall within 1KB region. Hence, any update to * core_mem address space would require an mb() to ensure this gets * completed before its next update to registers within hc_mem. */ mb(); if (io_level & REQ_IO_HIGH) writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) & ~CORE_IO_PAD_PWR_SWITCH), host->ioaddr + CORE_VENDOR_SPEC); else if (io_level & REQ_IO_LOW) writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) | CORE_IO_PAD_PWR_SWITCH), host->ioaddr + CORE_VENDOR_SPEC); mb(); pr_debug("%s: Handled IRQ(%d), ret=%d, ack=0x%x\n", mmc_hostname(msm_host->mmc), irq, ret, irq_ack); spin_lock_irqsave(&host->lock, flags); if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) msm_host->curr_io_level = io_level; complete(&msm_host->pwr_irq_completion); spin_unlock_irqrestore(&host->lock, flags); return IRQ_HANDLED; } /* This function returns the max. current supported by VDD rail in mA */ static unsigned int sdhci_msm_get_vreg_vdd_max_current(struct sdhci_msm_host *host) { struct sdhci_msm_slot_reg_data *curr_slot = host->pdata->vreg_data; if (!curr_slot) return 0; if (curr_slot->vdd_data) return curr_slot->vdd_data->hpm_uA / 1000; else return 0; } static ssize_t show_sdhci_max_bus_bw(struct device *dev, struct device_attribute *attr, char *buf) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; return snprintf(buf, PAGE_SIZE, "%u\n", msm_host->msm_bus_vote.is_max_bw_needed); } static ssize_t store_sdhci_max_bus_bw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; uint32_t value; unsigned long flags; if (!kstrtou32(buf, 0, &value)) { spin_lock_irqsave(&host->lock, flags); msm_host->msm_bus_vote.is_max_bw_needed = !!value; spin_unlock_irqrestore(&host->lock, flags); } return count; } static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; unsigned long flags; bool done = false; spin_lock_irqsave(&host->lock, flags); pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n", mmc_hostname(host->mmc), __func__, req_type, msm_host->curr_pwr_state, msm_host->curr_io_level); if ((req_type & msm_host->curr_pwr_state) || (req_type & msm_host->curr_io_level)) done = true; spin_unlock_irqrestore(&host->lock, flags); /* * This is needed here to hanlde a case where IRQ gets * triggered even before this function is called so that * x->done counter of completion gets reset. Otherwise, * next call to wait_for_completion returns immediately * without actually waiting for the IRQ to be handled. */ if (done) init_completion(&msm_host->pwr_irq_completion); else wait_for_completion(&msm_host->pwr_irq_completion); pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), __func__, req_type); } static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable) { if (enable) writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_CDR_EN), host->ioaddr + CORE_DLL_CONFIG); else writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) & ~CORE_CDR_EN), host->ioaddr + CORE_DLL_CONFIG); } static unsigned int sdhci_msm_max_segs(void) { return SDHCI_MSM_MAX_SEGMENTS; } static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; return msm_host->pdata->sup_clk_table[0]; } static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; int max_clk_index = msm_host->pdata->sup_clk_cnt; return msm_host->pdata->sup_clk_table[max_clk_index - 1]; } static unsigned int sdhci_msm_get_sup_clk_rate(struct sdhci_host *host, u32 req_clk) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; unsigned int sel_clk = -1; unsigned char cnt; if (req_clk < sdhci_msm_get_min_clock(host)) { sel_clk = sdhci_msm_get_min_clock(host); return sel_clk; } for (cnt = 0; cnt < msm_host->pdata->sup_clk_cnt; cnt++) { if (msm_host->pdata->sup_clk_table[cnt] > req_clk) { break; } else if (msm_host->pdata->sup_clk_table[cnt] == req_clk) { sel_clk = msm_host->pdata->sup_clk_table[cnt]; break; } else { sel_clk = msm_host->pdata->sup_clk_table[cnt]; } } return sel_clk; } static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; int rc = 0; if (enable && !atomic_read(&msm_host->clks_on)) { pr_debug("%s: request to enable clocks\n", mmc_hostname(host->mmc)); sdhci_msm_bus_voting(host, 1); if (!IS_ERR_OR_NULL(msm_host->bus_clk)) { rc = clk_prepare_enable(msm_host->bus_clk); if (rc) { pr_err("%s: %s: failed to enable the bus-clock with error %d\n", mmc_hostname(host->mmc), __func__, rc); goto remove_vote; } } if (!IS_ERR(msm_host->pclk)) { rc = clk_prepare_enable(msm_host->pclk); if (rc) { pr_err("%s: %s: failed to enable the pclk with error %d\n", mmc_hostname(host->mmc), __func__, rc); goto disable_bus_clk; } } rc = clk_prepare_enable(msm_host->clk); if (rc) { pr_err("%s: %s: failed to enable the host-clk with error %d\n", mmc_hostname(host->mmc), __func__, rc); goto disable_pclk; } mb(); } else if (!enable && atomic_read(&msm_host->clks_on)) { pr_debug("%s: request to disable clocks\n", mmc_hostname(host->mmc)); sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); mb(); clk_disable_unprepare(msm_host->clk); if (!IS_ERR(msm_host->pclk)) clk_disable_unprepare(msm_host->pclk); if (!IS_ERR_OR_NULL(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); sdhci_msm_bus_voting(host, 0); } atomic_set(&msm_host->clks_on, enable); goto out; disable_pclk: if (!IS_ERR_OR_NULL(msm_host->pclk)) clk_disable_unprepare(msm_host->pclk); disable_bus_clk: if (!IS_ERR_OR_NULL(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); remove_vote: if (msm_host->msm_bus_vote.client_handle) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); out: return rc; } static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) { int rc; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct mmc_ios curr_ios = host->mmc->ios; u32 sup_clock, ddr_clock; if (!clock) { sdhci_msm_prepare_clocks(host, false); host->clock = clock; return; } rc = sdhci_msm_prepare_clocks(host, true); if (rc) return; sup_clock = sdhci_msm_get_sup_clk_rate(host, clock); if (curr_ios.timing == MMC_TIMING_UHS_DDR50) { /* * The SDHC requires internal clock frequency to be double the * actual clock that will be set for DDR mode. The controller * uses the faster clock(100MHz) for some of its parts and send * the actual required clock (50MHz) to the card. */ ddr_clock = clock * 2; sup_clock = sdhci_msm_get_sup_clk_rate(host, ddr_clock); } if (sup_clock != msm_host->clk_rate) { pr_debug("%s: %s: setting clk rate to %u\n", mmc_hostname(host->mmc), __func__, sup_clock); rc = clk_set_rate(msm_host->clk, sup_clock); if (rc) { pr_err("%s: %s: Failed to set rate %u for host-clk : %d\n", mmc_hostname(host->mmc), __func__, sup_clock, rc); return; } msm_host->clk_rate = sup_clock; host->clock = clock; /* * Update the bus vote in case of frequency change due to * clock scaling. */ sdhci_msm_bus_voting(host, 1); } } static int sdhci_msm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { u16 ctrl_2; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; if (uhs == MMC_TIMING_MMC_HS200) ctrl_2 |= SDHCI_CTRL_UHS_SDR104; else if (uhs == MMC_TIMING_UHS_SDR12) ctrl_2 |= SDHCI_CTRL_UHS_SDR12; else if (uhs == MMC_TIMING_UHS_SDR25) ctrl_2 |= SDHCI_CTRL_UHS_SDR25; else if (uhs == MMC_TIMING_UHS_SDR50) ctrl_2 |= SDHCI_CTRL_UHS_SDR50; else if (uhs == MMC_TIMING_UHS_SDR104) ctrl_2 |= SDHCI_CTRL_UHS_SDR104; else if (uhs == MMC_TIMING_UHS_DDR50) ctrl_2 |= SDHCI_CTRL_UHS_DDR50; /* * When clock frquency is less than 100MHz, the feedback clock must be * provided and DLL must not be used so that tuning can be skipped. To * provide feedback clock, the mode selection can be any value less * than 3'b011 in bits [2:0] of HOST CONTROL2 register. */ if (host->clock <= (100 * 1000 * 1000) && (uhs == MMC_TIMING_MMC_HS200 || uhs == MMC_TIMING_UHS_SDR104)) ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); return 0; } /* * sdhci_msm_disable_data_xfer - disable undergoing AHB bus data transfer * * Write 0 to bit 0 in MCI_DATA_CTL (offset 0x2C) - clearing TxActive bit by * access to legacy registers. It will stop current burst and prevent start of * the next on. * * Polling CORE_AHB_DATA_DELAY_US timeout, by reading bit 13:12 until they are 0 * in CORE_SDCC_DEBUG_REG (offset 0x124) will validate that AHB burst was * completed and a new one didn't start. * * Waiting for 4us while AHB finishes descriptors fetch. */ static void sdhci_msm_disable_data_xfer(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; u32 value; int ret; value = readl_relaxed(msm_host->core_mem + CORE_MCI_DATA_CTRL); value &= ~(u32)CORE_MCI_DPSM_ENABLE; writel_relaxed(value, msm_host->core_mem + CORE_MCI_DATA_CTRL); /* Enable the test bus for device slot */ writel_relaxed(CORE_TESTBUS_ENA | CORE_TESTBUS_SEL2, msm_host->core_mem + CORE_TESTBUS_CONFIG); ret = readl_poll_timeout_noirq(msm_host->core_mem + CORE_SDCC_DEBUG_REG, value, !(value & CORE_DEBUG_REG_AHB_HTRANS), CORE_AHB_DATA_DELAY_US, 1); if (ret) { pr_err("%s: %s: can't stop ongoing AHB bus access by ADMA\n", mmc_hostname(host->mmc), __func__); BUG(); } /* Disable the test bus for device slot */ value = readl_relaxed(msm_host->core_mem + CORE_TESTBUS_CONFIG); value &= ~CORE_TESTBUS_ENA; writel_relaxed(value, msm_host->core_mem + CORE_TESTBUS_CONFIG); udelay(CORE_AHB_DESC_DELAY_US); } static struct sdhci_ops sdhci_msm_ops = { .set_uhs_signaling = sdhci_msm_set_uhs_signaling, .check_power_status = sdhci_msm_check_power_status, .execute_tuning = sdhci_msm_execute_tuning, .toggle_cdr = sdhci_msm_toggle_cdr, .get_max_segments = sdhci_msm_max_segs, .set_clock = sdhci_msm_set_clock, .get_min_clock = sdhci_msm_get_min_clock, .get_max_clock = sdhci_msm_get_max_clock, .disable_data_xfer = sdhci_msm_disable_data_xfer, }; static int __devinit sdhci_msm_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_msm_host *msm_host; struct resource *core_memres = NULL; int ret = 0, dead = 0; u32 vdd_max_current; u16 host_version; u32 pwr, irq_status, irq_ctl; pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__); msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host), GFP_KERNEL); if (!msm_host) { ret = -ENOMEM; goto out; } msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops; host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata); if (IS_ERR(host)) { ret = PTR_ERR(host); goto out; } pltfm_host = sdhci_priv(host); pltfm_host->priv = msm_host; msm_host->mmc = host->mmc; msm_host->pdev = pdev; /* Extract platform data */ if (pdev->dev.of_node) { ret = of_alias_get_id(pdev->dev.of_node, "sdhc"); if (ret < 0) { dev_err(&pdev->dev, "Failed to get slot index %d\n", ret); goto pltfm_free; } if (disable_slots & (1 << (ret - 1))) { dev_info(&pdev->dev, "%s: Slot %d disabled\n", __func__, ret); ret = -ENODEV; goto pltfm_free; } msm_host->pdata = sdhci_msm_populate_pdata(&pdev->dev); if (!msm_host->pdata) { dev_err(&pdev->dev, "DT parsing error\n"); goto pltfm_free; } } else { dev_err(&pdev->dev, "No device tree node\n"); goto pltfm_free; } /* Setup Clocks */ /* Setup SDCC bus voter clock. */ msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); if (!IS_ERR_OR_NULL(msm_host->bus_clk)) { /* Vote for max. clk rate for max. performance */ ret = clk_set_rate(msm_host->bus_clk, INT_MAX); if (ret) goto pltfm_free; ret = clk_prepare_enable(msm_host->bus_clk); if (ret) goto pltfm_free; } /* Setup main peripheral bus clock */ msm_host->pclk = devm_clk_get(&pdev->dev, "iface_clk"); if (!IS_ERR(msm_host->pclk)) { ret = clk_prepare_enable(msm_host->pclk); if (ret) goto bus_clk_disable; } /* Setup SDC MMC clock */ msm_host->clk = devm_clk_get(&pdev->dev, "core_clk"); if (IS_ERR(msm_host->clk)) { ret = PTR_ERR(msm_host->clk); goto pclk_disable; } /* Set to the minimum supported clock frequency */ ret = clk_set_rate(msm_host->clk, sdhci_msm_get_min_clock(host)); if (ret) { dev_err(&pdev->dev, "MClk rate set failed (%d)\n", ret); goto pclk_disable; } ret = clk_prepare_enable(msm_host->clk); if (ret) goto pclk_disable; msm_host->clk_rate = sdhci_msm_get_min_clock(host); atomic_set(&msm_host->clks_on, 1); ret = sdhci_msm_bus_register(msm_host, pdev); if (ret) goto clk_disable; if (msm_host->msm_bus_vote.client_handle) INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work, sdhci_msm_bus_work); sdhci_msm_bus_voting(host, 1); /* Setup regulators */ ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true); if (ret) { dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret); goto bus_unregister; } /* Reset the core and Enable SDHC mode */ core_memres = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core_mem"); msm_host->core_mem = devm_ioremap(&pdev->dev, core_memres->start, resource_size(core_memres)); if (!msm_host->core_mem) { dev_err(&pdev->dev, "Failed to remap registers\n"); ret = -ENOMEM; goto vreg_deinit; } /* Set SW_RST bit in POWER register (Offset 0x0) */ writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) | CORE_SW_RST, msm_host->core_mem + CORE_POWER); /* * SW reset can take upto 10HCLK + 15MCLK cycles. * Calculating based on min clk rates (hclk = 27MHz, * mclk = 400KHz) it comes to ~40us. Let's poll for * max. 1ms for reset completion. */ ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER, pwr, !(pwr & CORE_SW_RST), 100, 10); if (ret) { dev_err(&pdev->dev, "reset failed (%d)\n", ret); goto vreg_deinit; } /* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); /* * CORE_SW_RST above may trigger power irq if previous status of PWRCTL * was either BUS_ON or IO_HIGH_V. So before we enable the power irq * interrupt in GIC (by registering the interrupt handler), we need to * ensure that any pending power irq interrupt status is acknowledged * otherwise power irq interrupt handler would be fired prematurely. */ irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); writel_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR)); irq_ctl = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL); if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF)) irq_ctl |= CORE_PWRCTL_BUS_SUCCESS; if (irq_status & (CORE_PWRCTL_IO_HIGH | CORE_PWRCTL_IO_LOW)) irq_ctl |= CORE_PWRCTL_IO_SUCCESS; writel_relaxed(irq_ctl, (msm_host->core_mem + CORE_PWRCTL_CTL)); /* * Ensure that above writes are propogated before interrupt enablement * in GIC. */ mb(); /* * Following are the deviations from SDHC spec v3.0 - * 1. Card detection is handled using separate GPIO. * 2. Bus power control is handled by interacting with PMIC. */ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE; host->quirks |= SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; host->quirks2 |= SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK; host->quirks2 |= SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING; host->quirks2 |= SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE; host->quirks2 |= SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD; host->quirks2 |= SDHCI_QUIRK2_BROKEN_PRESET_VALUE; host->quirks2 |= SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT; 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) >> SDHCI_VENDOR_VER_SHIFT)); if (((host_version & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT) == SDHCI_VER_100) { /* * Add 40us delay in interrupt handler when * operating at initialization frequency(400KHz). */ host->quirks2 |= SDHCI_QUIRK2_SLOW_INT_CLR; /* * Set Software Reset for DAT line in Software * Reset Register (Bit 2). */ host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT; } /* Setup PWRCTL irq */ msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); if (msm_host->pwr_irq < 0) { dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n", msm_host->pwr_irq); goto vreg_deinit; } 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 threaded irq(%d) failed (%d)\n", msm_host->pwr_irq, ret); goto vreg_deinit; } /* Enable pwr irq interrupts */ writel_relaxed(INT_MASK, (msm_host->core_mem + CORE_PWRCTL_MASK)); /* Set clock gating delay to be used when CONFIG_MMC_CLKGATE is set */ msm_host->mmc->clkgate_delay = SDHCI_MSM_MMC_CLK_GATE_DELAY; /* Set host capabilities */ msm_host->mmc->caps |= msm_host->pdata->mmc_bus_width; msm_host->mmc->caps |= msm_host->pdata->caps; vdd_max_current = sdhci_msm_get_vreg_vdd_max_current(msm_host); if (vdd_max_current >= 800) msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_800; else if (vdd_max_current >= 600) msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_600; else if (vdd_max_current >= 400) msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_400; else msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_200; if (vdd_max_current > 150) msm_host->mmc->caps |= MMC_CAP_SET_XPC_180 | MMC_CAP_SET_XPC_300| MMC_CAP_SET_XPC_330; msm_host->mmc->caps |= MMC_CAP_HW_RESET; msm_host->mmc->caps2 |= msm_host->pdata->caps2; msm_host->mmc->caps2 |= MMC_CAP2_CORE_RUNTIME_PM; msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR; msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL; msm_host->mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR); msm_host->mmc->caps2 |= MMC_CAP2_SANITIZE; msm_host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL; msm_host->mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY; msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE; msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST; if (msm_host->pdata->nonremovable) msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE; host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us; init_completion(&msm_host->pwr_irq_completion); if (gpio_is_valid(msm_host->pdata->status_gpio)) { ret = mmc_cd_gpio_request(msm_host->mmc, msm_host->pdata->status_gpio); if (ret) { dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n", __func__, ret); goto vreg_deinit; } } if (dma_supported(mmc_dev(host->mmc), DMA_BIT_MASK(32))) { host->dma_mask = DMA_BIT_MASK(32); mmc_dev(host->mmc)->dma_mask = &host->dma_mask; } else { dev_err(&pdev->dev, "%s: Failed to set dma mask\n", __func__); } ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "Add host failed (%d)\n", ret); goto free_cd_gpio; } msm_host->msm_bus_vote.max_bus_bw.show = show_sdhci_max_bus_bw; msm_host->msm_bus_vote.max_bus_bw.store = store_sdhci_max_bus_bw; sysfs_attr_init(&msm_host->msm_bus_vote.max_bus_bw.attr); msm_host->msm_bus_vote.max_bus_bw.attr.name = "max_bus_bw"; msm_host->msm_bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; ret = device_create_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw); if (ret) goto remove_host; ret = pm_runtime_set_active(&pdev->dev); if (ret) pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n", mmc_hostname(host->mmc), __func__, ret); else pm_runtime_enable(&pdev->dev); /* Successful initialization */ goto out; remove_host: dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); free_cd_gpio: if (gpio_is_valid(msm_host->pdata->status_gpio)) mmc_cd_gpio_free(msm_host->mmc); vreg_deinit: sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false); bus_unregister: if (msm_host->msm_bus_vote.client_handle) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); sdhci_msm_bus_unregister(msm_host); clk_disable: if (!IS_ERR(msm_host->clk)) clk_disable_unprepare(msm_host->clk); pclk_disable: if (!IS_ERR(msm_host->pclk)) clk_disable_unprepare(msm_host->pclk); bus_clk_disable: if (!IS_ERR_OR_NULL(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); pltfm_free: sdhci_pltfm_free(pdev); out: pr_debug("%s: Exit %s\n", dev_name(&pdev->dev), __func__); return ret; } static int __devexit 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_pltfm_data *pdata = msm_host->pdata; int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__); device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw); sdhci_remove_host(host, dead); pm_runtime_disable(&pdev->dev); sdhci_pltfm_free(pdev); if (gpio_is_valid(msm_host->pdata->status_gpio)) mmc_cd_gpio_free(msm_host->mmc); sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false); if (pdata->pin_data) sdhci_msm_setup_pins(pdata, false); if (msm_host->msm_bus_vote.client_handle) { sdhci_msm_bus_cancel_work_and_set_vote(host, 0); sdhci_msm_bus_unregister(msm_host); } return 0; } static int sdhci_msm_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; disable_irq(host->irq); disable_irq(msm_host->pwr_irq); /* * Remove the vote immediately only if clocks are off in which * case we might have queued work to remove vote but it may not * be completed before runtime suspend or system suspend. */ if (!atomic_read(&msm_host->clks_on)) { if (msm_host->msm_bus_vote.client_handle) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); } return 0; } static int sdhci_msm_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; enable_irq(msm_host->pwr_irq); enable_irq(host->irq); return 0; } #ifdef CONFIG_PM_SLEEP static int sdhci_msm_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; int ret = 0; if (gpio_is_valid(msm_host->pdata->status_gpio)) mmc_cd_gpio_free(msm_host->mmc); if (pm_runtime_suspended(dev)) { pr_debug("%s: %s: already runtime suspended\n", mmc_hostname(host->mmc), __func__); goto out; } return sdhci_msm_runtime_suspend(dev); out: return ret; } static int sdhci_msm_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; int ret = 0; if (gpio_is_valid(msm_host->pdata->status_gpio)) { ret = mmc_cd_gpio_request(msm_host->mmc, msm_host->pdata->status_gpio); if (ret) pr_err("%s: %s: Failed to request card detection IRQ %d\n", mmc_hostname(host->mmc), __func__, ret); } if (pm_runtime_suspended(dev)) { pr_debug("%s: %s: runtime suspended, defer system resume\n", mmc_hostname(host->mmc), __func__); goto out; } return sdhci_msm_runtime_resume(dev); out: return ret; } #endif #ifdef CONFIG_PM static const struct dev_pm_ops sdhci_msm_pmops = { SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume) SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume, NULL) }; #define SDHCI_MSM_PMOPS (&sdhci_msm_pmops) #else #define SDHCI_PM_OPS NULL #endif static const struct of_device_id sdhci_msm_dt_match[] = { {.compatible = "qcom,sdhci-msm"}, }; MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); static struct platform_driver sdhci_msm_driver = { .probe = sdhci_msm_probe, .remove = __devexit_p(sdhci_msm_remove), .driver = { .name = "sdhci_msm", .owner = THIS_MODULE, .of_match_table = sdhci_msm_dt_match, .pm = SDHCI_MSM_PMOPS, }, }; module_platform_driver(sdhci_msm_driver); MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver"); MODULE_LICENSE("GPL v2");