From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/mmc/host/sdhci-omap.c | 154 +++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 135 insertions(+), 19 deletions(-) diff --git a/kernel/drivers/mmc/host/sdhci-omap.c b/kernel/drivers/mmc/host/sdhci-omap.c index f5bff9e..53c362b 100644 --- a/kernel/drivers/mmc/host/sdhci-omap.c +++ b/kernel/drivers/mmc/host/sdhci-omap.c @@ -1,23 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * SDHCI Controller driver for TI's OMAP SoCs * * Copyright (C) 2017 Texas Instruments * Author: Kishon Vijay Abraham I <kishon@ti.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/delay.h> +#include <linux/mmc/mmc.h> #include <linux/mmc/slot-gpio.h> #include <linux/module.h> #include <linux/of.h> @@ -72,6 +62,8 @@ #define SDHCI_OMAP_IE 0x234 #define INT_CC_EN BIT(0) +#define SDHCI_OMAP_ISE 0x238 + #define SDHCI_OMAP_AC12 0x23c #define AC12_V1V8_SIGEN BIT(19) #define AC12_SCLK_SEL BIT(23) @@ -96,6 +88,7 @@ /* sdhci-omap controller flags */ #define SDHCI_OMAP_REQUIRE_IODELAY BIT(0) +#define SDHCI_OMAP_SPECIAL_RESET BIT(1) struct sdhci_omap_data { u32 offset; @@ -117,6 +110,13 @@ struct pinctrl *pinctrl; struct pinctrl_state **pinctrl_state; bool is_tuning; + /* Omap specific context save */ + u32 con; + u32 hctl; + u32 sysctl; + u32 capa; + u32 ie; + u32 ise; }; static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host); @@ -304,10 +304,6 @@ int ret = 0; u32 reg; int i; - - pltfm_host = sdhci_priv(host); - omap_host = sdhci_pltfm_priv(pltfm_host); - dev = omap_host->dev; /* clock tuning is not needed for upto 52MHz */ if (ios->clock <= 52000000) @@ -701,7 +697,11 @@ struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); - reg |= CON_DMA_MASTER; + reg &= ~CON_DMA_MASTER; + /* Switch to DMA slave mode when using external DMA */ + if (!host->use_external_dma) + reg |= CON_DMA_MASTER; + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); return 0; @@ -790,14 +790,34 @@ sdhci_omap_start_clock(omap_host); } -void sdhci_omap_reset(struct sdhci_host *host, u8 mask) +#define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */ +static void sdhci_omap_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + unsigned long limit = MMC_TIMEOUT_US; + unsigned long i = 0; /* Don't reset data lines during tuning operation */ if (omap_host->is_tuning) mask &= ~SDHCI_RESET_DATA; + + if (omap_host->flags & SDHCI_OMAP_SPECIAL_RESET) { + sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); + while ((!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)) && + (i++ < limit)) + udelay(1); + i = 0; + while ((sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) && + (i++ < limit)) + udelay(1); + + if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) + dev_err(mmc_dev(host->mmc), + "Timeout waiting on controller reset in %s\n", + __func__); + return; + } sdhci_reset(host, mask); } @@ -839,6 +859,15 @@ return intmask; } +static void sdhci_omap_set_timeout(struct sdhci_host *host, + struct mmc_command *cmd) +{ + if (cmd->opcode == MMC_ERASE) + sdhci_set_data_timeout_irq(host, false); + + __sdhci_set_timeout(host, cmd); +} + static struct sdhci_ops sdhci_omap_ops = { .set_clock = sdhci_omap_set_clock, .set_power = sdhci_omap_set_power, @@ -850,6 +879,7 @@ .reset = sdhci_omap_reset, .set_uhs_signaling = sdhci_omap_set_uhs_signaling, .irq = sdhci_omap_irq, + .set_timeout = sdhci_omap_set_timeout, }; static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) @@ -899,6 +929,16 @@ .offset = 0x200, }; +static const struct sdhci_omap_data am335_data = { + .offset = 0x200, + .flags = SDHCI_OMAP_SPECIAL_RESET, +}; + +static const struct sdhci_omap_data am437_data = { + .offset = 0x200, + .flags = SDHCI_OMAP_SPECIAL_RESET, +}; + static const struct sdhci_omap_data dra7_data = { .offset = 0x200, .flags = SDHCI_OMAP_REQUIRE_IODELAY, @@ -907,6 +947,8 @@ static const struct of_device_id omap_sdhci_match[] = { { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, { .compatible = "ti,k2g-sdhci", .data = &k2g_data }, + { .compatible = "ti,am335-sdhci", .data = &am335_data }, + { .compatible = "ti,am437-sdhci", .data = &am437_data }, {}, }; MODULE_DEVICE_TABLE(of, omap_sdhci_match); @@ -1053,6 +1095,7 @@ const struct of_device_id *match; struct sdhci_omap_data *data; const struct soc_device_attribute *soc; + struct resource *regs; match = of_match_device(omap_sdhci_match, dev); if (!match) @@ -1064,6 +1107,10 @@ return -EINVAL; } offset = data->offset; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; host = sdhci_pltfm_init(pdev, &sdhci_omap_pdata, sizeof(*omap_host)); @@ -1081,6 +1128,7 @@ omap_host->timing = MMC_TIMING_LEGACY; omap_host->flags = data->flags; host->ioaddr += offset; + host->mapbase = regs->start + offset; mmc = host->mmc; sdhci_get_of_property(pdev); @@ -1098,6 +1146,9 @@ if (!strcmp(dev_name(dev), "480ad000.mmc")) mmc->f_max = 48000000; } + + if (!mmc_can_gpio_ro(mmc)) + mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; pltfm_host->clk = devm_clk_get(dev, "fck"); if (IS_ERR(pltfm_host->clk)) { @@ -1140,13 +1191,16 @@ goto err_put_sync; } - host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; host->mmc_host_ops.card_busy = sdhci_omap_card_busy; host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq; + + /* Switch to external DMA only if there is the "dmas" property */ + if (of_find_property(dev->of_node, "dmas", NULL)) + sdhci_switch_external_dma(host, true); /* R1B responses is required to properly manage HW busy detection. */ mmc->caps |= MMC_CAP_NEED_RSP_BUSY; @@ -1191,12 +1245,74 @@ return 0; } +#ifdef CONFIG_PM_SLEEP +static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host) +{ + omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL); + omap_host->sysctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL); + omap_host->capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); + omap_host->ie = sdhci_omap_readl(omap_host, SDHCI_OMAP_IE); + omap_host->ise = sdhci_omap_readl(omap_host, SDHCI_OMAP_ISE); +} + +/* Order matters here, HCTL must be restored in two phases */ +static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host) +{ + sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); + sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa); + sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); + + sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, omap_host->sysctl); + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con); + sdhci_omap_writel(omap_host, SDHCI_OMAP_IE, omap_host->ie); + sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise); +} + +static int __maybe_unused sdhci_omap_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + + sdhci_suspend_host(host); + + sdhci_omap_context_save(omap_host); + + pinctrl_pm_select_idle_state(dev); + + pm_runtime_force_suspend(dev); + + return 0; +} + +static int __maybe_unused sdhci_omap_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + + pm_runtime_force_resume(dev); + + pinctrl_pm_select_default_state(dev); + + sdhci_omap_context_restore(omap_host); + + sdhci_resume_host(host); + + return 0; +} +#endif +static SIMPLE_DEV_PM_OPS(sdhci_omap_dev_pm_ops, sdhci_omap_suspend, + sdhci_omap_resume); static struct platform_driver sdhci_omap_driver = { .probe = sdhci_omap_probe, .remove = sdhci_omap_remove, .driver = { .name = "sdhci-omap", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &sdhci_omap_dev_pm_ops, .of_match_table = omap_sdhci_match, }, }; -- Gitblit v1.6.2