12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2e3ec3a3dSSoren Brinkmann /* 3e3ec3a3dSSoren Brinkmann * Arasan Secure Digital Host Controller Interface. 4e3ec3a3dSSoren Brinkmann * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu> 5e3ec3a3dSSoren Brinkmann * Copyright (c) 2012 Wind River Systems, Inc. 6e3ec3a3dSSoren Brinkmann * Copyright (C) 2013 Pengutronix e.K. 7e3ec3a3dSSoren Brinkmann * Copyright (C) 2013 Xilinx Inc. 8e3ec3a3dSSoren Brinkmann * 9e3ec3a3dSSoren Brinkmann * Based on sdhci-of-esdhc.c 10e3ec3a3dSSoren Brinkmann * 11e3ec3a3dSSoren Brinkmann * Copyright (c) 2007 Freescale Semiconductor, Inc. 12e3ec3a3dSSoren Brinkmann * Copyright (c) 2009 MontaVista Software, Inc. 13e3ec3a3dSSoren Brinkmann * 14e3ec3a3dSSoren Brinkmann * Authors: Xiaobo Xie <X.Xie@freescale.com> 15e3ec3a3dSSoren Brinkmann * Anton Vorontsov <avorontsov@ru.mvista.com> 16e3ec3a3dSSoren Brinkmann */ 17e3ec3a3dSSoren Brinkmann 18c390f211SDouglas Anderson #include <linux/clk-provider.h> 193ea4666eSDouglas Anderson #include <linux/mfd/syscon.h> 20e3ec3a3dSSoren Brinkmann #include <linux/module.h> 21308f3f8dSSuman Tripathi #include <linux/of_device.h> 2291aa3661SShawn Lin #include <linux/phy/phy.h> 233ea4666eSDouglas Anderson #include <linux/regmap.h> 243794c542SZach Brown #include <linux/of.h> 25e3ec3a3dSSoren Brinkmann 2684362d79SShawn Lin #include "cqhci.h" 2784362d79SShawn Lin #include "sdhci-pltfm.h" 28e3ec3a3dSSoren Brinkmann 2984362d79SShawn Lin #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 3084362d79SShawn Lin #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 31a05c8465SShawn Lin #define VENDOR_ENHANCED_STROBE BIT(0) 32e3ec3a3dSSoren Brinkmann 33b2db9c67SDouglas Anderson #define PHY_CLK_TOO_SLOW_HZ 400000 34b2db9c67SDouglas Anderson 353ea4666eSDouglas Anderson /* 363ea4666eSDouglas Anderson * On some SoCs the syscon area has a feature where the upper 16-bits of 373ea4666eSDouglas Anderson * each 32-bit register act as a write mask for the lower 16-bits. This allows 383ea4666eSDouglas Anderson * atomic updates of the register without locking. This macro is used on SoCs 393ea4666eSDouglas Anderson * that have that feature. 403ea4666eSDouglas Anderson */ 413ea4666eSDouglas Anderson #define HIWORD_UPDATE(val, mask, shift) \ 423ea4666eSDouglas Anderson ((val) << (shift) | (mask) << ((shift) + 16)) 433ea4666eSDouglas Anderson 443ea4666eSDouglas Anderson /** 453ea4666eSDouglas Anderson * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map 463ea4666eSDouglas Anderson * 473ea4666eSDouglas Anderson * @reg: Offset within the syscon of the register containing this field 483ea4666eSDouglas Anderson * @width: Number of bits for this field 493ea4666eSDouglas Anderson * @shift: Bit offset within @reg of this field (or -1 if not avail) 503ea4666eSDouglas Anderson */ 513ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field { 523ea4666eSDouglas Anderson u32 reg; 533ea4666eSDouglas Anderson u16 width; 543ea4666eSDouglas Anderson s16 shift; 553ea4666eSDouglas Anderson }; 563ea4666eSDouglas Anderson 573ea4666eSDouglas Anderson /** 583ea4666eSDouglas Anderson * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers 593ea4666eSDouglas Anderson * 603ea4666eSDouglas Anderson * It's up to the licensee of the Arsan IP block to make these available 613ea4666eSDouglas Anderson * somewhere if needed. Presumably these will be scattered somewhere that's 623ea4666eSDouglas Anderson * accessible via the syscon API. 633ea4666eSDouglas Anderson * 643ea4666eSDouglas Anderson * @baseclkfreq: Where to find corecfg_baseclkfreq 65b2ca77c9SShawn Lin * @clockmultiplier: Where to find corecfg_clockmultiplier 663ea4666eSDouglas Anderson * @hiword_update: If true, use HIWORD_UPDATE to access the syscon 673ea4666eSDouglas Anderson */ 683ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_map { 693ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field baseclkfreq; 70b2ca77c9SShawn Lin struct sdhci_arasan_soc_ctl_field clockmultiplier; 713ea4666eSDouglas Anderson bool hiword_update; 723ea4666eSDouglas Anderson }; 733ea4666eSDouglas Anderson 74e3ec3a3dSSoren Brinkmann /** 75e1463618SManish Narani * struct sdhci_arasan_clk_data 76e1463618SManish Narani * @sdcardclk_hw: Struct for the clock we might provide to a PHY. 77e1463618SManish Narani * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. 7807a14d1dSManish Narani * @sampleclk_hw: Struct for the clock we might provide to a PHY. 7907a14d1dSManish Narani * @sampleclk: Pointer to normal 'struct clock' for sampleclk_hw. 80f3dafc37SManish Narani * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes 81f3dafc37SManish Narani * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes 82f3dafc37SManish Narani * @set_clk_delays: Function pointer for setting Clock Delays 83e1463618SManish Narani */ 84e1463618SManish Narani struct sdhci_arasan_clk_data { 85e1463618SManish Narani struct clk_hw sdcardclk_hw; 86e1463618SManish Narani struct clk *sdcardclk; 8707a14d1dSManish Narani struct clk_hw sampleclk_hw; 8807a14d1dSManish Narani struct clk *sampleclk; 89f3dafc37SManish Narani int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; 90f3dafc37SManish Narani int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; 91f3dafc37SManish Narani void (*set_clk_delays)(struct sdhci_host *host); 92e1463618SManish Narani }; 93e1463618SManish Narani 94e1463618SManish Narani /** 95e3ec3a3dSSoren Brinkmann * struct sdhci_arasan_data 96c390f211SDouglas Anderson * @host: Pointer to the main SDHCI host structure. 97e3ec3a3dSSoren Brinkmann * @clk_ahb: Pointer to the AHB clock 9891aa3661SShawn Lin * @phy: Pointer to the generic phy 99b2db9c67SDouglas Anderson * @is_phy_on: True if the PHY is on; false if not. 100e1463618SManish Narani * @clk_data: Struct for the Arasan Controller Clock Data. 1013ea4666eSDouglas Anderson * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. 1023ea4666eSDouglas Anderson * @soc_ctl_map: Map to get offsets into soc_ctl registers. 103e3ec3a3dSSoren Brinkmann */ 104e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data { 105c390f211SDouglas Anderson struct sdhci_host *host; 106e3ec3a3dSSoren Brinkmann struct clk *clk_ahb; 10791aa3661SShawn Lin struct phy *phy; 108b2db9c67SDouglas Anderson bool is_phy_on; 1093ea4666eSDouglas Anderson 11084362d79SShawn Lin bool has_cqe; 111e1463618SManish Narani struct sdhci_arasan_clk_data clk_data; 112c390f211SDouglas Anderson 1133ea4666eSDouglas Anderson struct regmap *soc_ctl_base; 1143ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 1153794c542SZach Brown unsigned int quirks; /* Arasan deviations from spec */ 1163794c542SZach Brown 1173794c542SZach Brown /* Controller does not have CD wired and will not function normally without */ 1183794c542SZach Brown #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0) 1193f2c7d5dSHelmut Grohne /* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the 1203f2c7d5dSHelmut Grohne * internal clock even when the clock isn't stable */ 1213f2c7d5dSHelmut Grohne #define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1) 122e3ec3a3dSSoren Brinkmann }; 123e3ec3a3dSSoren Brinkmann 12406b23ca0SFaiz Abbas struct sdhci_arasan_of_data { 12506b23ca0SFaiz Abbas const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 12606b23ca0SFaiz Abbas const struct sdhci_pltfm_data *pdata; 12706b23ca0SFaiz Abbas }; 12806b23ca0SFaiz Abbas 1293ea4666eSDouglas Anderson static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { 1303ea4666eSDouglas Anderson .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 }, 131b2ca77c9SShawn Lin .clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0}, 1323ea4666eSDouglas Anderson .hiword_update = true, 1333ea4666eSDouglas Anderson }; 1343ea4666eSDouglas Anderson 1355c1a4f40SRamuthevar Vadivel Muruganx static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = { 1365c1a4f40SRamuthevar Vadivel Muruganx .baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 }, 1375c1a4f40SRamuthevar Vadivel Muruganx .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 1385c1a4f40SRamuthevar Vadivel Muruganx .hiword_update = false, 1395c1a4f40SRamuthevar Vadivel Muruganx }; 1405c1a4f40SRamuthevar Vadivel Muruganx 141d1807ad6SRamuthevar Vadivel Murugan static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { 142d1807ad6SRamuthevar Vadivel Murugan .baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 }, 143d1807ad6SRamuthevar Vadivel Murugan .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 144d1807ad6SRamuthevar Vadivel Murugan .hiword_update = false, 145d1807ad6SRamuthevar Vadivel Murugan }; 146d1807ad6SRamuthevar Vadivel Murugan 1473ea4666eSDouglas Anderson /** 1483ea4666eSDouglas Anderson * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers 1493ea4666eSDouglas Anderson * 1503ea4666eSDouglas Anderson * This function allows writing to fields in sdhci_arasan_soc_ctl_map. 1513ea4666eSDouglas Anderson * Note that if a field is specified as not available (shift < 0) then 1523ea4666eSDouglas Anderson * this function will silently return an error code. It will be noisy 1533ea4666eSDouglas Anderson * and print errors for any other (unexpected) errors. 1543ea4666eSDouglas Anderson * 1553ea4666eSDouglas Anderson * @host: The sdhci_host 1563ea4666eSDouglas Anderson * @fld: The field to write to 1573ea4666eSDouglas Anderson * @val: The value to write 1583ea4666eSDouglas Anderson */ 1593ea4666eSDouglas Anderson static int sdhci_arasan_syscon_write(struct sdhci_host *host, 1603ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_field *fld, 1613ea4666eSDouglas Anderson u32 val) 1623ea4666eSDouglas Anderson { 1633ea4666eSDouglas Anderson struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1643ea4666eSDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 1653ea4666eSDouglas Anderson struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base; 1663ea4666eSDouglas Anderson u32 reg = fld->reg; 1673ea4666eSDouglas Anderson u16 width = fld->width; 1683ea4666eSDouglas Anderson s16 shift = fld->shift; 1693ea4666eSDouglas Anderson int ret; 1703ea4666eSDouglas Anderson 1713ea4666eSDouglas Anderson /* 1723ea4666eSDouglas Anderson * Silently return errors for shift < 0 so caller doesn't have 1733ea4666eSDouglas Anderson * to check for fields which are optional. For fields that 1743ea4666eSDouglas Anderson * are required then caller needs to do something special 1753ea4666eSDouglas Anderson * anyway. 1763ea4666eSDouglas Anderson */ 1773ea4666eSDouglas Anderson if (shift < 0) 1783ea4666eSDouglas Anderson return -EINVAL; 1793ea4666eSDouglas Anderson 1803ea4666eSDouglas Anderson if (sdhci_arasan->soc_ctl_map->hiword_update) 1813ea4666eSDouglas Anderson ret = regmap_write(soc_ctl_base, reg, 1823ea4666eSDouglas Anderson HIWORD_UPDATE(val, GENMASK(width, 0), 1833ea4666eSDouglas Anderson shift)); 1843ea4666eSDouglas Anderson else 1853ea4666eSDouglas Anderson ret = regmap_update_bits(soc_ctl_base, reg, 1863ea4666eSDouglas Anderson GENMASK(shift + width, shift), 1873ea4666eSDouglas Anderson val << shift); 1883ea4666eSDouglas Anderson 1893ea4666eSDouglas Anderson /* Yell about (unexpected) regmap errors */ 1903ea4666eSDouglas Anderson if (ret) 1913ea4666eSDouglas Anderson pr_warn("%s: Regmap write fail: %d\n", 1923ea4666eSDouglas Anderson mmc_hostname(host->mmc), ret); 1933ea4666eSDouglas Anderson 1943ea4666eSDouglas Anderson return ret; 1953ea4666eSDouglas Anderson } 1963ea4666eSDouglas Anderson 197802ac39aSShawn Lin static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) 198802ac39aSShawn Lin { 199802ac39aSShawn Lin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 200802ac39aSShawn Lin struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 201f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 2026fc09244SDouglas Anderson bool ctrl_phy = false; 203802ac39aSShawn Lin 204b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy)) { 205b2db9c67SDouglas Anderson if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) { 206b2db9c67SDouglas Anderson /* 207b2db9c67SDouglas Anderson * If PHY off, set clock to max speed and power PHY on. 208b2db9c67SDouglas Anderson * 209b2db9c67SDouglas Anderson * Although PHY docs apparently suggest power cycling 210b2db9c67SDouglas Anderson * when changing the clock the PHY doesn't like to be 211b2db9c67SDouglas Anderson * powered on while at low speeds like those used in ID 212b2db9c67SDouglas Anderson * mode. Even worse is powering the PHY on while the 213b2db9c67SDouglas Anderson * clock is off. 214b2db9c67SDouglas Anderson * 215b2db9c67SDouglas Anderson * To workaround the PHY limitations, the best we can 216b2db9c67SDouglas Anderson * do is to power it on at a faster speed and then slam 217b2db9c67SDouglas Anderson * through low speeds without power cycling. 218b2db9c67SDouglas Anderson */ 219b2db9c67SDouglas Anderson sdhci_set_clock(host, host->max_clk); 220b2db9c67SDouglas Anderson phy_power_on(sdhci_arasan->phy); 221b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 222802ac39aSShawn Lin 223b2db9c67SDouglas Anderson /* 224b2db9c67SDouglas Anderson * We'll now fall through to the below case with 225b2db9c67SDouglas Anderson * ctrl_phy = false (so we won't turn off/on). The 226b2db9c67SDouglas Anderson * sdhci_set_clock() will set the real clock. 227b2db9c67SDouglas Anderson */ 228b2db9c67SDouglas Anderson } else if (clock > PHY_CLK_TOO_SLOW_HZ) { 229b2db9c67SDouglas Anderson /* 230b2db9c67SDouglas Anderson * At higher clock speeds the PHY is fine being power 231b2db9c67SDouglas Anderson * cycled and docs say you _should_ power cycle when 232b2db9c67SDouglas Anderson * changing clock speeds. 233b2db9c67SDouglas Anderson */ 234b2db9c67SDouglas Anderson ctrl_phy = true; 235b2db9c67SDouglas Anderson } 236b2db9c67SDouglas Anderson } 237b2db9c67SDouglas Anderson 238b2db9c67SDouglas Anderson if (ctrl_phy && sdhci_arasan->is_phy_on) { 239802ac39aSShawn Lin phy_power_off(sdhci_arasan->phy); 240b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = false; 241802ac39aSShawn Lin } 242802ac39aSShawn Lin 243f3dafc37SManish Narani /* Set the Input and Output Clock Phase Delays */ 244f3dafc37SManish Narani if (clk_data->set_clk_delays) 245f3dafc37SManish Narani clk_data->set_clk_delays(host); 246f3dafc37SManish Narani 247802ac39aSShawn Lin sdhci_set_clock(host, clock); 248802ac39aSShawn Lin 2493f2c7d5dSHelmut Grohne if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE) 2503f2c7d5dSHelmut Grohne /* 2513f2c7d5dSHelmut Grohne * Some controllers immediately report SDHCI_CLOCK_INT_STABLE 2523f2c7d5dSHelmut Grohne * after enabling the clock even though the clock is not 2533f2c7d5dSHelmut Grohne * stable. Trying to use a clock without waiting here results 2543f2c7d5dSHelmut Grohne * in EILSEQ while detecting some older/slower cards. The 2553f2c7d5dSHelmut Grohne * chosen delay is the maximum delay from sdhci_set_clock. 2563f2c7d5dSHelmut Grohne */ 2573f2c7d5dSHelmut Grohne msleep(20); 2583f2c7d5dSHelmut Grohne 2596fc09244SDouglas Anderson if (ctrl_phy) { 260802ac39aSShawn Lin phy_power_on(sdhci_arasan->phy); 261b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 262802ac39aSShawn Lin } 263802ac39aSShawn Lin } 264802ac39aSShawn Lin 265a05c8465SShawn Lin static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, 266a05c8465SShawn Lin struct mmc_ios *ios) 267a05c8465SShawn Lin { 268a05c8465SShawn Lin u32 vendor; 269a05c8465SShawn Lin struct sdhci_host *host = mmc_priv(mmc); 270a05c8465SShawn Lin 2710daf72feSJean-Francois Dagenais vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER); 272a05c8465SShawn Lin if (ios->enhanced_strobe) 273a05c8465SShawn Lin vendor |= VENDOR_ENHANCED_STROBE; 274a05c8465SShawn Lin else 275a05c8465SShawn Lin vendor &= ~VENDOR_ENHANCED_STROBE; 276a05c8465SShawn Lin 2770daf72feSJean-Francois Dagenais sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER); 278a05c8465SShawn Lin } 279a05c8465SShawn Lin 28013d62fd2SWei Yongjun static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) 2813794c542SZach Brown { 2823794c542SZach Brown u8 ctrl; 2833794c542SZach Brown struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2843794c542SZach Brown struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 2853794c542SZach Brown 2863794c542SZach Brown sdhci_reset(host, mask); 2873794c542SZach Brown 2883794c542SZach Brown if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) { 2893794c542SZach Brown ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 2903794c542SZach Brown ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN; 2913794c542SZach Brown sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 2923794c542SZach Brown } 2933794c542SZach Brown } 2943794c542SZach Brown 2958a3bee9bSShawn Lin static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, 2968a3bee9bSShawn Lin struct mmc_ios *ios) 2978a3bee9bSShawn Lin { 2988a3bee9bSShawn Lin switch (ios->signal_voltage) { 2998a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_180: 3008a3bee9bSShawn Lin /* 3018a3bee9bSShawn Lin * Plese don't switch to 1V8 as arasan,5.1 doesn't 3028a3bee9bSShawn Lin * actually refer to this setting to indicate the 3038a3bee9bSShawn Lin * signal voltage and the state machine will be broken 3048a3bee9bSShawn Lin * actually if we force to enable 1V8. That's something 3058a3bee9bSShawn Lin * like broken quirk but we could work around here. 3068a3bee9bSShawn Lin */ 3078a3bee9bSShawn Lin return 0; 3088a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_330: 3098a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_120: 3108a3bee9bSShawn Lin /* We don't support 3V3 and 1V2 */ 3118a3bee9bSShawn Lin break; 3128a3bee9bSShawn Lin } 3138a3bee9bSShawn Lin 3148a3bee9bSShawn Lin return -EINVAL; 3158a3bee9bSShawn Lin } 3168a3bee9bSShawn Lin 317043f2dcaSMilan Stevanovic static void sdhci_arasan_set_power(struct sdhci_host *host, unsigned char mode, 318043f2dcaSMilan Stevanovic unsigned short vdd) 319043f2dcaSMilan Stevanovic { 320043f2dcaSMilan Stevanovic if (!IS_ERR(host->mmc->supply.vmmc)) { 321043f2dcaSMilan Stevanovic struct mmc_host *mmc = host->mmc; 322043f2dcaSMilan Stevanovic 323043f2dcaSMilan Stevanovic mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); 324043f2dcaSMilan Stevanovic } 325043f2dcaSMilan Stevanovic sdhci_set_power_noreg(host, mode, vdd); 326043f2dcaSMilan Stevanovic } 327043f2dcaSMilan Stevanovic 328a81dae3aSJulia Lawall static const struct sdhci_ops sdhci_arasan_ops = { 329802ac39aSShawn Lin .set_clock = sdhci_arasan_set_clock, 330e3ec3a3dSSoren Brinkmann .get_max_clock = sdhci_pltfm_clk_get_max_clock, 3318cc35289SShawn Lin .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 3322317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 3333794c542SZach Brown .reset = sdhci_arasan_reset, 33496d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 335043f2dcaSMilan Stevanovic .set_power = sdhci_arasan_set_power, 336e3ec3a3dSSoren Brinkmann }; 337e3ec3a3dSSoren Brinkmann 338a81dae3aSJulia Lawall static const struct sdhci_pltfm_data sdhci_arasan_pdata = { 339e3ec3a3dSSoren Brinkmann .ops = &sdhci_arasan_ops, 3402d532d45SSuneel Garapati .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 3412d532d45SSuneel Garapati .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 34257aac337SPhil Edworthy SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 34357aac337SPhil Edworthy SDHCI_QUIRK2_STOP_WITH_TC, 344e3ec3a3dSSoren Brinkmann }; 345e3ec3a3dSSoren Brinkmann 34606b23ca0SFaiz Abbas static struct sdhci_arasan_of_data sdhci_arasan_data = { 34706b23ca0SFaiz Abbas .pdata = &sdhci_arasan_pdata, 34806b23ca0SFaiz Abbas }; 34906b23ca0SFaiz Abbas 35084362d79SShawn Lin static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) 35184362d79SShawn Lin { 35284362d79SShawn Lin int cmd_error = 0; 35384362d79SShawn Lin int data_error = 0; 35484362d79SShawn Lin 35584362d79SShawn Lin if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 35684362d79SShawn Lin return intmask; 35784362d79SShawn Lin 35884362d79SShawn Lin cqhci_irq(host->mmc, intmask, cmd_error, data_error); 35984362d79SShawn Lin 36084362d79SShawn Lin return 0; 36184362d79SShawn Lin } 36284362d79SShawn Lin 36384362d79SShawn Lin static void sdhci_arasan_dumpregs(struct mmc_host *mmc) 36484362d79SShawn Lin { 36584362d79SShawn Lin sdhci_dumpregs(mmc_priv(mmc)); 36684362d79SShawn Lin } 36784362d79SShawn Lin 36884362d79SShawn Lin static void sdhci_arasan_cqe_enable(struct mmc_host *mmc) 36984362d79SShawn Lin { 37084362d79SShawn Lin struct sdhci_host *host = mmc_priv(mmc); 37184362d79SShawn Lin u32 reg; 37284362d79SShawn Lin 37384362d79SShawn Lin reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 37484362d79SShawn Lin while (reg & SDHCI_DATA_AVAILABLE) { 37584362d79SShawn Lin sdhci_readl(host, SDHCI_BUFFER); 37684362d79SShawn Lin reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 37784362d79SShawn Lin } 37884362d79SShawn Lin 37984362d79SShawn Lin sdhci_cqe_enable(mmc); 38084362d79SShawn Lin } 38184362d79SShawn Lin 38284362d79SShawn Lin static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = { 38384362d79SShawn Lin .enable = sdhci_arasan_cqe_enable, 38484362d79SShawn Lin .disable = sdhci_cqe_disable, 38584362d79SShawn Lin .dumpregs = sdhci_arasan_dumpregs, 38684362d79SShawn Lin }; 38784362d79SShawn Lin 38884362d79SShawn Lin static const struct sdhci_ops sdhci_arasan_cqe_ops = { 38984362d79SShawn Lin .set_clock = sdhci_arasan_set_clock, 39084362d79SShawn Lin .get_max_clock = sdhci_pltfm_clk_get_max_clock, 39184362d79SShawn Lin .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 39284362d79SShawn Lin .set_bus_width = sdhci_set_bus_width, 39384362d79SShawn Lin .reset = sdhci_arasan_reset, 39484362d79SShawn Lin .set_uhs_signaling = sdhci_set_uhs_signaling, 39584362d79SShawn Lin .set_power = sdhci_arasan_set_power, 39684362d79SShawn Lin .irq = sdhci_arasan_cqhci_irq, 39784362d79SShawn Lin }; 39884362d79SShawn Lin 39984362d79SShawn Lin static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { 40084362d79SShawn Lin .ops = &sdhci_arasan_cqe_ops, 40184362d79SShawn Lin .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 40284362d79SShawn Lin .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 40384362d79SShawn Lin SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, 40484362d79SShawn Lin }; 40584362d79SShawn Lin 40606b23ca0SFaiz Abbas static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { 40706b23ca0SFaiz Abbas .soc_ctl_map = &rk3399_soc_ctl_map, 40806b23ca0SFaiz Abbas .pdata = &sdhci_arasan_cqe_pdata, 40906b23ca0SFaiz Abbas }; 41006b23ca0SFaiz Abbas 4115c1a4f40SRamuthevar Vadivel Muruganx static struct sdhci_arasan_of_data intel_lgm_emmc_data = { 4125c1a4f40SRamuthevar Vadivel Muruganx .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, 4135c1a4f40SRamuthevar Vadivel Muruganx .pdata = &sdhci_arasan_cqe_pdata, 4145c1a4f40SRamuthevar Vadivel Muruganx }; 4155c1a4f40SRamuthevar Vadivel Muruganx 416d1807ad6SRamuthevar Vadivel Murugan static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { 417d1807ad6SRamuthevar Vadivel Murugan .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, 418d1807ad6SRamuthevar Vadivel Murugan .pdata = &sdhci_arasan_cqe_pdata, 419d1807ad6SRamuthevar Vadivel Murugan }; 420d1807ad6SRamuthevar Vadivel Murugan 421e3ec3a3dSSoren Brinkmann #ifdef CONFIG_PM_SLEEP 422e3ec3a3dSSoren Brinkmann /** 423e3ec3a3dSSoren Brinkmann * sdhci_arasan_suspend - Suspend method for the driver 424e3ec3a3dSSoren Brinkmann * @dev: Address of the device structure 425e3ec3a3dSSoren Brinkmann * Returns 0 on success and error value on error 426e3ec3a3dSSoren Brinkmann * 427e3ec3a3dSSoren Brinkmann * Put the device in a low power state. 428e3ec3a3dSSoren Brinkmann */ 429e3ec3a3dSSoren Brinkmann static int sdhci_arasan_suspend(struct device *dev) 430e3ec3a3dSSoren Brinkmann { 431970f2d90SWolfram Sang struct sdhci_host *host = dev_get_drvdata(dev); 432e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 43389211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 434e3ec3a3dSSoren Brinkmann int ret; 435e3ec3a3dSSoren Brinkmann 436d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 437d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 438d38dcad4SAdrian Hunter 43984362d79SShawn Lin if (sdhci_arasan->has_cqe) { 44084362d79SShawn Lin ret = cqhci_suspend(host->mmc); 44184362d79SShawn Lin if (ret) 44284362d79SShawn Lin return ret; 44384362d79SShawn Lin } 44484362d79SShawn Lin 445e3ec3a3dSSoren Brinkmann ret = sdhci_suspend_host(host); 446e3ec3a3dSSoren Brinkmann if (ret) 447e3ec3a3dSSoren Brinkmann return ret; 448e3ec3a3dSSoren Brinkmann 449b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) { 45091aa3661SShawn Lin ret = phy_power_off(sdhci_arasan->phy); 45191aa3661SShawn Lin if (ret) { 45291aa3661SShawn Lin dev_err(dev, "Cannot power off phy.\n"); 45391aa3661SShawn Lin sdhci_resume_host(host); 45491aa3661SShawn Lin return ret; 45591aa3661SShawn Lin } 456b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = false; 45791aa3661SShawn Lin } 45891aa3661SShawn Lin 459e3ec3a3dSSoren Brinkmann clk_disable(pltfm_host->clk); 460e3ec3a3dSSoren Brinkmann clk_disable(sdhci_arasan->clk_ahb); 461e3ec3a3dSSoren Brinkmann 462e3ec3a3dSSoren Brinkmann return 0; 463e3ec3a3dSSoren Brinkmann } 464e3ec3a3dSSoren Brinkmann 465e3ec3a3dSSoren Brinkmann /** 466e3ec3a3dSSoren Brinkmann * sdhci_arasan_resume - Resume method for the driver 467e3ec3a3dSSoren Brinkmann * @dev: Address of the device structure 468e3ec3a3dSSoren Brinkmann * Returns 0 on success and error value on error 469e3ec3a3dSSoren Brinkmann * 470e3ec3a3dSSoren Brinkmann * Resume operation after suspend 471e3ec3a3dSSoren Brinkmann */ 472e3ec3a3dSSoren Brinkmann static int sdhci_arasan_resume(struct device *dev) 473e3ec3a3dSSoren Brinkmann { 474970f2d90SWolfram Sang struct sdhci_host *host = dev_get_drvdata(dev); 475e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 47689211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 477e3ec3a3dSSoren Brinkmann int ret; 478e3ec3a3dSSoren Brinkmann 479e3ec3a3dSSoren Brinkmann ret = clk_enable(sdhci_arasan->clk_ahb); 480e3ec3a3dSSoren Brinkmann if (ret) { 481e3ec3a3dSSoren Brinkmann dev_err(dev, "Cannot enable AHB clock.\n"); 482e3ec3a3dSSoren Brinkmann return ret; 483e3ec3a3dSSoren Brinkmann } 484e3ec3a3dSSoren Brinkmann 485e3ec3a3dSSoren Brinkmann ret = clk_enable(pltfm_host->clk); 486e3ec3a3dSSoren Brinkmann if (ret) { 487e3ec3a3dSSoren Brinkmann dev_err(dev, "Cannot enable SD clock.\n"); 488e3ec3a3dSSoren Brinkmann return ret; 489e3ec3a3dSSoren Brinkmann } 490e3ec3a3dSSoren Brinkmann 491b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) { 49291aa3661SShawn Lin ret = phy_power_on(sdhci_arasan->phy); 49391aa3661SShawn Lin if (ret) { 49491aa3661SShawn Lin dev_err(dev, "Cannot power on phy.\n"); 49591aa3661SShawn Lin return ret; 49691aa3661SShawn Lin } 497b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 49891aa3661SShawn Lin } 49991aa3661SShawn Lin 50084362d79SShawn Lin ret = sdhci_resume_host(host); 50184362d79SShawn Lin if (ret) { 50284362d79SShawn Lin dev_err(dev, "Cannot resume host.\n"); 50384362d79SShawn Lin return ret; 50484362d79SShawn Lin } 50584362d79SShawn Lin 50684362d79SShawn Lin if (sdhci_arasan->has_cqe) 50784362d79SShawn Lin return cqhci_resume(host->mmc); 50884362d79SShawn Lin 50984362d79SShawn Lin return 0; 510e3ec3a3dSSoren Brinkmann } 511e3ec3a3dSSoren Brinkmann #endif /* ! CONFIG_PM_SLEEP */ 512e3ec3a3dSSoren Brinkmann 513e3ec3a3dSSoren Brinkmann static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, 514e3ec3a3dSSoren Brinkmann sdhci_arasan_resume); 515e3ec3a3dSSoren Brinkmann 5163ea4666eSDouglas Anderson static const struct of_device_id sdhci_arasan_of_match[] = { 5173ea4666eSDouglas Anderson /* SoC-specific compatible strings w/ soc_ctl_map */ 5183ea4666eSDouglas Anderson { 5193ea4666eSDouglas Anderson .compatible = "rockchip,rk3399-sdhci-5.1", 52006b23ca0SFaiz Abbas .data = &sdhci_arasan_rk3399_data, 5213ea4666eSDouglas Anderson }, 5225c1a4f40SRamuthevar Vadivel Muruganx { 5235c1a4f40SRamuthevar Vadivel Muruganx .compatible = "intel,lgm-sdhci-5.1-emmc", 5245c1a4f40SRamuthevar Vadivel Muruganx .data = &intel_lgm_emmc_data, 5255c1a4f40SRamuthevar Vadivel Muruganx }, 526d1807ad6SRamuthevar Vadivel Murugan { 527d1807ad6SRamuthevar Vadivel Murugan .compatible = "intel,lgm-sdhci-5.1-sdxc", 528d1807ad6SRamuthevar Vadivel Murugan .data = &intel_lgm_sdxc_data, 529d1807ad6SRamuthevar Vadivel Murugan }, 5303ea4666eSDouglas Anderson /* Generic compatible below here */ 53106b23ca0SFaiz Abbas { 53206b23ca0SFaiz Abbas .compatible = "arasan,sdhci-8.9a", 53306b23ca0SFaiz Abbas .data = &sdhci_arasan_data, 53406b23ca0SFaiz Abbas }, 53506b23ca0SFaiz Abbas { 53606b23ca0SFaiz Abbas .compatible = "arasan,sdhci-5.1", 53706b23ca0SFaiz Abbas .data = &sdhci_arasan_data, 53806b23ca0SFaiz Abbas }, 53906b23ca0SFaiz Abbas { 54006b23ca0SFaiz Abbas .compatible = "arasan,sdhci-4.9a", 54106b23ca0SFaiz Abbas .data = &sdhci_arasan_data, 54206b23ca0SFaiz Abbas }, 5433ea4666eSDouglas Anderson { /* sentinel */ } 5443ea4666eSDouglas Anderson }; 5453ea4666eSDouglas Anderson MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); 5463ea4666eSDouglas Anderson 5473ea4666eSDouglas Anderson /** 548c390f211SDouglas Anderson * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate 549c390f211SDouglas Anderson * 550c390f211SDouglas Anderson * Return the current actual rate of the SD card clock. This can be used 551c390f211SDouglas Anderson * to communicate with out PHY. 552c390f211SDouglas Anderson * 553c390f211SDouglas Anderson * @hw: Pointer to the hardware clock structure. 554c390f211SDouglas Anderson * @parent_rate The parent rate (should be rate of clk_xin). 555c390f211SDouglas Anderson * Returns the card clock rate. 556c390f211SDouglas Anderson */ 557c390f211SDouglas Anderson static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, 558c390f211SDouglas Anderson unsigned long parent_rate) 559c390f211SDouglas Anderson 560c390f211SDouglas Anderson { 561e1463618SManish Narani struct sdhci_arasan_clk_data *clk_data = 562e1463618SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 563c390f211SDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = 564e1463618SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 565c390f211SDouglas Anderson struct sdhci_host *host = sdhci_arasan->host; 566c390f211SDouglas Anderson 567c390f211SDouglas Anderson return host->mmc->actual_clock; 568c390f211SDouglas Anderson } 569c390f211SDouglas Anderson 570c390f211SDouglas Anderson static const struct clk_ops arasan_sdcardclk_ops = { 571c390f211SDouglas Anderson .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 572c390f211SDouglas Anderson }; 573c390f211SDouglas Anderson 574c390f211SDouglas Anderson /** 57507a14d1dSManish Narani * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate 57607a14d1dSManish Narani * 57707a14d1dSManish Narani * Return the current actual rate of the sampling clock. This can be used 57807a14d1dSManish Narani * to communicate with out PHY. 57907a14d1dSManish Narani * 58007a14d1dSManish Narani * @hw: Pointer to the hardware clock structure. 58107a14d1dSManish Narani * @parent_rate The parent rate (should be rate of clk_xin). 58207a14d1dSManish Narani * Returns the sample clock rate. 58307a14d1dSManish Narani */ 58407a14d1dSManish Narani static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, 58507a14d1dSManish Narani unsigned long parent_rate) 58607a14d1dSManish Narani 58707a14d1dSManish Narani { 58807a14d1dSManish Narani struct sdhci_arasan_clk_data *clk_data = 58907a14d1dSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 59007a14d1dSManish Narani struct sdhci_arasan_data *sdhci_arasan = 59107a14d1dSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 59207a14d1dSManish Narani struct sdhci_host *host = sdhci_arasan->host; 59307a14d1dSManish Narani 59407a14d1dSManish Narani return host->mmc->actual_clock; 59507a14d1dSManish Narani } 59607a14d1dSManish Narani 59707a14d1dSManish Narani static const struct clk_ops arasan_sampleclk_ops = { 59807a14d1dSManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 59907a14d1dSManish Narani }; 60007a14d1dSManish Narani 60107a14d1dSManish Narani /** 602b2ca77c9SShawn Lin * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier 603b2ca77c9SShawn Lin * 604b2ca77c9SShawn Lin * The corecfg_clockmultiplier is supposed to contain clock multiplier 605b2ca77c9SShawn Lin * value of programmable clock generator. 606b2ca77c9SShawn Lin * 607b2ca77c9SShawn Lin * NOTES: 608b2ca77c9SShawn Lin * - Many existing devices don't seem to do this and work fine. To keep 609b2ca77c9SShawn Lin * compatibility for old hardware where the device tree doesn't provide a 610b2ca77c9SShawn Lin * register map, this function is a noop if a soc_ctl_map hasn't been provided 611b2ca77c9SShawn Lin * for this platform. 612b2ca77c9SShawn Lin * - The value of corecfg_clockmultiplier should sync with that of corresponding 613b2ca77c9SShawn Lin * value reading from sdhci_capability_register. So this function is called 614b2ca77c9SShawn Lin * once at probe time and never called again. 615b2ca77c9SShawn Lin * 616b2ca77c9SShawn Lin * @host: The sdhci_host 617b2ca77c9SShawn Lin */ 618b2ca77c9SShawn Lin static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, 619b2ca77c9SShawn Lin u32 value) 620b2ca77c9SShawn Lin { 621b2ca77c9SShawn Lin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 622b2ca77c9SShawn Lin struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 623b2ca77c9SShawn Lin const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 624b2ca77c9SShawn Lin sdhci_arasan->soc_ctl_map; 625b2ca77c9SShawn Lin 626b2ca77c9SShawn Lin /* Having a map is optional */ 627b2ca77c9SShawn Lin if (!soc_ctl_map) 628b2ca77c9SShawn Lin return; 629b2ca77c9SShawn Lin 630b2ca77c9SShawn Lin /* If we have a map, we expect to have a syscon */ 631b2ca77c9SShawn Lin if (!sdhci_arasan->soc_ctl_base) { 632b2ca77c9SShawn Lin pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 633b2ca77c9SShawn Lin mmc_hostname(host->mmc)); 634b2ca77c9SShawn Lin return; 635b2ca77c9SShawn Lin } 636b2ca77c9SShawn Lin 637b2ca77c9SShawn Lin sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value); 638b2ca77c9SShawn Lin } 639b2ca77c9SShawn Lin 640b2ca77c9SShawn Lin /** 6413ea4666eSDouglas Anderson * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq 6423ea4666eSDouglas Anderson * 6433ea4666eSDouglas Anderson * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This 6443ea4666eSDouglas Anderson * function can be used to make that happen. 6453ea4666eSDouglas Anderson * 6463ea4666eSDouglas Anderson * NOTES: 6473ea4666eSDouglas Anderson * - Many existing devices don't seem to do this and work fine. To keep 6483ea4666eSDouglas Anderson * compatibility for old hardware where the device tree doesn't provide a 6493ea4666eSDouglas Anderson * register map, this function is a noop if a soc_ctl_map hasn't been provided 6503ea4666eSDouglas Anderson * for this platform. 6513ea4666eSDouglas Anderson * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider 6523ea4666eSDouglas Anderson * to achieve lower clock rates. That means that this function is called once 6533ea4666eSDouglas Anderson * at probe time and never called again. 6543ea4666eSDouglas Anderson * 6553ea4666eSDouglas Anderson * @host: The sdhci_host 6563ea4666eSDouglas Anderson */ 6573ea4666eSDouglas Anderson static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) 6583ea4666eSDouglas Anderson { 6593ea4666eSDouglas Anderson struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 6603ea4666eSDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 6613ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 6623ea4666eSDouglas Anderson sdhci_arasan->soc_ctl_map; 6633ea4666eSDouglas Anderson u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000); 6643ea4666eSDouglas Anderson 6653ea4666eSDouglas Anderson /* Having a map is optional */ 6663ea4666eSDouglas Anderson if (!soc_ctl_map) 6673ea4666eSDouglas Anderson return; 6683ea4666eSDouglas Anderson 6693ea4666eSDouglas Anderson /* If we have a map, we expect to have a syscon */ 6703ea4666eSDouglas Anderson if (!sdhci_arasan->soc_ctl_base) { 6713ea4666eSDouglas Anderson pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 6723ea4666eSDouglas Anderson mmc_hostname(host->mmc)); 6733ea4666eSDouglas Anderson return; 6743ea4666eSDouglas Anderson } 6753ea4666eSDouglas Anderson 6763ea4666eSDouglas Anderson sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz); 6773ea4666eSDouglas Anderson } 6783ea4666eSDouglas Anderson 679f3dafc37SManish Narani static void sdhci_arasan_set_clk_delays(struct sdhci_host *host) 680f3dafc37SManish Narani { 681f3dafc37SManish Narani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 682f3dafc37SManish Narani struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 683f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 684f3dafc37SManish Narani 685f3dafc37SManish Narani clk_set_phase(clk_data->sampleclk, 686f3dafc37SManish Narani clk_data->clk_phase_in[host->timing]); 687f3dafc37SManish Narani clk_set_phase(clk_data->sdcardclk, 688f3dafc37SManish Narani clk_data->clk_phase_out[host->timing]); 689f3dafc37SManish Narani } 690f3dafc37SManish Narani 691f3dafc37SManish Narani static void arasan_dt_read_clk_phase(struct device *dev, 692f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data, 693f3dafc37SManish Narani unsigned int timing, const char *prop) 694f3dafc37SManish Narani { 695f3dafc37SManish Narani struct device_node *np = dev->of_node; 696f3dafc37SManish Narani 697f3dafc37SManish Narani int clk_phase[2] = {0}; 698f3dafc37SManish Narani 699f3dafc37SManish Narani /* 700f3dafc37SManish Narani * Read Tap Delay values from DT, if the DT does not contain the 701f3dafc37SManish Narani * Tap Values then use the pre-defined values. 702f3dafc37SManish Narani */ 703f3dafc37SManish Narani if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], 704f3dafc37SManish Narani 2, 0)) { 705f3dafc37SManish Narani dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", 706f3dafc37SManish Narani prop, clk_data->clk_phase_in[timing], 707f3dafc37SManish Narani clk_data->clk_phase_out[timing]); 708f3dafc37SManish Narani return; 709f3dafc37SManish Narani } 710f3dafc37SManish Narani 711f3dafc37SManish Narani /* The values read are Input and Output Clock Delays in order */ 712f3dafc37SManish Narani clk_data->clk_phase_in[timing] = clk_phase[0]; 713f3dafc37SManish Narani clk_data->clk_phase_out[timing] = clk_phase[1]; 714f3dafc37SManish Narani } 715f3dafc37SManish Narani 716f3dafc37SManish Narani /** 717f3dafc37SManish Narani * arasan_dt_parse_clk_phases - Read Clock Delay values from DT 718f3dafc37SManish Narani * 719f3dafc37SManish Narani * Called at initialization to parse the values of Clock Delays. 720f3dafc37SManish Narani * 721f3dafc37SManish Narani * @dev: Pointer to our struct device. 722f3dafc37SManish Narani * @clk_data: Pointer to the Clock Data structure 723f3dafc37SManish Narani */ 724f3dafc37SManish Narani static void arasan_dt_parse_clk_phases(struct device *dev, 725f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data) 726f3dafc37SManish Narani { 727f3dafc37SManish Narani /* 728f3dafc37SManish Narani * This has been kept as a pointer and is assigned a function here. 729f3dafc37SManish Narani * So that different controller variants can assign their own handling 730f3dafc37SManish Narani * function. 731f3dafc37SManish Narani */ 732f3dafc37SManish Narani clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; 733f3dafc37SManish Narani 734f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, 735f3dafc37SManish Narani "clk-phase-legacy"); 736f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, 737f3dafc37SManish Narani "clk-phase-mmc-hs"); 738f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, 739f3dafc37SManish Narani "clk-phase-sd-hs"); 740f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, 741f3dafc37SManish Narani "clk-phase-uhs-sdr12"); 742f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, 743f3dafc37SManish Narani "clk-phase-uhs-sdr25"); 744f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, 745f3dafc37SManish Narani "clk-phase-uhs-sdr50"); 746f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, 747f3dafc37SManish Narani "clk-phase-uhs-sdr104"); 748f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, 749f3dafc37SManish Narani "clk-phase-uhs-ddr50"); 750f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, 751f3dafc37SManish Narani "clk-phase-mmc-ddr52"); 752f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, 753f3dafc37SManish Narani "clk-phase-mmc-hs200"); 754f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, 755f3dafc37SManish Narani "clk-phase-mmc-hs400"); 756f3dafc37SManish Narani } 757f3dafc37SManish Narani 758c390f211SDouglas Anderson /** 75907a14d1dSManish Narani * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use 760c390f211SDouglas Anderson * 761c390f211SDouglas Anderson * Some PHY devices need to know what the actual card clock is. In order for 762c390f211SDouglas Anderson * them to find out, we'll provide a clock through the common clock framework 763c390f211SDouglas Anderson * for them to query. 764c390f211SDouglas Anderson * 765c390f211SDouglas Anderson * @sdhci_arasan: Our private data structure. 766c390f211SDouglas Anderson * @clk_xin: Pointer to the functional clock 767c390f211SDouglas Anderson * @dev: Pointer to our struct device. 768c390f211SDouglas Anderson * Returns 0 on success and error value on error 769c390f211SDouglas Anderson */ 77007a14d1dSManish Narani static int 77107a14d1dSManish Narani sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, 772c390f211SDouglas Anderson struct clk *clk_xin, 773c390f211SDouglas Anderson struct device *dev) 774c390f211SDouglas Anderson { 775e1463618SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 776c390f211SDouglas Anderson struct device_node *np = dev->of_node; 777c390f211SDouglas Anderson struct clk_init_data sdcardclk_init; 778c390f211SDouglas Anderson const char *parent_clk_name; 779c390f211SDouglas Anderson int ret; 780c390f211SDouglas Anderson 781c390f211SDouglas Anderson ret = of_property_read_string_index(np, "clock-output-names", 0, 782c390f211SDouglas Anderson &sdcardclk_init.name); 783c390f211SDouglas Anderson if (ret) { 784c390f211SDouglas Anderson dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 785c390f211SDouglas Anderson return ret; 786c390f211SDouglas Anderson } 787c390f211SDouglas Anderson 788c390f211SDouglas Anderson parent_clk_name = __clk_get_name(clk_xin); 789c390f211SDouglas Anderson sdcardclk_init.parent_names = &parent_clk_name; 790c390f211SDouglas Anderson sdcardclk_init.num_parents = 1; 791c390f211SDouglas Anderson sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; 792c390f211SDouglas Anderson sdcardclk_init.ops = &arasan_sdcardclk_ops; 793c390f211SDouglas Anderson 794e1463618SManish Narani clk_data->sdcardclk_hw.init = &sdcardclk_init; 795e1463618SManish Narani clk_data->sdcardclk = 796e1463618SManish Narani devm_clk_register(dev, &clk_data->sdcardclk_hw); 797e1463618SManish Narani clk_data->sdcardclk_hw.init = NULL; 798c390f211SDouglas Anderson 799c390f211SDouglas Anderson ret = of_clk_add_provider(np, of_clk_src_simple_get, 800e1463618SManish Narani clk_data->sdcardclk); 801c390f211SDouglas Anderson if (ret) 80207a14d1dSManish Narani dev_err(dev, "Failed to add sdcard clock provider\n"); 80307a14d1dSManish Narani 80407a14d1dSManish Narani return ret; 80507a14d1dSManish Narani } 80607a14d1dSManish Narani 80707a14d1dSManish Narani /** 80807a14d1dSManish Narani * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use 80907a14d1dSManish Narani * 81007a14d1dSManish Narani * Some PHY devices need to know what the actual card clock is. In order for 81107a14d1dSManish Narani * them to find out, we'll provide a clock through the common clock framework 81207a14d1dSManish Narani * for them to query. 81307a14d1dSManish Narani * 81407a14d1dSManish Narani * @sdhci_arasan: Our private data structure. 81507a14d1dSManish Narani * @clk_xin: Pointer to the functional clock 81607a14d1dSManish Narani * @dev: Pointer to our struct device. 81707a14d1dSManish Narani * Returns 0 on success and error value on error 81807a14d1dSManish Narani */ 81907a14d1dSManish Narani static int 82007a14d1dSManish Narani sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, 82107a14d1dSManish Narani struct clk *clk_xin, 82207a14d1dSManish Narani struct device *dev) 82307a14d1dSManish Narani { 82407a14d1dSManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 82507a14d1dSManish Narani struct device_node *np = dev->of_node; 82607a14d1dSManish Narani struct clk_init_data sampleclk_init; 82707a14d1dSManish Narani const char *parent_clk_name; 82807a14d1dSManish Narani int ret; 82907a14d1dSManish Narani 83007a14d1dSManish Narani ret = of_property_read_string_index(np, "clock-output-names", 1, 83107a14d1dSManish Narani &sampleclk_init.name); 83207a14d1dSManish Narani if (ret) { 83307a14d1dSManish Narani dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 83407a14d1dSManish Narani return ret; 83507a14d1dSManish Narani } 83607a14d1dSManish Narani 83707a14d1dSManish Narani parent_clk_name = __clk_get_name(clk_xin); 83807a14d1dSManish Narani sampleclk_init.parent_names = &parent_clk_name; 83907a14d1dSManish Narani sampleclk_init.num_parents = 1; 84007a14d1dSManish Narani sampleclk_init.flags = CLK_GET_RATE_NOCACHE; 84107a14d1dSManish Narani sampleclk_init.ops = &arasan_sampleclk_ops; 84207a14d1dSManish Narani 84307a14d1dSManish Narani clk_data->sampleclk_hw.init = &sampleclk_init; 84407a14d1dSManish Narani clk_data->sampleclk = 84507a14d1dSManish Narani devm_clk_register(dev, &clk_data->sampleclk_hw); 84607a14d1dSManish Narani clk_data->sampleclk_hw.init = NULL; 84707a14d1dSManish Narani 84807a14d1dSManish Narani ret = of_clk_add_provider(np, of_clk_src_simple_get, 84907a14d1dSManish Narani clk_data->sampleclk); 85007a14d1dSManish Narani if (ret) 85107a14d1dSManish Narani dev_err(dev, "Failed to add sample clock provider\n"); 852c390f211SDouglas Anderson 853c390f211SDouglas Anderson return ret; 854c390f211SDouglas Anderson } 855c390f211SDouglas Anderson 856c390f211SDouglas Anderson /** 857c390f211SDouglas Anderson * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() 858c390f211SDouglas Anderson * 859c390f211SDouglas Anderson * Should be called any time we're exiting and sdhci_arasan_register_sdclk() 860c390f211SDouglas Anderson * returned success. 861c390f211SDouglas Anderson * 862c390f211SDouglas Anderson * @dev: Pointer to our struct device. 863c390f211SDouglas Anderson */ 864c390f211SDouglas Anderson static void sdhci_arasan_unregister_sdclk(struct device *dev) 865c390f211SDouglas Anderson { 866c390f211SDouglas Anderson struct device_node *np = dev->of_node; 867c390f211SDouglas Anderson 868c390f211SDouglas Anderson if (!of_find_property(np, "#clock-cells", NULL)) 869c390f211SDouglas Anderson return; 870c390f211SDouglas Anderson 871c390f211SDouglas Anderson of_clk_del_provider(dev->of_node); 872c390f211SDouglas Anderson } 873c390f211SDouglas Anderson 87407a14d1dSManish Narani /** 87507a14d1dSManish Narani * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use 87607a14d1dSManish Narani * 87707a14d1dSManish Narani * Some PHY devices need to know what the actual card clock is. In order for 87807a14d1dSManish Narani * them to find out, we'll provide a clock through the common clock framework 87907a14d1dSManish Narani * for them to query. 88007a14d1dSManish Narani * 88107a14d1dSManish Narani * Note: without seriously re-architecting SDHCI's clock code and testing on 88207a14d1dSManish Narani * all platforms, there's no way to create a totally beautiful clock here 88307a14d1dSManish Narani * with all clock ops implemented. Instead, we'll just create a clock that can 88407a14d1dSManish Narani * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock 88507a14d1dSManish Narani * framework that we're doing things behind its back. This should be sufficient 88607a14d1dSManish Narani * to create nice clean device tree bindings and later (if needed) we can try 88707a14d1dSManish Narani * re-architecting SDHCI if we see some benefit to it. 88807a14d1dSManish Narani * 88907a14d1dSManish Narani * @sdhci_arasan: Our private data structure. 89007a14d1dSManish Narani * @clk_xin: Pointer to the functional clock 89107a14d1dSManish Narani * @dev: Pointer to our struct device. 89207a14d1dSManish Narani * Returns 0 on success and error value on error 89307a14d1dSManish Narani */ 89407a14d1dSManish Narani static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, 89507a14d1dSManish Narani struct clk *clk_xin, 89607a14d1dSManish Narani struct device *dev) 89707a14d1dSManish Narani { 89807a14d1dSManish Narani struct device_node *np = dev->of_node; 89907a14d1dSManish Narani u32 num_clks = 0; 90007a14d1dSManish Narani int ret; 90107a14d1dSManish Narani 90207a14d1dSManish Narani /* Providing a clock to the PHY is optional; no error if missing */ 90307a14d1dSManish Narani if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0) 90407a14d1dSManish Narani return 0; 90507a14d1dSManish Narani 90607a14d1dSManish Narani ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev); 90707a14d1dSManish Narani if (ret) 90807a14d1dSManish Narani return ret; 90907a14d1dSManish Narani 91007a14d1dSManish Narani if (num_clks) { 91107a14d1dSManish Narani ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin, 91207a14d1dSManish Narani dev); 91307a14d1dSManish Narani if (ret) { 91407a14d1dSManish Narani sdhci_arasan_unregister_sdclk(dev); 91507a14d1dSManish Narani return ret; 91607a14d1dSManish Narani } 91707a14d1dSManish Narani } 91807a14d1dSManish Narani 91907a14d1dSManish Narani return 0; 92007a14d1dSManish Narani } 92107a14d1dSManish Narani 92284362d79SShawn Lin static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan) 92384362d79SShawn Lin { 92484362d79SShawn Lin struct sdhci_host *host = sdhci_arasan->host; 92584362d79SShawn Lin struct cqhci_host *cq_host; 92684362d79SShawn Lin bool dma64; 92784362d79SShawn Lin int ret; 92884362d79SShawn Lin 92984362d79SShawn Lin if (!sdhci_arasan->has_cqe) 93084362d79SShawn Lin return sdhci_add_host(host); 93184362d79SShawn Lin 93284362d79SShawn Lin ret = sdhci_setup_host(host); 93384362d79SShawn Lin if (ret) 93484362d79SShawn Lin return ret; 93584362d79SShawn Lin 93684362d79SShawn Lin cq_host = devm_kzalloc(host->mmc->parent, 93784362d79SShawn Lin sizeof(*cq_host), GFP_KERNEL); 93884362d79SShawn Lin if (!cq_host) { 93984362d79SShawn Lin ret = -ENOMEM; 94084362d79SShawn Lin goto cleanup; 94184362d79SShawn Lin } 94284362d79SShawn Lin 94384362d79SShawn Lin cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR; 94484362d79SShawn Lin cq_host->ops = &sdhci_arasan_cqhci_ops; 94584362d79SShawn Lin 94684362d79SShawn Lin dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 94784362d79SShawn Lin if (dma64) 94884362d79SShawn Lin cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 94984362d79SShawn Lin 95084362d79SShawn Lin ret = cqhci_init(cq_host, host->mmc, dma64); 95184362d79SShawn Lin if (ret) 95284362d79SShawn Lin goto cleanup; 95384362d79SShawn Lin 95484362d79SShawn Lin ret = __sdhci_add_host(host); 95584362d79SShawn Lin if (ret) 95684362d79SShawn Lin goto cleanup; 95784362d79SShawn Lin 95884362d79SShawn Lin return 0; 95984362d79SShawn Lin 96084362d79SShawn Lin cleanup: 96184362d79SShawn Lin sdhci_cleanup_host(host); 96284362d79SShawn Lin return ret; 96384362d79SShawn Lin } 96484362d79SShawn Lin 965e3ec3a3dSSoren Brinkmann static int sdhci_arasan_probe(struct platform_device *pdev) 966e3ec3a3dSSoren Brinkmann { 967e3ec3a3dSSoren Brinkmann int ret; 9683ea4666eSDouglas Anderson const struct of_device_id *match; 9693ea4666eSDouglas Anderson struct device_node *node; 970e3ec3a3dSSoren Brinkmann struct clk *clk_xin; 971e3ec3a3dSSoren Brinkmann struct sdhci_host *host; 972e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host; 973e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data *sdhci_arasan; 9743794c542SZach Brown struct device_node *np = pdev->dev.of_node; 97506b23ca0SFaiz Abbas const struct sdhci_arasan_of_data *data; 976e3ec3a3dSSoren Brinkmann 97706b23ca0SFaiz Abbas match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node); 97806b23ca0SFaiz Abbas data = match->data; 97906b23ca0SFaiz Abbas host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan)); 98084362d79SShawn Lin 98189211418SJisheng Zhang if (IS_ERR(host)) 98289211418SJisheng Zhang return PTR_ERR(host); 98389211418SJisheng Zhang 98489211418SJisheng Zhang pltfm_host = sdhci_priv(host); 98589211418SJisheng Zhang sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 986c390f211SDouglas Anderson sdhci_arasan->host = host; 987e3ec3a3dSSoren Brinkmann 98806b23ca0SFaiz Abbas sdhci_arasan->soc_ctl_map = data->soc_ctl_map; 9893ea4666eSDouglas Anderson 9903ea4666eSDouglas Anderson node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0); 9913ea4666eSDouglas Anderson if (node) { 9923ea4666eSDouglas Anderson sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node); 9933ea4666eSDouglas Anderson of_node_put(node); 9943ea4666eSDouglas Anderson 9953ea4666eSDouglas Anderson if (IS_ERR(sdhci_arasan->soc_ctl_base)) { 9963ea4666eSDouglas Anderson ret = PTR_ERR(sdhci_arasan->soc_ctl_base); 9973ea4666eSDouglas Anderson if (ret != -EPROBE_DEFER) 9983ea4666eSDouglas Anderson dev_err(&pdev->dev, "Can't get syscon: %d\n", 9993ea4666eSDouglas Anderson ret); 10003ea4666eSDouglas Anderson goto err_pltfm_free; 10013ea4666eSDouglas Anderson } 10023ea4666eSDouglas Anderson } 10033ea4666eSDouglas Anderson 1004e3ec3a3dSSoren Brinkmann sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); 1005e3ec3a3dSSoren Brinkmann if (IS_ERR(sdhci_arasan->clk_ahb)) { 1006e3ec3a3dSSoren Brinkmann dev_err(&pdev->dev, "clk_ahb clock not found.\n"); 1007278d0962SShawn Lin ret = PTR_ERR(sdhci_arasan->clk_ahb); 1008278d0962SShawn Lin goto err_pltfm_free; 1009e3ec3a3dSSoren Brinkmann } 1010e3ec3a3dSSoren Brinkmann 1011e3ec3a3dSSoren Brinkmann clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); 1012e3ec3a3dSSoren Brinkmann if (IS_ERR(clk_xin)) { 1013e3ec3a3dSSoren Brinkmann dev_err(&pdev->dev, "clk_xin clock not found.\n"); 1014278d0962SShawn Lin ret = PTR_ERR(clk_xin); 1015278d0962SShawn Lin goto err_pltfm_free; 1016e3ec3a3dSSoren Brinkmann } 1017e3ec3a3dSSoren Brinkmann 1018e3ec3a3dSSoren Brinkmann ret = clk_prepare_enable(sdhci_arasan->clk_ahb); 1019e3ec3a3dSSoren Brinkmann if (ret) { 1020e3ec3a3dSSoren Brinkmann dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); 1021278d0962SShawn Lin goto err_pltfm_free; 1022e3ec3a3dSSoren Brinkmann } 1023e3ec3a3dSSoren Brinkmann 1024e3ec3a3dSSoren Brinkmann ret = clk_prepare_enable(clk_xin); 1025e3ec3a3dSSoren Brinkmann if (ret) { 1026e3ec3a3dSSoren Brinkmann dev_err(&pdev->dev, "Unable to enable SD clock.\n"); 1027e3ec3a3dSSoren Brinkmann goto clk_dis_ahb; 1028e3ec3a3dSSoren Brinkmann } 1029e3ec3a3dSSoren Brinkmann 1030e3ec3a3dSSoren Brinkmann sdhci_get_of_property(pdev); 10313794c542SZach Brown 10323794c542SZach Brown if (of_property_read_bool(np, "xlnx,fails-without-test-cd")) 10333794c542SZach Brown sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST; 10343794c542SZach Brown 10353f2c7d5dSHelmut Grohne if (of_property_read_bool(np, "xlnx,int-clock-stable-broken")) 10363f2c7d5dSHelmut Grohne sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE; 10373f2c7d5dSHelmut Grohne 1038e3ec3a3dSSoren Brinkmann pltfm_host->clk = clk_xin; 1039e3ec3a3dSSoren Brinkmann 1040b2ca77c9SShawn Lin if (of_device_is_compatible(pdev->dev.of_node, 1041b2ca77c9SShawn Lin "rockchip,rk3399-sdhci-5.1")) 1042b2ca77c9SShawn Lin sdhci_arasan_update_clockmultiplier(host, 0x0); 1043b2ca77c9SShawn Lin 10443ea4666eSDouglas Anderson sdhci_arasan_update_baseclkfreq(host); 10453ea4666eSDouglas Anderson 1046c390f211SDouglas Anderson ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev); 1047c390f211SDouglas Anderson if (ret) 1048c390f211SDouglas Anderson goto clk_disable_all; 1049c390f211SDouglas Anderson 1050f3dafc37SManish Narani arasan_dt_parse_clk_phases(&pdev->dev, &sdhci_arasan->clk_data); 1051f3dafc37SManish Narani 105216b23787SMichal Simek ret = mmc_of_parse(host->mmc); 105316b23787SMichal Simek if (ret) { 105460208a26SMichal Simek if (ret != -EPROBE_DEFER) 1055940e698cSShubhrajyoti Datta dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret); 1056c390f211SDouglas Anderson goto unreg_clk; 105716b23787SMichal Simek } 105816b23787SMichal Simek 105991aa3661SShawn Lin sdhci_arasan->phy = ERR_PTR(-ENODEV); 106091aa3661SShawn Lin if (of_device_is_compatible(pdev->dev.of_node, 106191aa3661SShawn Lin "arasan,sdhci-5.1")) { 106291aa3661SShawn Lin sdhci_arasan->phy = devm_phy_get(&pdev->dev, 106391aa3661SShawn Lin "phy_arasan"); 106491aa3661SShawn Lin if (IS_ERR(sdhci_arasan->phy)) { 106591aa3661SShawn Lin ret = PTR_ERR(sdhci_arasan->phy); 106691aa3661SShawn Lin dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n"); 1067c390f211SDouglas Anderson goto unreg_clk; 106891aa3661SShawn Lin } 106991aa3661SShawn Lin 107091aa3661SShawn Lin ret = phy_init(sdhci_arasan->phy); 107191aa3661SShawn Lin if (ret < 0) { 107291aa3661SShawn Lin dev_err(&pdev->dev, "phy_init err.\n"); 1073c390f211SDouglas Anderson goto unreg_clk; 107491aa3661SShawn Lin } 107591aa3661SShawn Lin 1076a05c8465SShawn Lin host->mmc_host_ops.hs400_enhanced_strobe = 1077a05c8465SShawn Lin sdhci_arasan_hs400_enhanced_strobe; 10788a3bee9bSShawn Lin host->mmc_host_ops.start_signal_voltage_switch = 10798a3bee9bSShawn Lin sdhci_arasan_voltage_switch; 108084362d79SShawn Lin sdhci_arasan->has_cqe = true; 10817bda9482SChristoph Muellner host->mmc->caps2 |= MMC_CAP2_CQE; 10827bda9482SChristoph Muellner 10837bda9482SChristoph Muellner if (!of_property_read_bool(np, "disable-cqe-dcmd")) 10847bda9482SChristoph Muellner host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; 108591aa3661SShawn Lin } 108691aa3661SShawn Lin 108784362d79SShawn Lin ret = sdhci_arasan_add_host(sdhci_arasan); 1088b1df9de7SMike Looijmans if (ret) 108991aa3661SShawn Lin goto err_add_host; 1090e3ec3a3dSSoren Brinkmann 1091e3ec3a3dSSoren Brinkmann return 0; 1092e3ec3a3dSSoren Brinkmann 109391aa3661SShawn Lin err_add_host: 109491aa3661SShawn Lin if (!IS_ERR(sdhci_arasan->phy)) 109591aa3661SShawn Lin phy_exit(sdhci_arasan->phy); 1096c390f211SDouglas Anderson unreg_clk: 1097c390f211SDouglas Anderson sdhci_arasan_unregister_sdclk(&pdev->dev); 1098e3ec3a3dSSoren Brinkmann clk_disable_all: 1099e3ec3a3dSSoren Brinkmann clk_disable_unprepare(clk_xin); 1100e3ec3a3dSSoren Brinkmann clk_dis_ahb: 1101e3ec3a3dSSoren Brinkmann clk_disable_unprepare(sdhci_arasan->clk_ahb); 1102278d0962SShawn Lin err_pltfm_free: 1103278d0962SShawn Lin sdhci_pltfm_free(pdev); 1104e3ec3a3dSSoren Brinkmann return ret; 1105e3ec3a3dSSoren Brinkmann } 1106e3ec3a3dSSoren Brinkmann 1107e3ec3a3dSSoren Brinkmann static int sdhci_arasan_remove(struct platform_device *pdev) 1108e3ec3a3dSSoren Brinkmann { 11090c7fe32eSJisheng Zhang int ret; 1110e3ec3a3dSSoren Brinkmann struct sdhci_host *host = platform_get_drvdata(pdev); 1111e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 111289211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 111389211418SJisheng Zhang struct clk *clk_ahb = sdhci_arasan->clk_ahb; 1114e3ec3a3dSSoren Brinkmann 111591aa3661SShawn Lin if (!IS_ERR(sdhci_arasan->phy)) { 1116b2db9c67SDouglas Anderson if (sdhci_arasan->is_phy_on) 111791aa3661SShawn Lin phy_power_off(sdhci_arasan->phy); 111891aa3661SShawn Lin phy_exit(sdhci_arasan->phy); 111991aa3661SShawn Lin } 112091aa3661SShawn Lin 1121c390f211SDouglas Anderson sdhci_arasan_unregister_sdclk(&pdev->dev); 1122c390f211SDouglas Anderson 11230c7fe32eSJisheng Zhang ret = sdhci_pltfm_unregister(pdev); 11240c7fe32eSJisheng Zhang 112589211418SJisheng Zhang clk_disable_unprepare(clk_ahb); 1126e3ec3a3dSSoren Brinkmann 11270c7fe32eSJisheng Zhang return ret; 1128e3ec3a3dSSoren Brinkmann } 1129e3ec3a3dSSoren Brinkmann 1130e3ec3a3dSSoren Brinkmann static struct platform_driver sdhci_arasan_driver = { 1131e3ec3a3dSSoren Brinkmann .driver = { 1132e3ec3a3dSSoren Brinkmann .name = "sdhci-arasan", 1133e3ec3a3dSSoren Brinkmann .of_match_table = sdhci_arasan_of_match, 1134e3ec3a3dSSoren Brinkmann .pm = &sdhci_arasan_dev_pm_ops, 1135e3ec3a3dSSoren Brinkmann }, 1136e3ec3a3dSSoren Brinkmann .probe = sdhci_arasan_probe, 1137e3ec3a3dSSoren Brinkmann .remove = sdhci_arasan_remove, 1138e3ec3a3dSSoren Brinkmann }; 1139e3ec3a3dSSoren Brinkmann 1140e3ec3a3dSSoren Brinkmann module_platform_driver(sdhci_arasan_driver); 1141e3ec3a3dSSoren Brinkmann 1142e3ec3a3dSSoren Brinkmann MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller"); 1143e3ec3a3dSSoren Brinkmann MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>"); 1144e3ec3a3dSSoren Brinkmann MODULE_LICENSE("GPL"); 1145