[go: nahoru, domu]

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