101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt/* 201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Copyright (C) 2013 Broadcom Corporation 301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * 401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * This program is free software; you can redistribute it and/or 501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * modify it under the terms of the GNU General Public License as 601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * published by the Free Software Foundation version 2. 701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * 801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * This program is distributed "as is" WITHOUT ANY WARRANTY of any 901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * kind, whether express or implied; without even the implied warranty 1001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * GNU General Public License for more details. 1201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 1301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 1401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/kernel.h> 1501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/module.h> 1601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/delay.h> 1701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/highmem.h> 1801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/platform_device.h> 1901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/mmc/host.h> 2001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/io.h> 2101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/gpio.h> 2201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/clk.h> 2301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/regulator/consumer.h> 2401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/of.h> 2501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/of_device.h> 2601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/of_gpio.h> 2701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include <linux/mmc/slot-gpio.h> 2801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 2901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include "sdhci-pltfm.h" 3001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#include "sdhci.h" 3101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 3201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define SDHCI_SOFT_RESET 0x01000000 3301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_CORECTRL 0x8000 3401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_CD_PINCTRL 0x00000008 3501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_STOP_HCLK 0x00000004 3601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_RESET 0x00000002 3701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_EN 0x00000001 3801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 3901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_CORESTAT 0x8004 4001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_WP 0x00000002 4101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_CD_SW 0x00000001 4201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 4301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_COREIMR 0x8008 4401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_IP 0x00000001 4501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 4601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_COREISR 0x800C 4701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_COREIMSR 0x8010 4801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_COREDBG1 0x8014 4901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_SDHOST_COREGPO_MASK 0x8018 5001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 5101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define SD_DETECT_GPIO_DEBOUNCE_128MS 128 5201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 5301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt#define KONA_MMC_AUTOSUSPEND_DELAY (50) 5401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 5501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstruct sdhci_bcm_kona_dev { 5601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct mutex write_lock; /* protect back to back writes */ 57a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger struct clk *external_clk; 5801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt}; 5901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 6001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 6101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic int sdhci_bcm_kona_sd_reset(struct sdhci_host *host) 6201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 6301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt unsigned int val; 6401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt unsigned long timeout; 6501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 6601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* This timeout should be sufficent for core to reset */ 6701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt timeout = jiffies + msecs_to_jiffies(100); 6801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 6901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* reset the host using the top level reset */ 7001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 7101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val |= KONA_SDHOST_RESET; 7201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 7301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 7401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) { 7501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (time_is_before_jiffies(timeout)) { 7601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt pr_err("Error: sd host is stuck in reset!!!\n"); 7701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return -EFAULT; 7801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 7901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 8001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 8101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* bring the host out of reset */ 8201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 8301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val &= ~KONA_SDHOST_RESET; 8401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 8501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* 8601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) 8701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Back-to-Back writes to same register needs delay when SD bus clock 8801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * is very low w.r.t AHB clock, mainly during boot-time and during card 8901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * insert-removal. 9001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 9101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt usleep_range(1000, 5000); 9201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 9301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 9401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return 0; 9501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 9601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 9701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic void sdhci_bcm_kona_sd_init(struct sdhci_host *host) 9801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 9901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt unsigned int val; 10001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 10101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* enable the interrupt from the IP core */ 10201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val = sdhci_readl(host, KONA_SDHOST_COREIMR); 10301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val |= KONA_SDHOST_IP; 10401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_writel(host, val, KONA_SDHOST_COREIMR); 10501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 10601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* Enable the AHB clock gating module to the host */ 10701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 10801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val |= KONA_SDHOST_EN; 10901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 11001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* 11101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) 11201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Back-to-Back writes to same register needs delay when SD bus clock 11301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * is very low w.r.t AHB clock, mainly during boot-time and during card 11401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * insert-removal. 11501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 11601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt usleep_range(1000, 5000); 11701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 11801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 11901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 12001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt/* 12101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Software emulation of the SD card insertion/removal. Set insert=1 for insert 12201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * and insert=0 for removal. The card detection is done by GPIO. For Broadcom 12301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * IP to function properly the bit 0 of CORESTAT register needs to be set/reset 12401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet. 12501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 12601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert) 12701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 12801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); 12901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); 13001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt u32 val; 13101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 13201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* 13301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Back-to-Back register write needs a delay of min 10uS. 13401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Back-to-Back writes to same register needs delay when SD bus clock 13501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * is very low w.r.t AHB clock, mainly during boot-time and during card 13601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * insert-removal. 13701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * We keep 20uS 13801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 13901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt mutex_lock(&kona_dev->write_lock); 14001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt udelay(20); 14101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val = sdhci_readl(host, KONA_SDHOST_CORESTAT); 14201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 14301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (insert) { 14401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt int ret; 14501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 14601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ret = mmc_gpio_get_ro(host->mmc); 14701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (ret >= 0) 14801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val = (val & ~KONA_SDHOST_WP) | 14901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ((ret) ? KONA_SDHOST_WP : 0); 15001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 15101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val |= KONA_SDHOST_CD_SW; 15201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORESTAT); 15301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } else { 15401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt val &= ~KONA_SDHOST_CD_SW; 15501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_writel(host, val, KONA_SDHOST_CORESTAT); 15601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 15701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt mutex_unlock(&kona_dev->write_lock); 15801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 15901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return 0; 16001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 16101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 16201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt/* 16301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * SD card interrupt event callback 16401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 165ceb2ea195a4167bc1ee9d78b19220562b1524fbaSachin Kamatstatic void sdhci_bcm_kona_card_event(struct sdhci_host *host) 16601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 16701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (mmc_gpio_get_cd(host->mmc) > 0) { 16801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(mmc_dev(host->mmc), 16901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt "card inserted\n"); 17001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_bcm_kona_sd_card_emulate(host, 1); 17101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } else { 17201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(mmc_dev(host->mmc), 17301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt "card removed\n"); 17401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_bcm_kona_sd_card_emulate(host, 0); 17501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 17601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 17701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 17801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt/* 17901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Get the base clock. Use central clock source for now. Not sure if different 18001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * clock speed to each dev is allowed 18101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 18201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host) 18301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 18401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_bcm_kona_dev *kona_dev; 18501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); 18601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt kona_dev = sdhci_pltfm_priv(pltfm_priv); 18701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 18801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return host->mmc->f_max; 18901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 19001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 19101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic unsigned int sdhci_bcm_kona_get_timeout_clock(struct sdhci_host *host) 19201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 19301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return sdhci_bcm_kona_get_max_clk(host); 19401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 19501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 19601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, 19701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt u8 power_mode) 19801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 19901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* 20001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * JEDEC and SD spec specify supplying 74 continuous clocks to 20101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * device after power up. With minimum bus (100KHz) that 20201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * that translates to 740us 20301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 20401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (power_mode != MMC_POWER_OFF) 20501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt udelay(740); 20601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 20701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 20801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic struct sdhci_ops sdhci_bcm_kona_ops = { 2091771059cf5f9c09e37ef6315df8acf120f2642fcRussell King .set_clock = sdhci_set_clock, 21001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .get_max_clock = sdhci_bcm_kona_get_max_clk, 21101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, 21201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, 2132317f56c055fcad524bf6a873df48a754e7ebc4dRussell King .set_bus_width = sdhci_set_bus_width, 21403231f9b781f24205c0af0398ce3cbef70090939Russell King .reset = sdhci_reset, 21596d7b78cfc2fd6b1539704e2d33239dbaa097cc4Russell King .set_uhs_signaling = sdhci_set_uhs_signaling, 21601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .card_event = sdhci_bcm_kona_card_event, 21701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt}; 21801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 21901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic struct sdhci_pltfm_data sdhci_pltfm_data_kona = { 22001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .ops = &sdhci_bcm_kona_ops, 22101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .quirks = SDHCI_QUIRK_NO_CARD_NO_RESET | 22201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR | 22301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | 22401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt SDHCI_QUIRK_FORCE_BLK_SZ_2048 | 22501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 22601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt}; 22701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 228b3f635ad6648d17178c3e2ab2f0a4823fcac1e83Behan Websterstatic const struct of_device_id sdhci_bcm_kona_of_match[] = { 229aea237bfa0a8ce8fe364e3fa7de6850777044a60Christian Daudt { .compatible = "brcm,kona-sdhci"}, 230aea237bfa0a8ce8fe364e3fa7de6850777044a60Christian Daudt { .compatible = "bcm,kona-sdhci"}, /* deprecated name */ 23101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt {} 23201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt}; 23301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian DaudtMODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match); 23401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 235058feb53666f8ca1f4b838227a9efae13801b861Markus Mayerstatic int sdhci_bcm_kona_probe(struct platform_device *pdev) 23601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 23701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_bcm_kona_dev *kona_dev = NULL; 23801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_pltfm_host *pltfm_priv; 23901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct device *dev = &pdev->dev; 24001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt struct sdhci_host *host; 24101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt int ret; 24201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 24301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ret = 0; 24401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 24501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona, 24601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sizeof(*kona_dev)); 24701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (IS_ERR(host)) 24801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return PTR_ERR(host); 24901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 25001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr); 25101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 25201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt pltfm_priv = sdhci_priv(host); 25301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 25401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt kona_dev = sdhci_pltfm_priv(pltfm_priv); 25501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt mutex_init(&kona_dev->write_lock); 25601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 25701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt mmc_of_parse(host->mmc); 25801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 25901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (!host->mmc->f_max) { 26001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n"); 26101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ret = -ENXIO; 26201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt goto err_pltfm_free; 26301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 26401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 265a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger /* Get and enable the external clock */ 266a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger kona_dev->external_clk = devm_clk_get(dev, NULL); 267a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger if (IS_ERR(kona_dev->external_clk)) { 268a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger dev_err(dev, "Failed to get external clock\n"); 269a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger ret = PTR_ERR(kona_dev->external_clk); 270a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger goto err_pltfm_free; 271a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger } 272a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 273a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) { 274a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger dev_err(dev, "Failed to set rate external clock\n"); 275a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger goto err_pltfm_free; 276a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger } 277a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 278a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger if (clk_prepare_enable(kona_dev->external_clk) != 0) { 279a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger dev_err(dev, "Failed to enable external clock\n"); 280a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger goto err_pltfm_free; 281a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger } 282a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 28301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(dev, "non-removable=%c\n", 28401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N'); 28501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n", 28601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N', 28701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N'); 28801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 289cf68b629f938c01c9aa84fff95e1be96032af08dChristian Daudt if (host->mmc->caps & MMC_CAP_NONREMOVABLE) 29001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; 29101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 29201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(dev, "is_8bit=%c\n", 29301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt (host->mmc->caps | MMC_CAP_8_BIT_DATA) ? 'Y' : 'N'); 29401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 29501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ret = sdhci_bcm_kona_sd_reset(host); 29601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (ret) 297a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger goto err_clk_disable; 29801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 29901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_bcm_kona_sd_init(host); 30001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 30101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ret = sdhci_add_host(host); 30201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (ret) { 30301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_err(dev, "Failed sdhci_add_host\n"); 30401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt goto err_reset; 30501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 30601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 30701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* if device is eMMC, emulate card insert right here */ 308cf68b629f938c01c9aa84fff95e1be96032af08dChristian Daudt if (host->mmc->caps & MMC_CAP_NONREMOVABLE) { 30901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt ret = sdhci_bcm_kona_sd_card_emulate(host, 1); 31001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (ret) { 31101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_err(dev, 31201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt "unable to emulate card insertion\n"); 31301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt goto err_remove_host; 31401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 31501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt } 31601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt /* 31701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * Since the card detection GPIO interrupt is configured to be 31801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * edge sensitive, check the initial GPIO value here, emulate 31901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt * only if the card is present 32001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt */ 32101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt if (mmc_gpio_get_cd(host->mmc) > 0) 32201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_bcm_kona_sd_card_emulate(host, 1); 32301ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 32401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_dbg(dev, "initialized properly\n"); 32501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return 0; 32601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 32701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudterr_remove_host: 32801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_remove_host(host, 0); 32901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 33001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudterr_reset: 33101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_bcm_kona_sd_reset(host); 33201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 333a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Krygererr_clk_disable: 334a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger clk_disable_unprepare(kona_dev->external_clk); 335a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 33601ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudterr_pltfm_free: 33701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt sdhci_pltfm_free(pdev); 33801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 33901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret); 34001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt return ret; 34101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 34201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 3434025ce24f326830135341814307c072f6c2a7738Russell Kingstatic int sdhci_bcm_kona_remove(struct platform_device *pdev) 34401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt{ 345a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger struct sdhci_host *host = platform_get_drvdata(pdev); 346a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); 347a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); 348a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 349a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 350a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger sdhci_remove_host(host, dead); 351a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 352a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger clk_disable_unprepare(kona_dev->external_clk); 353a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 354a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger sdhci_pltfm_free(pdev); 355a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger 356a6492c02073cd966ae490c1afcdebdd0d5ba3d81Tim Kryger return 0; 35701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt} 35801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 35901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtstatic struct platform_driver sdhci_bcm_kona_driver = { 36001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .driver = { 36101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .name = "sdhci-kona", 36201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .pm = SDHCI_PLTFM_PMOPS, 363058feb53666f8ca1f4b838227a9efae13801b861Markus Mayer .of_match_table = sdhci_bcm_kona_of_match, 36401ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt }, 36501ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt .probe = sdhci_bcm_kona_probe, 366058feb53666f8ca1f4b838227a9efae13801b861Markus Mayer .remove = sdhci_bcm_kona_remove, 36701ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt}; 36801ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudtmodule_platform_driver(sdhci_bcm_kona_driver); 36901ebea1b411aafc8eab440bf1d2037f01bbed99bChristian Daudt 37001ebea1b411aafc8eab440bf1d2037f01bbed99bChristian DaudtMODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform"); 37101ebea1b411aafc8eab440bf1d2037f01bbed99bChristian DaudtMODULE_AUTHOR("Broadcom"); 37201ebea1b411aafc8eab440bf1d2037f01bbed99bChristian DaudtMODULE_LICENSE("GPL v2"); 373