brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · e067c7f Raw
338 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// Copyright (C) 2013 Broadcom Corporation3 4#include <linux/kernel.h>5#include <linux/module.h>6#include <linux/delay.h>7#include <linux/highmem.h>8#include <linux/platform_device.h>9#include <linux/mmc/host.h>10#include <linux/io.h>11#include <linux/clk.h>12#include <linux/regulator/consumer.h>13#include <linux/of.h>14#include <linux/mmc/slot-gpio.h>15 16#include "sdhci-pltfm.h"17#include "sdhci.h"18 19#define SDHCI_SOFT_RESET			0x0100000020#define KONA_SDHOST_CORECTRL			0x800021#define KONA_SDHOST_CD_PINCTRL			0x0000000822#define KONA_SDHOST_STOP_HCLK			0x0000000423#define KONA_SDHOST_RESET			0x0000000224#define KONA_SDHOST_EN				0x0000000125 26#define KONA_SDHOST_CORESTAT			0x800427#define KONA_SDHOST_WP				0x0000000228#define KONA_SDHOST_CD_SW			0x0000000129 30#define KONA_SDHOST_COREIMR			0x800831#define KONA_SDHOST_IP				0x0000000132 33#define KONA_SDHOST_COREISR			0x800C34#define KONA_SDHOST_COREIMSR			0x801035#define KONA_SDHOST_COREDBG1			0x801436#define KONA_SDHOST_COREGPO_MASK		0x801837 38#define SD_DETECT_GPIO_DEBOUNCE_128MS		12839 40#define KONA_MMC_AUTOSUSPEND_DELAY		(50)41 42struct sdhci_bcm_kona_dev {43	struct mutex	write_lock; /* protect back to back writes */44};45 46 47static int sdhci_bcm_kona_sd_reset(struct sdhci_host *host)48{49	unsigned int val;50	unsigned long timeout;51 52	/* This timeout should be sufficent for core to reset */53	timeout = jiffies + msecs_to_jiffies(100);54 55	/* reset the host using the top level reset */56	val = sdhci_readl(host, KONA_SDHOST_CORECTRL);57	val |= KONA_SDHOST_RESET;58	sdhci_writel(host, val, KONA_SDHOST_CORECTRL);59 60	while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) {61		if (time_is_before_jiffies(timeout)) {62			pr_err("Error: sd host is stuck in reset!!!\n");63			return -EFAULT;64		}65	}66 67	/* bring the host out of reset */68	val = sdhci_readl(host, KONA_SDHOST_CORECTRL);69	val &= ~KONA_SDHOST_RESET;70 71	/*72	 * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS)73	 * Back-to-Back writes to same register needs delay when SD bus clock74	 * is very low w.r.t AHB clock, mainly during boot-time and during card75	 * insert-removal.76	 */77	usleep_range(1000, 5000);78	sdhci_writel(host, val, KONA_SDHOST_CORECTRL);79 80	return 0;81}82 83static void sdhci_bcm_kona_sd_init(struct sdhci_host *host)84{85	unsigned int val;86 87	/* enable the interrupt from the IP core */88	val = sdhci_readl(host, KONA_SDHOST_COREIMR);89	val |= KONA_SDHOST_IP;90	sdhci_writel(host, val, KONA_SDHOST_COREIMR);91 92	/* Enable the AHB clock gating module to the host */93	val = sdhci_readl(host, KONA_SDHOST_CORECTRL);94	val |= KONA_SDHOST_EN;95 96	/*97	 * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS)98	 * Back-to-Back writes to same register needs delay when SD bus clock99	 * is very low w.r.t AHB clock, mainly during boot-time and during card100	 * insert-removal.101	 */102	usleep_range(1000, 5000);103	sdhci_writel(host, val, KONA_SDHOST_CORECTRL);104}105 106/*107 * Software emulation of the SD card insertion/removal. Set insert=1 for insert108 * and insert=0 for removal. The card detection is done by GPIO. For Broadcom109 * IP to function properly the bit 0 of CORESTAT register needs to be set/reset110* to generate the CD IRQ handled in sdhci.c111 */112static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert)113{114	struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);115	struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv);116	u32 val;117 118	/*119	 * Back-to-Back register write needs a delay of min 10uS.120	 * Back-to-Back writes to same register needs delay when SD bus clock121	 * is very low w.r.t AHB clock, mainly during boot-time and during card122	 * insert-removal.123	 * We keep 20uS124	 */125	mutex_lock(&kona_dev->write_lock);126	udelay(20);127	val = sdhci_readl(host, KONA_SDHOST_CORESTAT);128 129	if (insert) {130		int ret;131 132		ret = mmc_gpio_get_ro(host->mmc);133		if (ret >= 0)134			val = (val & ~KONA_SDHOST_WP) |135				((ret) ? KONA_SDHOST_WP : 0);136 137		val |= KONA_SDHOST_CD_SW;138		sdhci_writel(host, val, KONA_SDHOST_CORESTAT);139	} else {140		val &= ~KONA_SDHOST_CD_SW;141		sdhci_writel(host, val, KONA_SDHOST_CORESTAT);142	}143	mutex_unlock(&kona_dev->write_lock);144 145	return 0;146}147 148/*149 * SD card interrupt event callback150 */151static void sdhci_bcm_kona_card_event(struct sdhci_host *host)152{153	if (mmc_gpio_get_cd(host->mmc) > 0) {154		dev_dbg(mmc_dev(host->mmc),155			"card inserted\n");156		sdhci_bcm_kona_sd_card_emulate(host, 1);157	} else {158		dev_dbg(mmc_dev(host->mmc),159			"card removed\n");160		sdhci_bcm_kona_sd_card_emulate(host, 0);161	}162}163 164static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,165				u8 power_mode)166{167	/*168	 *  JEDEC and SD spec specify supplying 74 continuous clocks to169	 * device after power up. With minimum bus (100KHz) that170	 * translates to 740us171	 */172	if (power_mode != MMC_POWER_OFF)173		udelay(740);174}175 176static const struct sdhci_ops sdhci_bcm_kona_ops = {177	.set_clock = sdhci_set_clock,178	.get_max_clock = sdhci_pltfm_clk_get_max_clock,179	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,180	.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,181	.set_bus_width = sdhci_set_bus_width,182	.reset = sdhci_reset,183	.set_uhs_signaling = sdhci_set_uhs_signaling,184	.card_event = sdhci_bcm_kona_card_event,185};186 187static const struct sdhci_pltfm_data sdhci_pltfm_data_kona = {188	.ops    = &sdhci_bcm_kona_ops,189	.quirks = SDHCI_QUIRK_NO_CARD_NO_RESET |190		SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR |191		SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE |192		SDHCI_QUIRK_FORCE_BLK_SZ_2048 |193		SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,194};195 196static const struct of_device_id sdhci_bcm_kona_of_match[] = {197	{ .compatible = "brcm,kona-sdhci"},198	{ .compatible = "bcm,kona-sdhci"}, /* deprecated name */199	{}200};201MODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match);202 203static int sdhci_bcm_kona_probe(struct platform_device *pdev)204{205	struct sdhci_bcm_kona_dev *kona_dev = NULL;206	struct sdhci_pltfm_host *pltfm_priv;207	struct device *dev = &pdev->dev;208	struct sdhci_host *host;209	int ret;210 211	ret = 0;212 213	host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona,214			sizeof(*kona_dev));215	if (IS_ERR(host))216		return PTR_ERR(host);217 218	dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr);219 220	pltfm_priv = sdhci_priv(host);221 222	kona_dev = sdhci_pltfm_priv(pltfm_priv);223	mutex_init(&kona_dev->write_lock);224 225	ret = mmc_of_parse(host->mmc);226	if (ret)227		goto err_pltfm_free;228 229	if (!host->mmc->f_max) {230		dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n");231		ret = -ENXIO;232		goto err_pltfm_free;233	}234 235	/* Get and enable the core clock */236	pltfm_priv->clk = devm_clk_get(dev, NULL);237	if (IS_ERR(pltfm_priv->clk)) {238		dev_err(dev, "Failed to get core clock\n");239		ret = PTR_ERR(pltfm_priv->clk);240		goto err_pltfm_free;241	}242 243	ret = clk_set_rate(pltfm_priv->clk, host->mmc->f_max);244	if (ret) {245		dev_err(dev, "Failed to set rate core clock\n");246		goto err_pltfm_free;247	}248 249	ret = clk_prepare_enable(pltfm_priv->clk);250	if (ret) {251		dev_err(dev, "Failed to enable core clock\n");252		goto err_pltfm_free;253	}254 255	dev_dbg(dev, "non-removable=%c\n",256		mmc_card_is_removable(host->mmc) ? 'N' : 'Y');257	dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",258		(mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N',259		(mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N');260 261	if (!mmc_card_is_removable(host->mmc))262		host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;263 264	dev_dbg(dev, "is_8bit=%c\n",265		(host->mmc->caps & MMC_CAP_8_BIT_DATA) ? 'Y' : 'N');266 267	ret = sdhci_bcm_kona_sd_reset(host);268	if (ret)269		goto err_clk_disable;270 271	sdhci_bcm_kona_sd_init(host);272 273	ret = sdhci_add_host(host);274	if (ret)275		goto err_reset;276 277	/* if device is eMMC, emulate card insert right here */278	if (!mmc_card_is_removable(host->mmc)) {279		ret = sdhci_bcm_kona_sd_card_emulate(host, 1);280		if (ret) {281			dev_err(dev,282				"unable to emulate card insertion\n");283			goto err_remove_host;284		}285	}286	/*287	 * Since the card detection GPIO interrupt is configured to be288	 * edge sensitive, check the initial GPIO value here, emulate289	 * only if the card is present290	 */291	if (mmc_gpio_get_cd(host->mmc) > 0)292		sdhci_bcm_kona_sd_card_emulate(host, 1);293 294	dev_dbg(dev, "initialized properly\n");295	return 0;296 297err_remove_host:298	sdhci_remove_host(host, 0);299 300err_reset:301	sdhci_bcm_kona_sd_reset(host);302 303err_clk_disable:304	clk_disable_unprepare(pltfm_priv->clk);305 306err_pltfm_free:307	sdhci_pltfm_free(pdev);308 309	dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret);310	return ret;311}312 313static void sdhci_bcm_kona_remove(struct platform_device *pdev)314{315	struct sdhci_host *host = platform_get_drvdata(pdev);316	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);317	struct clk *clk = pltfm_host->clk;318 319	sdhci_pltfm_remove(pdev);320	clk_disable_unprepare(clk);321}322 323static struct platform_driver sdhci_bcm_kona_driver = {324	.driver		= {325		.name	= "sdhci-kona",326		.probe_type = PROBE_PREFER_ASYNCHRONOUS,327		.pm	= &sdhci_pltfm_pmops,328		.of_match_table = sdhci_bcm_kona_of_match,329	},330	.probe		= sdhci_bcm_kona_probe,331	.remove_new	= sdhci_bcm_kona_remove,332};333module_platform_driver(sdhci_bcm_kona_driver);334 335MODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform");336MODULE_AUTHOR("Broadcom");337MODULE_LICENSE("GPL v2");338