^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (C) 2019 ASPEED Technology Inc. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) /* Copyright (C) 2019 IBM Corp. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/mmc/host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "sdhci-pltfm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define ASPEED_SDC_INFO 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define ASPEED_SDC_S1MMC8 BIT(25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define ASPEED_SDC_S0MMC8 BIT(24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct aspeed_sdc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct aspeed_sdhci {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct aspeed_sdc *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u32 width_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc *sdc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct aspeed_sdhci *sdhci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) bool bus8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u32 info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Set/clear 8 bit mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) spin_lock(&sdc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) info = readl(sdc->regs + ASPEED_SDC_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (bus8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) info |= sdhci->width_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) info &= ~sdhci->width_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) writel(info, sdc->regs + ASPEED_SDC_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) spin_unlock(&sdc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct sdhci_pltfm_host *pltfm_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned long parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u16 clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) parent = clk_get_rate(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (clock == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (WARN_ON(clock > host->max_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) clock = host->max_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) for (div = 2; div < 256; div *= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if ((parent / div) <= clock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) div >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) clk = div << SDHCI_DIVIDER_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) sdhci_enable_clk(host, clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static unsigned int aspeed_sdhci_get_max_clock(struct sdhci_host *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (host->mmc->f_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return host->mmc->f_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return sdhci_pltfm_clk_get_max_clock(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct sdhci_pltfm_host *pltfm_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct aspeed_sdhci *aspeed_sdhci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct aspeed_sdc *aspeed_sdc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u8 ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) pltfm_priv = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) aspeed_sdc = aspeed_sdhci->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* Set/clear 8-bit mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) width == MMC_BUS_WIDTH_8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Set/clear 1 or 4 bit mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (width == MMC_BUS_WIDTH_4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ctrl |= SDHCI_CTRL_4BITBUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ctrl &= ~SDHCI_CTRL_4BITBUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static u32 aspeed_sdhci_readl(struct sdhci_host *host, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) u32 val = readl(host->ioaddr + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (unlikely(reg == SDHCI_PRESENT_STATE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) (host->mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) val ^= SDHCI_CARD_PRESENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static const struct sdhci_ops aspeed_sdhci_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .read_l = aspeed_sdhci_readl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .set_clock = aspeed_sdhci_set_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .get_max_clock = aspeed_sdhci_get_max_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .set_bus_width = aspeed_sdhci_set_bus_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .reset = sdhci_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .set_uhs_signaling = sdhci_set_uhs_signaling,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static const struct sdhci_pltfm_data aspeed_sdhci_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .ops = &aspeed_sdhci_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct resource *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) resource_size_t delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!res || resource_type(res) != IORESOURCE_MEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (res->start < dev->parent->res->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) delta = res->start - dev->parent->res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (delta & (0x100 - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return (delta / 0x100) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int aspeed_sdhci_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct sdhci_pltfm_host *pltfm_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct aspeed_sdhci *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct sdhci_host *host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (IS_ERR(host))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return PTR_ERR(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) dev = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) dev->parent = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) slot = aspeed_sdhci_calculate_slot(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (slot < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) else if (slot >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) dev_info(&pdev->dev, "Configuring for slot %d\n", slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) dev->width_mask = !slot ? ASPEED_SDC_S0MMC8 : ASPEED_SDC_S1MMC8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) sdhci_get_of_property(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (IS_ERR(pltfm_host->clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return PTR_ERR(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ret = clk_prepare_enable(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) dev_err(&pdev->dev, "Unable to enable SDIO clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) goto err_pltfm_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) ret = mmc_of_parse(host->mmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) goto err_sdhci_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) ret = sdhci_add_host(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) goto err_sdhci_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) err_sdhci_add:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) clk_disable_unprepare(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) err_pltfm_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) sdhci_pltfm_free(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static int aspeed_sdhci_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct sdhci_pltfm_host *pltfm_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct sdhci_host *host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int dead = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) host = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) sdhci_remove_host(host, dead);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) clk_disable_unprepare(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) sdhci_pltfm_free(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static const struct of_device_id aspeed_sdhci_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) { .compatible = "aspeed,ast2400-sdhci", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) { .compatible = "aspeed,ast2500-sdhci", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) { .compatible = "aspeed,ast2600-sdhci", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static struct platform_driver aspeed_sdhci_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .name = "sdhci-aspeed",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .probe_type = PROBE_PREFER_ASYNCHRONOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .of_match_table = aspeed_sdhci_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .probe = aspeed_sdhci_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .remove = aspeed_sdhci_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static int aspeed_sdc_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct device_node *parent, *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct aspeed_sdc *sdc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (!sdc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) spin_lock_init(&sdc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) sdc->clk = devm_clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (IS_ERR(sdc->clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return PTR_ERR(sdc->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) ret = clk_prepare_enable(sdc->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) dev_err(&pdev->dev, "Unable to enable SDCLK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) sdc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) sdc->regs = devm_ioremap_resource(&pdev->dev, sdc->res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (IS_ERR(sdc->regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ret = PTR_ERR(sdc->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) goto err_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) dev_set_drvdata(&pdev->dev, sdc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) parent = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) for_each_available_child_of_node(parent, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) struct platform_device *cpdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) cpdev = of_platform_device_create(child, NULL, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (!cpdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) of_node_put(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) goto err_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) err_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) clk_disable_unprepare(sdc->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int aspeed_sdc_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) clk_disable_unprepare(sdc->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static const struct of_device_id aspeed_sdc_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) { .compatible = "aspeed,ast2400-sd-controller", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) { .compatible = "aspeed,ast2500-sd-controller", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) { .compatible = "aspeed,ast2600-sd-controller", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static struct platform_driver aspeed_sdc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .name = "sd-controller-aspeed",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .probe_type = PROBE_PREFER_ASYNCHRONOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .pm = &sdhci_pltfm_pmops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .of_match_table = aspeed_sdc_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .probe = aspeed_sdc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .remove = aspeed_sdc_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static int __init aspeed_sdc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) rc = platform_driver_register(&aspeed_sdhci_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) rc = platform_driver_register(&aspeed_sdc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) platform_driver_unregister(&aspeed_sdhci_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) module_init(aspeed_sdc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static void __exit aspeed_sdc_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) platform_driver_unregister(&aspeed_sdc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) platform_driver_unregister(&aspeed_sdhci_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) module_exit(aspeed_sdc_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) MODULE_LICENSE("GPL");