1a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao/* 2a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Copyright (C) 2010 Marvell International Ltd. 3a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Zhangfei Gao <zhangfei.gao@marvell.com> 4a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Kevin Wang <dwang4@marvell.com> 5a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Mingwei Wang <mwwang@marvell.com> 6a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Philip Rakity <prakity@marvell.com> 7a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Mark Brown <markb@marvell.com> 8a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * 9a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * This software is licensed under the terms of the GNU General Public 10a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * License version 2, as published by the Free Software Foundation, and 11a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * may be copied, distributed, and modified under those terms. 12a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * 13a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * This program is distributed in the hope that it will be useful, 14a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * but WITHOUT ANY WARRANTY; without even the implied warranty of 15a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * GNU General Public License for more details. 17a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * 18a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao */ 19a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/err.h> 20a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/init.h> 21a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/platform_device.h> 22a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/clk.h> 23a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/io.h> 24a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/gpio.h> 25a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/mmc/card.h> 26a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/mmc/host.h> 278f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball#include <linux/mmc/slot-gpio.h> 28bfed345edfe05b291f7e5d396d4b447b6e8e66faZhangfei Gao#include <linux/platform_data/pxa_sdhci.h> 29a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/slab.h> 30a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include <linux/delay.h> 3188b47679746b81534002bcba42da97ab82b5d12aPaul Gortmaker#include <linux/module.h> 32b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#include <linux/of.h> 33b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#include <linux/of_device.h> 348f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball#include <linux/of_gpio.h> 35bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#include <linux/pm.h> 36bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#include <linux/pm_runtime.h> 375491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas#include <linux/mbus.h> 38b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 39a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include "sdhci.h" 40a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#include "sdhci-pltfm.h" 41a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 42bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#define PXAV3_RPM_DELAY_MS 50 43bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 44a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SD_CLOCK_BURST_SIZE_SETUP 0x10A 45a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCLK_SEL 0x100 46a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCLK_DELAY_SHIFT 9 47a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCLK_DELAY_MASK 0x1f 48a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 49a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SD_CFG_FIFO_PARAM 0x100 50a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCFG_GEN_PAD_CLK_ON (1<<6) 51a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCFG_GEN_PAD_CLK_CNT_MASK 0xFF 52a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCFG_GEN_PAD_CLK_CNT_SHIFT 24 53a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 54a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SD_SPI_MODE 0x108 55a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SD_CE_ATA_1 0x10C 56a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 57a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SD_CE_ATA_2 0x10E 58a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCE_MISC_INT (1<<2) 59a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define SDCE_MISC_INT_EN (1<<1) 60a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 615491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas/* 625491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas * These registers are relative to the second register region, for the 635491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas * MBus bridge. 645491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas */ 655491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas#define SDHCI_WINDOW_CTRL(i) (0x80 + ((i) << 3)) 665491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas#define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3)) 675491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas#define SDHCI_MAX_WIN_NUM 8 685491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 695491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtasstatic int mv_conf_mbus_windows(struct platform_device *pdev, 705491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas const struct mbus_dram_target_info *dram) 715491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas{ 725491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas int i; 735491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas void __iomem *regs; 745491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas struct resource *res; 755491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 765491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas if (!dram) { 775491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas dev_err(&pdev->dev, "no mbus dram info\n"); 785491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas return -EINVAL; 795491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas } 805491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 815491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 825491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas if (!res) { 835491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas dev_err(&pdev->dev, "cannot get mbus registers\n"); 845491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas return -EINVAL; 855491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas } 865491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 875491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas regs = ioremap(res->start, resource_size(res)); 885491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas if (!regs) { 895491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas dev_err(&pdev->dev, "cannot map mbus registers\n"); 905491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas return -ENOMEM; 915491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas } 925491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 935491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas for (i = 0; i < SDHCI_MAX_WIN_NUM; i++) { 945491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas writel(0, regs + SDHCI_WINDOW_CTRL(i)); 955491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas writel(0, regs + SDHCI_WINDOW_BASE(i)); 965491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas } 975491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 985491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas for (i = 0; i < dram->num_cs; i++) { 995491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas const struct mbus_dram_window *cs = dram->cs + i; 1005491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 1015491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas /* Write size, attributes and target id to control register */ 1025491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas writel(((cs->size - 1) & 0xffff0000) | 1035491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas (cs->mbus_attr << 8) | 1045491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas (dram->mbus_dram_target_id << 4) | 1, 1055491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas regs + SDHCI_WINDOW_CTRL(i)); 1065491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas /* Write base address to base register */ 1075491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas writel(cs->base, regs + SDHCI_WINDOW_BASE(i)); 1085491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas } 1095491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 1105491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas iounmap(regs); 1115491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 1125491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas return 0; 1135491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas} 1145491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 11503231f9b781f24205c0af0398ce3cbef70090939Russell Kingstatic void pxav3_reset(struct sdhci_host *host, u8 mask) 116a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao{ 117a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); 118a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; 119a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 12003231f9b781f24205c0af0398ce3cbef70090939Russell King sdhci_reset(host, mask); 12103231f9b781f24205c0af0398ce3cbef70090939Russell King 122a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (mask == SDHCI_RESET_ALL) { 123a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* 124a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * tune timing of read data/command when crc error happen 125a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * no performance impact 126a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao */ 127a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (pdata && 0 != pdata->clk_delay_cycles) { 128a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao u16 tmp; 129a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 130a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); 131a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK) 132a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao << SDCLK_DELAY_SHIFT; 133a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp |= SDCLK_SEL; 134a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); 135a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 136a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 137a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao} 138a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 139a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao#define MAX_WAIT_COUNT 5 140a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gaostatic void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) 141a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao{ 142a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 143a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pxa *pxa = pltfm_host->priv; 144a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao u16 tmp; 145a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao int count; 146a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 147a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (pxa->power_mode == MMC_POWER_UP 148a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao && power_mode == MMC_POWER_ON) { 149a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 150a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao dev_dbg(mmc_dev(host->mmc), 151a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao "%s: slot->power_mode = %d," 152a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao "ios->power_mode = %d\n", 153a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao __func__, 154a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao pxa->power_mode, 155a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao power_mode); 156a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 157a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* set we want notice of when 74 clocks are sent */ 158a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp = readw(host->ioaddr + SD_CE_ATA_2); 159a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp |= SDCE_MISC_INT_EN; 160a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao writew(tmp, host->ioaddr + SD_CE_ATA_2); 161a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 162a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* start sending the 74 clocks */ 163a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM); 164a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp |= SDCFG_GEN_PAD_CLK_ON; 165a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM); 166a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 167a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* slowest speed is about 100KHz or 10usec per clock */ 168a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao udelay(740); 169a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao count = 0; 170a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 171a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao while (count++ < MAX_WAIT_COUNT) { 172a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if ((readw(host->ioaddr + SD_CE_ATA_2) 173a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao & SDCE_MISC_INT) == 0) 174a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao break; 175a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao udelay(10); 176a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 177a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 178a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (count == MAX_WAIT_COUNT) 179a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao dev_warn(mmc_dev(host->mmc), "74 clock interrupt not cleared\n"); 180a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 181a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* clear the interrupt bit if posted */ 182a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp = readw(host->ioaddr + SD_CE_ATA_2); 183a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao tmp |= SDCE_MISC_INT; 184a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao writew(tmp, host->ioaddr + SD_CE_ATA_2); 185a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 186a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao pxa->power_mode = power_mode; 187a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao} 188a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 18913e645012dff774895906058163ae244f47b9b81Russell Kingstatic void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) 190a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao{ 191a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao u16 ctrl_2; 192a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 193a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* 194a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * Set V18_EN -- UHS modes do not work without this. 195a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao * does not change signaling voltage 196a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao */ 197a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 198a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 199a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* Select Bus Speed Mode for host */ 200a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 201a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao switch (uhs) { 202a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao case MMC_TIMING_UHS_SDR12: 203a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 |= SDHCI_CTRL_UHS_SDR12; 204a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao break; 205a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao case MMC_TIMING_UHS_SDR25: 206a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 207a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao break; 208a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao case MMC_TIMING_UHS_SDR50: 209a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; 210a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao break; 211a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao case MMC_TIMING_UHS_SDR104: 212a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; 213a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao break; 214a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao case MMC_TIMING_UHS_DDR50: 215a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; 216a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao break; 217a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 218a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 219a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 220a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao dev_dbg(mmc_dev(host->mmc), 221a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao "%s uhs = %d, ctrl_2 = %04X\n", 222a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao __func__, uhs, ctrl_2); 223a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao} 224a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 225c915568d99f12898aea4e15845cf891a8b5cc575Lars-Peter Clausenstatic const struct sdhci_ops pxav3_sdhci_ops = { 2261771059cf5f9c09e37ef6315df8acf120f2642fcRussell King .set_clock = sdhci_set_clock, 227a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, 228d005d94359a8df84ea6e5ac137393707f9e87e81Lars-Peter Clausen .get_max_clock = sdhci_pltfm_clk_get_max_clock, 2292317f56c055fcad524bf6a873df48a754e7ebc4dRussell King .set_bus_width = sdhci_set_bus_width, 23003231f9b781f24205c0af0398ce3cbef70090939Russell King .reset = pxav3_reset, 231b315376573778b195e640a163675fb9f5937ddcaPeter Griffin .set_uhs_signaling = pxav3_set_uhs_signaling, 232a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao}; 233a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 23473b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liustatic struct sdhci_pltfm_data sdhci_pxav3_pdata = { 235e065162ae476f55376ba06f9e80f41b28f769938Kevin Liu .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK 23673b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liu | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC 23773b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liu | SDHCI_QUIRK_32BIT_ADMA_SIZE 23873b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liu | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 23973b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liu .ops = &pxav3_sdhci_ops, 24073b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liu}; 24173b7afb9764b77fca99d515b8d9cbeeaae5fe55cKevin Liu 242b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#ifdef CONFIG_OF 243b650352dd3df36164e3427bff3f33bc06ac47642Chris Ballstatic const struct of_device_id sdhci_pxav3_of_match[] = { 244b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball { 245b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball .compatible = "mrvl,pxav3-mmc", 246b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball }, 2475491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas { 2485491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas .compatible = "marvell,armada-380-sdhci", 2495491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas }, 250b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball {}, 251b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball}; 252b650352dd3df36164e3427bff3f33bc06ac47642Chris BallMODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match); 253b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 254b650352dd3df36164e3427bff3f33bc06ac47642Chris Ballstatic struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) 255b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball{ 256b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball struct sdhci_pxa_platdata *pdata; 257b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball struct device_node *np = dev->of_node; 258b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball u32 clk_delay_cycles; 259b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 260b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 261b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball if (!pdata) 262b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball return NULL; 263b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 264b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); 265b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball if (clk_delay_cycles > 0) 266b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball pdata->clk_delay_cycles = clk_delay_cycles; 267b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 268b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball return pdata; 269b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball} 270b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#else 271b650352dd3df36164e3427bff3f33bc06ac47642Chris Ballstatic inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) 272b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball{ 273b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball return NULL; 274b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball} 275b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#endif 276b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 277c3be1efd41a97f93be390240387d356a07b664c7Bill Pembertonstatic int sdhci_pxav3_probe(struct platform_device *pdev) 278a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao{ 279a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pltfm_host *pltfm_host; 280a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; 281a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct device *dev = &pdev->dev; 2825491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas struct device_node *np = pdev->dev.of_node; 283a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_host *host = NULL; 284a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pxa *pxa = NULL; 285b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball const struct of_device_id *match; 286b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball 287a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao int ret; 288a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct clk *clk; 289a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 2903df5b28149df5c04f0fbb4efe15ef870ce93de93Laurent Pinchart pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL); 291a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (!pxa) 292a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao return -ENOMEM; 293a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 2940e748234293f5f2caa8dbd152caba5efb754c707Christian Daudt host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, 0); 2953df5b28149df5c04f0fbb4efe15ef870ce93de93Laurent Pinchart if (IS_ERR(host)) 296a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao return PTR_ERR(host); 2975491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 2985491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) { 2995491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info()); 3005491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas if (ret < 0) 3015491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas goto err_mbus_win; 3025491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas } 3035491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 3045491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtas 305a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao pltfm_host = sdhci_priv(host); 306a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao pltfm_host->priv = pxa; 307a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 3083df5b28149df5c04f0fbb4efe15ef870ce93de93Laurent Pinchart clk = devm_clk_get(dev, NULL); 309a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (IS_ERR(clk)) { 310a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao dev_err(dev, "failed to get io clock\n"); 311a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ret = PTR_ERR(clk); 312a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao goto err_clk_get; 313a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 314a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao pltfm_host->clk = clk; 315164378efe7612ae1506d1a3b21fd37abf9909a5cChao Xie clk_prepare_enable(clk); 316a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 317a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* enable 1/8V DDR capable */ 318a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao host->mmc->caps |= MMC_CAP_1_8V_DDR; 319a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 320b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); 321943647f6fe3aa7217d13cacac830c88455a88326Kevin Liu if (match) { 322d2cf6071cc09337eb68d960bcba94d2998de6172Simon Baatz ret = mmc_of_parse(host->mmc); 323d2cf6071cc09337eb68d960bcba94d2998de6172Simon Baatz if (ret) 324d2cf6071cc09337eb68d960bcba94d2998de6172Simon Baatz goto err_of_parse; 325943647f6fe3aa7217d13cacac830c88455a88326Kevin Liu sdhci_get_of_property(pdev); 326b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball pdata = pxav3_get_mmc_pdata(dev); 327943647f6fe3aa7217d13cacac830c88455a88326Kevin Liu } else if (pdata) { 328c844a46f135e493ffda0bd770e16f6c3dd6c7eb7Kevin Liu /* on-chip device */ 329c844a46f135e493ffda0bd770e16f6c3dd6c7eb7Kevin Liu if (pdata->flags & PXA_FLAG_CARD_PERMANENT) 330a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao host->mmc->caps |= MMC_CAP_NONREMOVABLE; 331a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 332a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao /* If slot design supports 8 bit data, indicate this to MMC. */ 333a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) 334a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao host->mmc->caps |= MMC_CAP_8_BIT_DATA; 335a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 336a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (pdata->quirks) 337a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao host->quirks |= pdata->quirks; 3387c52d7bb87955095f23f96c717e787af4eea4195Kevin Liu if (pdata->quirks2) 3397c52d7bb87955095f23f96c717e787af4eea4195Kevin Liu host->quirks2 |= pdata->quirks2; 340a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (pdata->host_caps) 341a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao host->mmc->caps |= pdata->host_caps; 3428f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball if (pdata->host_caps2) 3438f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball host->mmc->caps2 |= pdata->host_caps2; 344a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (pdata->pm_caps) 345a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao host->mmc->pm_caps |= pdata->pm_caps; 3468f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball 3478f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball if (gpio_is_valid(pdata->ext_cd_gpio)) { 348214fc309d1387e822d606a33a10e31cacfe83520Laurent Pinchart ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio, 349214fc309d1387e822d606a33a10e31cacfe83520Laurent Pinchart 0); 3508f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball if (ret) { 3518f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball dev_err(mmc_dev(host->mmc), 3528f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball "failed to allocate card detect gpio\n"); 3538f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball goto err_cd_req; 3548f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball } 3558f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball } 356a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 357a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 358bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_enable(&pdev->dev); 3590dcaa2499b7d111bd70da5b0976c34210c850fb3Daniel Drake pm_runtime_get_sync(&pdev->dev); 360bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); 361bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_use_autosuspend(&pdev->dev); 362bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_suspend_ignore_children(&pdev->dev, 1); 363bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 364a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao ret = sdhci_add_host(host); 365a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao if (ret) { 366a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao dev_err(&pdev->dev, "failed to add host\n"); 367a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao goto err_add_host; 368a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao } 369a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 370a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao platform_set_drvdata(pdev, host); 371a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 372943647f6fe3aa7217d13cacac830c88455a88326Kevin Liu if (host->mmc->pm_caps & MMC_PM_KEEP_POWER) { 373740b7a44aedbe8d916ce21b636f78467f5da1c59Kevin Liu device_init_wakeup(&pdev->dev, 1); 374740b7a44aedbe8d916ce21b636f78467f5da1c59Kevin Liu host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ; 375740b7a44aedbe8d916ce21b636f78467f5da1c59Kevin Liu } else { 376740b7a44aedbe8d916ce21b636f78467f5da1c59Kevin Liu device_init_wakeup(&pdev->dev, 0); 377740b7a44aedbe8d916ce21b636f78467f5da1c59Kevin Liu } 378740b7a44aedbe8d916ce21b636f78467f5da1c59Kevin Liu 379bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_put_autosuspend(&pdev->dev); 380bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 381a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao return 0; 382a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 383a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gaoerr_add_host: 3840dcaa2499b7d111bd70da5b0976c34210c850fb3Daniel Drake pm_runtime_put_sync(&pdev->dev); 3850dcaa2499b7d111bd70da5b0976c34210c850fb3Daniel Drake pm_runtime_disable(&pdev->dev); 38687d2163dae1f2388c7ccda5269be8d58e24382ddXiang Wangerr_of_parse: 38787d2163dae1f2388c7ccda5269be8d58e24382ddXiang Wangerr_cd_req: 388164378efe7612ae1506d1a3b21fd37abf9909a5cChao Xie clk_disable_unprepare(clk); 389a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gaoerr_clk_get: 3905491ce3f79eed79f68fcc2dc4c10aeafe00215a6Marcin Wojtaserr_mbus_win: 391a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao sdhci_pltfm_free(pdev); 392a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao return ret; 393a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao} 394a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 3956e0ee714fdab0568c3487455951dea2673e9557fBill Pembertonstatic int sdhci_pxav3_remove(struct platform_device *pdev) 396a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao{ 397a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_host *host = platform_get_drvdata(pdev); 398a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 399a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 400bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_get_sync(&pdev->dev); 401a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao sdhci_remove_host(host, 1); 402bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_disable(&pdev->dev); 403a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 404164378efe7612ae1506d1a3b21fd37abf9909a5cChao Xie clk_disable_unprepare(pltfm_host->clk); 4058f63795c60ef5bc3dbfcbf19c1ac64ed79d23c62Chris Ball 406a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao sdhci_pltfm_free(pdev); 407a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 408a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao return 0; 409a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao} 410a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 411bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#ifdef CONFIG_PM_SLEEP 412bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liustatic int sdhci_pxav3_suspend(struct device *dev) 413bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu{ 414bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu int ret; 415bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu struct sdhci_host *host = dev_get_drvdata(dev); 416bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 417bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_get_sync(dev); 418bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu ret = sdhci_suspend_host(host); 419bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_mark_last_busy(dev); 420bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_put_autosuspend(dev); 421bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 422bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu return ret; 423bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu} 424bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 425bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liustatic int sdhci_pxav3_resume(struct device *dev) 426bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu{ 427bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu int ret; 428bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu struct sdhci_host *host = dev_get_drvdata(dev); 429bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 430bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_get_sync(dev); 431bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu ret = sdhci_resume_host(host); 432bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_mark_last_busy(dev); 433bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu pm_runtime_put_autosuspend(dev); 434bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 435bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu return ret; 436bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu} 437bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#endif 438bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 439bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#ifdef CONFIG_PM_RUNTIME 440bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liustatic int sdhci_pxav3_runtime_suspend(struct device *dev) 441bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu{ 442bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu struct sdhci_host *host = dev_get_drvdata(dev); 443bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 444bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu unsigned long flags; 445bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 446bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu if (pltfm_host->clk) { 447bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu spin_lock_irqsave(&host->lock, flags); 448bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu host->runtime_suspended = true; 449bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu spin_unlock_irqrestore(&host->lock, flags); 450bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 451bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu clk_disable_unprepare(pltfm_host->clk); 452bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu } 453bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 454bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu return 0; 455bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu} 456bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 457bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liustatic int sdhci_pxav3_runtime_resume(struct device *dev) 458bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu{ 459bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu struct sdhci_host *host = dev_get_drvdata(dev); 460bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 461bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu unsigned long flags; 462bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 463bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu if (pltfm_host->clk) { 464bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu clk_prepare_enable(pltfm_host->clk); 465bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 466bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu spin_lock_irqsave(&host->lock, flags); 467bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu host->runtime_suspended = false; 468bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu spin_unlock_irqrestore(&host->lock, flags); 469bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu } 470bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 471bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu return 0; 472bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu} 473bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#endif 474bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 475bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#ifdef CONFIG_PM 476bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liustatic const struct dev_pm_ops sdhci_pxav3_pmops = { 477bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume) 478bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend, 479bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu sdhci_pxav3_runtime_resume, NULL) 480bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu}; 481bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 482bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#define SDHCI_PXAV3_PMOPS (&sdhci_pxav3_pmops) 483bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 484bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#else 485bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#define SDHCI_PXAV3_PMOPS NULL 486bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu#endif 487bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu 488a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gaostatic struct platform_driver sdhci_pxav3_driver = { 489a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao .driver = { 490a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao .name = "sdhci-pxav3", 491b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#ifdef CONFIG_OF 492b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball .of_match_table = sdhci_pxav3_of_match, 493b650352dd3df36164e3427bff3f33bc06ac47642Chris Ball#endif 494bb691ae464b77d30e74c66480e98d74e88d6b194Kevin Liu .pm = SDHCI_PXAV3_PMOPS, 495a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao }, 496a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao .probe = sdhci_pxav3_probe, 4970433c14356702e296f474f77ebd42f0a9d9a5487Bill Pemberton .remove = sdhci_pxav3_remove, 498a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao}; 499a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 500d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(sdhci_pxav3_driver); 501a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 502a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei GaoMODULE_DESCRIPTION("SDHCI driver for pxav3"); 503a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei GaoMODULE_AUTHOR("Marvell International Ltd."); 504a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei GaoMODULE_LICENSE("GPL v2"); 505a702c8abb2a95a5b5920373a727be0b94d96b33cZhangfei Gao 506