101ebea1bSChristian Daudt /* 201ebea1bSChristian Daudt * Copyright (C) 2013 Broadcom Corporation 301ebea1bSChristian Daudt * 401ebea1bSChristian Daudt * This program is free software; you can redistribute it and/or 501ebea1bSChristian Daudt * modify it under the terms of the GNU General Public License as 601ebea1bSChristian Daudt * published by the Free Software Foundation version 2. 701ebea1bSChristian Daudt * 801ebea1bSChristian Daudt * This program is distributed "as is" WITHOUT ANY WARRANTY of any 901ebea1bSChristian Daudt * kind, whether express or implied; without even the implied warranty 1001ebea1bSChristian Daudt * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1101ebea1bSChristian Daudt * GNU General Public License for more details. 1201ebea1bSChristian Daudt */ 1301ebea1bSChristian Daudt 1401ebea1bSChristian Daudt #include <linux/kernel.h> 1501ebea1bSChristian Daudt #include <linux/module.h> 1601ebea1bSChristian Daudt #include <linux/delay.h> 1701ebea1bSChristian Daudt #include <linux/highmem.h> 1801ebea1bSChristian Daudt #include <linux/platform_device.h> 1901ebea1bSChristian Daudt #include <linux/mmc/host.h> 2001ebea1bSChristian Daudt #include <linux/io.h> 2101ebea1bSChristian Daudt #include <linux/gpio.h> 2201ebea1bSChristian Daudt #include <linux/clk.h> 2301ebea1bSChristian Daudt #include <linux/regulator/consumer.h> 2401ebea1bSChristian Daudt #include <linux/of.h> 2501ebea1bSChristian Daudt #include <linux/of_device.h> 2601ebea1bSChristian Daudt #include <linux/of_gpio.h> 2701ebea1bSChristian Daudt #include <linux/mmc/slot-gpio.h> 2801ebea1bSChristian Daudt 2901ebea1bSChristian Daudt #include "sdhci-pltfm.h" 3001ebea1bSChristian Daudt #include "sdhci.h" 3101ebea1bSChristian Daudt 3201ebea1bSChristian Daudt #define SDHCI_SOFT_RESET 0x01000000 3301ebea1bSChristian Daudt #define KONA_SDHOST_CORECTRL 0x8000 3401ebea1bSChristian Daudt #define KONA_SDHOST_CD_PINCTRL 0x00000008 3501ebea1bSChristian Daudt #define KONA_SDHOST_STOP_HCLK 0x00000004 3601ebea1bSChristian Daudt #define KONA_SDHOST_RESET 0x00000002 3701ebea1bSChristian Daudt #define KONA_SDHOST_EN 0x00000001 3801ebea1bSChristian Daudt 3901ebea1bSChristian Daudt #define KONA_SDHOST_CORESTAT 0x8004 4001ebea1bSChristian Daudt #define KONA_SDHOST_WP 0x00000002 4101ebea1bSChristian Daudt #define KONA_SDHOST_CD_SW 0x00000001 4201ebea1bSChristian Daudt 4301ebea1bSChristian Daudt #define KONA_SDHOST_COREIMR 0x8008 4401ebea1bSChristian Daudt #define KONA_SDHOST_IP 0x00000001 4501ebea1bSChristian Daudt 4601ebea1bSChristian Daudt #define KONA_SDHOST_COREISR 0x800C 4701ebea1bSChristian Daudt #define KONA_SDHOST_COREIMSR 0x8010 4801ebea1bSChristian Daudt #define KONA_SDHOST_COREDBG1 0x8014 4901ebea1bSChristian Daudt #define KONA_SDHOST_COREGPO_MASK 0x8018 5001ebea1bSChristian Daudt 5101ebea1bSChristian Daudt #define SD_DETECT_GPIO_DEBOUNCE_128MS 128 5201ebea1bSChristian Daudt 5301ebea1bSChristian Daudt #define KONA_MMC_AUTOSUSPEND_DELAY (50) 5401ebea1bSChristian Daudt 5501ebea1bSChristian Daudt struct sdhci_bcm_kona_dev { 5601ebea1bSChristian Daudt struct mutex write_lock; /* protect back to back writes */ 5701ebea1bSChristian Daudt }; 5801ebea1bSChristian Daudt 5901ebea1bSChristian Daudt 6001ebea1bSChristian Daudt static int sdhci_bcm_kona_sd_reset(struct sdhci_host *host) 6101ebea1bSChristian Daudt { 6201ebea1bSChristian Daudt unsigned int val; 6301ebea1bSChristian Daudt unsigned long timeout; 6401ebea1bSChristian Daudt 6501ebea1bSChristian Daudt /* This timeout should be sufficent for core to reset */ 6601ebea1bSChristian Daudt timeout = jiffies + msecs_to_jiffies(100); 6701ebea1bSChristian Daudt 6801ebea1bSChristian Daudt /* reset the host using the top level reset */ 6901ebea1bSChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 7001ebea1bSChristian Daudt val |= KONA_SDHOST_RESET; 7101ebea1bSChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 7201ebea1bSChristian Daudt 7301ebea1bSChristian Daudt while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) { 7401ebea1bSChristian Daudt if (time_is_before_jiffies(timeout)) { 7501ebea1bSChristian Daudt pr_err("Error: sd host is stuck in reset!!!\n"); 7601ebea1bSChristian Daudt return -EFAULT; 7701ebea1bSChristian Daudt } 7801ebea1bSChristian Daudt } 7901ebea1bSChristian Daudt 8001ebea1bSChristian Daudt /* bring the host out of reset */ 8101ebea1bSChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 8201ebea1bSChristian Daudt val &= ~KONA_SDHOST_RESET; 8301ebea1bSChristian Daudt 8401ebea1bSChristian Daudt /* 8501ebea1bSChristian Daudt * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) 8601ebea1bSChristian Daudt * Back-to-Back writes to same register needs delay when SD bus clock 8701ebea1bSChristian Daudt * is very low w.r.t AHB clock, mainly during boot-time and during card 8801ebea1bSChristian Daudt * insert-removal. 8901ebea1bSChristian Daudt */ 9001ebea1bSChristian Daudt usleep_range(1000, 5000); 9101ebea1bSChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 9201ebea1bSChristian Daudt 9301ebea1bSChristian Daudt return 0; 9401ebea1bSChristian Daudt } 9501ebea1bSChristian Daudt 9601ebea1bSChristian Daudt static void sdhci_bcm_kona_sd_init(struct sdhci_host *host) 9701ebea1bSChristian Daudt { 9801ebea1bSChristian Daudt unsigned int val; 9901ebea1bSChristian Daudt 10001ebea1bSChristian Daudt /* enable the interrupt from the IP core */ 10101ebea1bSChristian Daudt val = sdhci_readl(host, KONA_SDHOST_COREIMR); 10201ebea1bSChristian Daudt val |= KONA_SDHOST_IP; 10301ebea1bSChristian Daudt sdhci_writel(host, val, KONA_SDHOST_COREIMR); 10401ebea1bSChristian Daudt 10501ebea1bSChristian Daudt /* Enable the AHB clock gating module to the host */ 10601ebea1bSChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 10701ebea1bSChristian Daudt val |= KONA_SDHOST_EN; 10801ebea1bSChristian Daudt 10901ebea1bSChristian Daudt /* 11001ebea1bSChristian Daudt * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) 11101ebea1bSChristian Daudt * Back-to-Back writes to same register needs delay when SD bus clock 11201ebea1bSChristian Daudt * is very low w.r.t AHB clock, mainly during boot-time and during card 11301ebea1bSChristian Daudt * insert-removal. 11401ebea1bSChristian Daudt */ 11501ebea1bSChristian Daudt usleep_range(1000, 5000); 11601ebea1bSChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 11701ebea1bSChristian Daudt } 11801ebea1bSChristian Daudt 11901ebea1bSChristian Daudt /* 12001ebea1bSChristian Daudt * Software emulation of the SD card insertion/removal. Set insert=1 for insert 12101ebea1bSChristian Daudt * and insert=0 for removal. The card detection is done by GPIO. For Broadcom 12201ebea1bSChristian Daudt * IP to function properly the bit 0 of CORESTAT register needs to be set/reset 12301ebea1bSChristian Daudt * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet. 12401ebea1bSChristian Daudt */ 12501ebea1bSChristian Daudt static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert) 12601ebea1bSChristian Daudt { 12701ebea1bSChristian Daudt struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); 12801ebea1bSChristian Daudt struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); 12901ebea1bSChristian Daudt u32 val; 13001ebea1bSChristian Daudt 13101ebea1bSChristian Daudt /* 13201ebea1bSChristian Daudt * Back-to-Back register write needs a delay of min 10uS. 13301ebea1bSChristian Daudt * Back-to-Back writes to same register needs delay when SD bus clock 13401ebea1bSChristian Daudt * is very low w.r.t AHB clock, mainly during boot-time and during card 13501ebea1bSChristian Daudt * insert-removal. 13601ebea1bSChristian Daudt * We keep 20uS 13701ebea1bSChristian Daudt */ 13801ebea1bSChristian Daudt mutex_lock(&kona_dev->write_lock); 13901ebea1bSChristian Daudt udelay(20); 14001ebea1bSChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORESTAT); 14101ebea1bSChristian Daudt 14201ebea1bSChristian Daudt if (insert) { 14301ebea1bSChristian Daudt int ret; 14401ebea1bSChristian Daudt 14501ebea1bSChristian Daudt ret = mmc_gpio_get_ro(host->mmc); 14601ebea1bSChristian Daudt if (ret >= 0) 14701ebea1bSChristian Daudt val = (val & ~KONA_SDHOST_WP) | 14801ebea1bSChristian Daudt ((ret) ? KONA_SDHOST_WP : 0); 14901ebea1bSChristian Daudt 15001ebea1bSChristian Daudt val |= KONA_SDHOST_CD_SW; 15101ebea1bSChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORESTAT); 15201ebea1bSChristian Daudt } else { 15301ebea1bSChristian Daudt val &= ~KONA_SDHOST_CD_SW; 15401ebea1bSChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORESTAT); 15501ebea1bSChristian Daudt } 15601ebea1bSChristian Daudt mutex_unlock(&kona_dev->write_lock); 15701ebea1bSChristian Daudt 15801ebea1bSChristian Daudt return 0; 15901ebea1bSChristian Daudt } 16001ebea1bSChristian Daudt 16101ebea1bSChristian Daudt /* 16201ebea1bSChristian Daudt * SD card interrupt event callback 16301ebea1bSChristian Daudt */ 164ceb2ea19SSachin Kamat static void sdhci_bcm_kona_card_event(struct sdhci_host *host) 16501ebea1bSChristian Daudt { 16601ebea1bSChristian Daudt if (mmc_gpio_get_cd(host->mmc) > 0) { 16701ebea1bSChristian Daudt dev_dbg(mmc_dev(host->mmc), 16801ebea1bSChristian Daudt "card inserted\n"); 16901ebea1bSChristian Daudt sdhci_bcm_kona_sd_card_emulate(host, 1); 17001ebea1bSChristian Daudt } else { 17101ebea1bSChristian Daudt dev_dbg(mmc_dev(host->mmc), 17201ebea1bSChristian Daudt "card removed\n"); 17301ebea1bSChristian Daudt sdhci_bcm_kona_sd_card_emulate(host, 0); 17401ebea1bSChristian Daudt } 17501ebea1bSChristian Daudt } 17601ebea1bSChristian Daudt 17701ebea1bSChristian Daudt static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, 17801ebea1bSChristian Daudt u8 power_mode) 17901ebea1bSChristian Daudt { 18001ebea1bSChristian Daudt /* 18101ebea1bSChristian Daudt * JEDEC and SD spec specify supplying 74 continuous clocks to 18201ebea1bSChristian Daudt * device after power up. With minimum bus (100KHz) that 18301ebea1bSChristian Daudt * that translates to 740us 18401ebea1bSChristian Daudt */ 18501ebea1bSChristian Daudt if (power_mode != MMC_POWER_OFF) 18601ebea1bSChristian Daudt udelay(740); 18701ebea1bSChristian Daudt } 18801ebea1bSChristian Daudt 18901ebea1bSChristian Daudt static struct sdhci_ops sdhci_bcm_kona_ops = { 1901771059cSRussell King .set_clock = sdhci_set_clock, 1912290fcb3SKevin Hao .get_max_clock = sdhci_pltfm_clk_get_max_clock, 1922290fcb3SKevin Hao .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 19301ebea1bSChristian Daudt .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, 1942317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 19503231f9bSRussell King .reset = sdhci_reset, 19696d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 19701ebea1bSChristian Daudt .card_event = sdhci_bcm_kona_card_event, 19801ebea1bSChristian Daudt }; 19901ebea1bSChristian Daudt 20001ebea1bSChristian Daudt static struct sdhci_pltfm_data sdhci_pltfm_data_kona = { 20101ebea1bSChristian Daudt .ops = &sdhci_bcm_kona_ops, 20201ebea1bSChristian Daudt .quirks = SDHCI_QUIRK_NO_CARD_NO_RESET | 20301ebea1bSChristian Daudt SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR | 20401ebea1bSChristian Daudt SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | 20501ebea1bSChristian Daudt SDHCI_QUIRK_FORCE_BLK_SZ_2048 | 20601ebea1bSChristian Daudt SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 20701ebea1bSChristian Daudt }; 20801ebea1bSChristian Daudt 209b3f635adSBehan Webster static const struct of_device_id sdhci_bcm_kona_of_match[] = { 210aea237bfSChristian Daudt { .compatible = "brcm,kona-sdhci"}, 211aea237bfSChristian Daudt { .compatible = "bcm,kona-sdhci"}, /* deprecated name */ 21201ebea1bSChristian Daudt {} 21301ebea1bSChristian Daudt }; 21401ebea1bSChristian Daudt MODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match); 21501ebea1bSChristian Daudt 216058feb53SMarkus Mayer static int sdhci_bcm_kona_probe(struct platform_device *pdev) 21701ebea1bSChristian Daudt { 21801ebea1bSChristian Daudt struct sdhci_bcm_kona_dev *kona_dev = NULL; 21901ebea1bSChristian Daudt struct sdhci_pltfm_host *pltfm_priv; 22001ebea1bSChristian Daudt struct device *dev = &pdev->dev; 22101ebea1bSChristian Daudt struct sdhci_host *host; 22201ebea1bSChristian Daudt int ret; 22301ebea1bSChristian Daudt 22401ebea1bSChristian Daudt ret = 0; 22501ebea1bSChristian Daudt 22601ebea1bSChristian Daudt host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona, 22701ebea1bSChristian Daudt sizeof(*kona_dev)); 22801ebea1bSChristian Daudt if (IS_ERR(host)) 22901ebea1bSChristian Daudt return PTR_ERR(host); 23001ebea1bSChristian Daudt 23101ebea1bSChristian Daudt dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr); 23201ebea1bSChristian Daudt 23301ebea1bSChristian Daudt pltfm_priv = sdhci_priv(host); 23401ebea1bSChristian Daudt 23501ebea1bSChristian Daudt kona_dev = sdhci_pltfm_priv(pltfm_priv); 23601ebea1bSChristian Daudt mutex_init(&kona_dev->write_lock); 23701ebea1bSChristian Daudt 238acfa77b1SUlf Hansson ret = mmc_of_parse(host->mmc); 239acfa77b1SUlf Hansson if (ret) 240acfa77b1SUlf Hansson goto err_pltfm_free; 24101ebea1bSChristian Daudt 24201ebea1bSChristian Daudt if (!host->mmc->f_max) { 24301ebea1bSChristian Daudt dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n"); 24401ebea1bSChristian Daudt ret = -ENXIO; 24501ebea1bSChristian Daudt goto err_pltfm_free; 24601ebea1bSChristian Daudt } 24701ebea1bSChristian Daudt 2482290fcb3SKevin Hao /* Get and enable the core clock */ 2492290fcb3SKevin Hao pltfm_priv->clk = devm_clk_get(dev, NULL); 2502290fcb3SKevin Hao if (IS_ERR(pltfm_priv->clk)) { 2512290fcb3SKevin Hao dev_err(dev, "Failed to get core clock\n"); 2522290fcb3SKevin Hao ret = PTR_ERR(pltfm_priv->clk); 253a6492c02STim Kryger goto err_pltfm_free; 254a6492c02STim Kryger } 255a6492c02STim Kryger 25666fe6ac5SWei Yongjun ret = clk_set_rate(pltfm_priv->clk, host->mmc->f_max); 25766fe6ac5SWei Yongjun if (ret) { 2582290fcb3SKevin Hao dev_err(dev, "Failed to set rate core clock\n"); 259a6492c02STim Kryger goto err_pltfm_free; 260a6492c02STim Kryger } 261a6492c02STim Kryger 26266fe6ac5SWei Yongjun ret = clk_prepare_enable(pltfm_priv->clk); 26366fe6ac5SWei Yongjun if (ret) { 2642290fcb3SKevin Hao dev_err(dev, "Failed to enable core clock\n"); 265a6492c02STim Kryger goto err_pltfm_free; 266a6492c02STim Kryger } 267a6492c02STim Kryger 26801ebea1bSChristian Daudt dev_dbg(dev, "non-removable=%c\n", 269860951c5SJaehoon Chung mmc_card_is_removable(host->mmc) ? 'N' : 'Y'); 27001ebea1bSChristian Daudt dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n", 27101ebea1bSChristian Daudt (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N', 27201ebea1bSChristian Daudt (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N'); 27301ebea1bSChristian Daudt 274860951c5SJaehoon Chung if (!mmc_card_is_removable(host->mmc)) 27501ebea1bSChristian Daudt host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; 27601ebea1bSChristian Daudt 27701ebea1bSChristian Daudt dev_dbg(dev, "is_8bit=%c\n", 27828804293SJavier Martinez Canillas (host->mmc->caps & MMC_CAP_8_BIT_DATA) ? 'Y' : 'N'); 27901ebea1bSChristian Daudt 28001ebea1bSChristian Daudt ret = sdhci_bcm_kona_sd_reset(host); 28101ebea1bSChristian Daudt if (ret) 282a6492c02STim Kryger goto err_clk_disable; 28301ebea1bSChristian Daudt 28401ebea1bSChristian Daudt sdhci_bcm_kona_sd_init(host); 28501ebea1bSChristian Daudt 28601ebea1bSChristian Daudt ret = sdhci_add_host(host); 28701ebea1bSChristian Daudt if (ret) { 28801ebea1bSChristian Daudt dev_err(dev, "Failed sdhci_add_host\n"); 28901ebea1bSChristian Daudt goto err_reset; 29001ebea1bSChristian Daudt } 29101ebea1bSChristian Daudt 29201ebea1bSChristian Daudt /* if device is eMMC, emulate card insert right here */ 293860951c5SJaehoon Chung if (!mmc_card_is_removable(host->mmc)) { 29401ebea1bSChristian Daudt ret = sdhci_bcm_kona_sd_card_emulate(host, 1); 29501ebea1bSChristian Daudt if (ret) { 29601ebea1bSChristian Daudt dev_err(dev, 29701ebea1bSChristian Daudt "unable to emulate card insertion\n"); 29801ebea1bSChristian Daudt goto err_remove_host; 29901ebea1bSChristian Daudt } 30001ebea1bSChristian Daudt } 30101ebea1bSChristian Daudt /* 30201ebea1bSChristian Daudt * Since the card detection GPIO interrupt is configured to be 30301ebea1bSChristian Daudt * edge sensitive, check the initial GPIO value here, emulate 30401ebea1bSChristian Daudt * only if the card is present 30501ebea1bSChristian Daudt */ 30601ebea1bSChristian Daudt if (mmc_gpio_get_cd(host->mmc) > 0) 30701ebea1bSChristian Daudt sdhci_bcm_kona_sd_card_emulate(host, 1); 30801ebea1bSChristian Daudt 30901ebea1bSChristian Daudt dev_dbg(dev, "initialized properly\n"); 31001ebea1bSChristian Daudt return 0; 31101ebea1bSChristian Daudt 31201ebea1bSChristian Daudt err_remove_host: 31301ebea1bSChristian Daudt sdhci_remove_host(host, 0); 31401ebea1bSChristian Daudt 31501ebea1bSChristian Daudt err_reset: 31601ebea1bSChristian Daudt sdhci_bcm_kona_sd_reset(host); 31701ebea1bSChristian Daudt 318a6492c02STim Kryger err_clk_disable: 3192290fcb3SKevin Hao clk_disable_unprepare(pltfm_priv->clk); 320a6492c02STim Kryger 32101ebea1bSChristian Daudt err_pltfm_free: 32201ebea1bSChristian Daudt sdhci_pltfm_free(pdev); 32301ebea1bSChristian Daudt 32401ebea1bSChristian Daudt dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret); 32501ebea1bSChristian Daudt return ret; 32601ebea1bSChristian Daudt } 32701ebea1bSChristian Daudt 32801ebea1bSChristian Daudt static struct platform_driver sdhci_bcm_kona_driver = { 32901ebea1bSChristian Daudt .driver = { 33001ebea1bSChristian Daudt .name = "sdhci-kona", 331fa243f64SUlf Hansson .pm = &sdhci_pltfm_pmops, 332058feb53SMarkus Mayer .of_match_table = sdhci_bcm_kona_of_match, 33301ebea1bSChristian Daudt }, 33401ebea1bSChristian Daudt .probe = sdhci_bcm_kona_probe, 335caebcae9SKevin Hao .remove = sdhci_pltfm_unregister, 33601ebea1bSChristian Daudt }; 33701ebea1bSChristian Daudt module_platform_driver(sdhci_bcm_kona_driver); 33801ebea1bSChristian Daudt 33901ebea1bSChristian Daudt MODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform"); 34001ebea1bSChristian Daudt MODULE_AUTHOR("Broadcom"); 34101ebea1bSChristian Daudt MODULE_LICENSE("GPL v2"); 342