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> 25a5c8b2aeSManish Narani #include <linux/firmware/xlnx-zynqmp.h> 26e3ec3a3dSSoren Brinkmann 2784362d79SShawn Lin #include "cqhci.h" 2884362d79SShawn Lin #include "sdhci-pltfm.h" 29e3ec3a3dSSoren Brinkmann 3084362d79SShawn Lin #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 311a470721SManish Narani 321a470721SManish Narani #define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 33d338c6d0SManish Narani #define SDHCI_ARASAN_ITAPDLY_SEL_MASK 0xFF 34d338c6d0SManish Narani 351a470721SManish Narani #define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC 36d338c6d0SManish Narani #define SDHCI_ARASAN_OTAPDLY_SEL_MASK 0x3F 371a470721SManish Narani 3884362d79SShawn Lin #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 39a05c8465SShawn Lin #define VENDOR_ENHANCED_STROBE BIT(0) 40e3ec3a3dSSoren Brinkmann 41b2db9c67SDouglas Anderson #define PHY_CLK_TOO_SLOW_HZ 400000 42b2db9c67SDouglas Anderson 431a470721SManish Narani #define SDHCI_ITAPDLY_CHGWIN 0x200 441a470721SManish Narani #define SDHCI_ITAPDLY_ENABLE 0x100 451a470721SManish Narani #define SDHCI_OTAPDLY_ENABLE 0x40 461a470721SManish Narani 47a5c8b2aeSManish Narani /* Default settings for ZynqMP Clock Phases */ 48a5c8b2aeSManish Narani #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} 49a5c8b2aeSManish Narani #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} 50a5c8b2aeSManish Narani 511a470721SManish Narani #define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0} 521a470721SManish Narani #define VERSAL_OCLK_PHASE {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0} 531a470721SManish Narani 543ea4666eSDouglas Anderson /* 553ea4666eSDouglas Anderson * On some SoCs the syscon area has a feature where the upper 16-bits of 563ea4666eSDouglas Anderson * each 32-bit register act as a write mask for the lower 16-bits. This allows 573ea4666eSDouglas Anderson * atomic updates of the register without locking. This macro is used on SoCs 583ea4666eSDouglas Anderson * that have that feature. 593ea4666eSDouglas Anderson */ 603ea4666eSDouglas Anderson #define HIWORD_UPDATE(val, mask, shift) \ 613ea4666eSDouglas Anderson ((val) << (shift) | (mask) << ((shift) + 16)) 623ea4666eSDouglas Anderson 633ea4666eSDouglas Anderson /** 643ea4666eSDouglas Anderson * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map 653ea4666eSDouglas Anderson * 663ea4666eSDouglas Anderson * @reg: Offset within the syscon of the register containing this field 673ea4666eSDouglas Anderson * @width: Number of bits for this field 683ea4666eSDouglas Anderson * @shift: Bit offset within @reg of this field (or -1 if not avail) 693ea4666eSDouglas Anderson */ 703ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field { 713ea4666eSDouglas Anderson u32 reg; 723ea4666eSDouglas Anderson u16 width; 733ea4666eSDouglas Anderson s16 shift; 743ea4666eSDouglas Anderson }; 753ea4666eSDouglas Anderson 763ea4666eSDouglas Anderson /** 773ea4666eSDouglas Anderson * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers 783ea4666eSDouglas Anderson * 793ea4666eSDouglas Anderson * @baseclkfreq: Where to find corecfg_baseclkfreq 80b2ca77c9SShawn Lin * @clockmultiplier: Where to find corecfg_clockmultiplier 8136c6aadaSWan Ahmad Zainie * @support64b: Where to find SUPPORT64B bit 823ea4666eSDouglas Anderson * @hiword_update: If true, use HIWORD_UPDATE to access the syscon 834908460eSManish Narani * 844908460eSManish Narani * It's up to the licensee of the Arsan IP block to make these available 854908460eSManish Narani * somewhere if needed. Presumably these will be scattered somewhere that's 864908460eSManish Narani * accessible via the syscon API. 873ea4666eSDouglas Anderson */ 883ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_map { 893ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field baseclkfreq; 90b2ca77c9SShawn Lin struct sdhci_arasan_soc_ctl_field clockmultiplier; 9136c6aadaSWan Ahmad Zainie struct sdhci_arasan_soc_ctl_field support64b; 923ea4666eSDouglas Anderson bool hiword_update; 933ea4666eSDouglas Anderson }; 943ea4666eSDouglas Anderson 95e3ec3a3dSSoren Brinkmann /** 9616ada730SManish Narani * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller 9716ada730SManish Narani * 9816ada730SManish Narani * @sdcardclk_ops: The output clock related operations 9916ada730SManish Narani * @sampleclk_ops: The sample clock related operations 10016ada730SManish Narani */ 10116ada730SManish Narani struct sdhci_arasan_clk_ops { 10216ada730SManish Narani const struct clk_ops *sdcardclk_ops; 10316ada730SManish Narani const struct clk_ops *sampleclk_ops; 10416ada730SManish Narani }; 10516ada730SManish Narani 10616ada730SManish Narani /** 1074908460eSManish Narani * struct sdhci_arasan_clk_data - Arasan Controller Clock Data. 1084908460eSManish Narani * 109e1463618SManish Narani * @sdcardclk_hw: Struct for the clock we might provide to a PHY. 110e1463618SManish Narani * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. 11107a14d1dSManish Narani * @sampleclk_hw: Struct for the clock we might provide to a PHY. 11207a14d1dSManish Narani * @sampleclk: Pointer to normal 'struct clock' for sampleclk_hw. 113f3dafc37SManish Narani * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes 114f3dafc37SManish Narani * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes 115f3dafc37SManish Narani * @set_clk_delays: Function pointer for setting Clock Delays 116a5c8b2aeSManish Narani * @clk_of_data: Platform specific runtime clock data storage pointer 117e1463618SManish Narani */ 118e1463618SManish Narani struct sdhci_arasan_clk_data { 119e1463618SManish Narani struct clk_hw sdcardclk_hw; 120e1463618SManish Narani struct clk *sdcardclk; 12107a14d1dSManish Narani struct clk_hw sampleclk_hw; 12207a14d1dSManish Narani struct clk *sampleclk; 123f3dafc37SManish Narani int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; 124f3dafc37SManish Narani int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; 125f3dafc37SManish Narani void (*set_clk_delays)(struct sdhci_host *host); 126a5c8b2aeSManish Narani void *clk_of_data; 127a5c8b2aeSManish Narani }; 128a5c8b2aeSManish Narani 129e1463618SManish Narani /** 1304908460eSManish Narani * struct sdhci_arasan_data - Arasan Controller Data 1314908460eSManish Narani * 132c390f211SDouglas Anderson * @host: Pointer to the main SDHCI host structure. 133e3ec3a3dSSoren Brinkmann * @clk_ahb: Pointer to the AHB clock 13491aa3661SShawn Lin * @phy: Pointer to the generic phy 135b2db9c67SDouglas Anderson * @is_phy_on: True if the PHY is on; false if not. 1364908460eSManish Narani * @has_cqe: True if controller has command queuing engine. 137e1463618SManish Narani * @clk_data: Struct for the Arasan Controller Clock Data. 13816ada730SManish Narani * @clk_ops: Struct for the Arasan Controller Clock Operations. 1393ea4666eSDouglas Anderson * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. 1403ea4666eSDouglas Anderson * @soc_ctl_map: Map to get offsets into soc_ctl registers. 1414908460eSManish Narani * @quirks: Arasan deviations from spec. 142e3ec3a3dSSoren Brinkmann */ 143e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data { 144c390f211SDouglas Anderson struct sdhci_host *host; 145e3ec3a3dSSoren Brinkmann struct clk *clk_ahb; 14691aa3661SShawn Lin struct phy *phy; 147b2db9c67SDouglas Anderson bool is_phy_on; 1483ea4666eSDouglas Anderson 14984362d79SShawn Lin bool has_cqe; 150e1463618SManish Narani struct sdhci_arasan_clk_data clk_data; 15116ada730SManish Narani const struct sdhci_arasan_clk_ops *clk_ops; 152c390f211SDouglas Anderson 1533ea4666eSDouglas Anderson struct regmap *soc_ctl_base; 1543ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 1554908460eSManish Narani unsigned int quirks; 1563794c542SZach Brown 1573794c542SZach Brown /* Controller does not have CD wired and will not function normally without */ 1583794c542SZach Brown #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0) 1593f2c7d5dSHelmut Grohne /* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the 1603f2c7d5dSHelmut Grohne * internal clock even when the clock isn't stable */ 1613f2c7d5dSHelmut Grohne #define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1) 162e3ec3a3dSSoren Brinkmann }; 163e3ec3a3dSSoren Brinkmann 16406b23ca0SFaiz Abbas struct sdhci_arasan_of_data { 16506b23ca0SFaiz Abbas const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 16606b23ca0SFaiz Abbas const struct sdhci_pltfm_data *pdata; 16716ada730SManish Narani const struct sdhci_arasan_clk_ops *clk_ops; 16806b23ca0SFaiz Abbas }; 16906b23ca0SFaiz Abbas 1703ea4666eSDouglas Anderson static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { 1713ea4666eSDouglas Anderson .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 }, 172b2ca77c9SShawn Lin .clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0}, 1733ea4666eSDouglas Anderson .hiword_update = true, 1743ea4666eSDouglas Anderson }; 1753ea4666eSDouglas Anderson 1765c1a4f40SRamuthevar Vadivel Muruganx static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = { 1775c1a4f40SRamuthevar Vadivel Muruganx .baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 }, 1785c1a4f40SRamuthevar Vadivel Muruganx .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 1795c1a4f40SRamuthevar Vadivel Muruganx .hiword_update = false, 1805c1a4f40SRamuthevar Vadivel Muruganx }; 1815c1a4f40SRamuthevar Vadivel Muruganx 182d1807ad6SRamuthevar Vadivel Murugan static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { 183d1807ad6SRamuthevar Vadivel Murugan .baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 }, 184d1807ad6SRamuthevar Vadivel Murugan .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 185d1807ad6SRamuthevar Vadivel Murugan .hiword_update = false, 186d1807ad6SRamuthevar Vadivel Murugan }; 187d1807ad6SRamuthevar Vadivel Murugan 18836c6aadaSWan Ahmad Zainie static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { 18936c6aadaSWan Ahmad Zainie .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, 19036c6aadaSWan Ahmad Zainie .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, 19136c6aadaSWan Ahmad Zainie .support64b = { .reg = 0x4, .width = 1, .shift = 24 }, 19236c6aadaSWan Ahmad Zainie .hiword_update = false, 19336c6aadaSWan Ahmad Zainie }; 19436c6aadaSWan Ahmad Zainie 1953ea4666eSDouglas Anderson /** 1963ea4666eSDouglas Anderson * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers 1973ea4666eSDouglas Anderson * 1984908460eSManish Narani * @host: The sdhci_host 1994908460eSManish Narani * @fld: The field to write to 2004908460eSManish Narani * @val: The value to write 2014908460eSManish Narani * 2023ea4666eSDouglas Anderson * This function allows writing to fields in sdhci_arasan_soc_ctl_map. 2033ea4666eSDouglas Anderson * Note that if a field is specified as not available (shift < 0) then 2043ea4666eSDouglas Anderson * this function will silently return an error code. It will be noisy 2053ea4666eSDouglas Anderson * and print errors for any other (unexpected) errors. 2063ea4666eSDouglas Anderson * 2074908460eSManish Narani * Return: 0 on success and error value on error 2083ea4666eSDouglas Anderson */ 2093ea4666eSDouglas Anderson static int sdhci_arasan_syscon_write(struct sdhci_host *host, 2103ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_field *fld, 2113ea4666eSDouglas Anderson u32 val) 2123ea4666eSDouglas Anderson { 2133ea4666eSDouglas Anderson struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2143ea4666eSDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 2153ea4666eSDouglas Anderson struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base; 2163ea4666eSDouglas Anderson u32 reg = fld->reg; 2173ea4666eSDouglas Anderson u16 width = fld->width; 2183ea4666eSDouglas Anderson s16 shift = fld->shift; 2193ea4666eSDouglas Anderson int ret; 2203ea4666eSDouglas Anderson 2213ea4666eSDouglas Anderson /* 2223ea4666eSDouglas Anderson * Silently return errors for shift < 0 so caller doesn't have 2233ea4666eSDouglas Anderson * to check for fields which are optional. For fields that 2243ea4666eSDouglas Anderson * are required then caller needs to do something special 2253ea4666eSDouglas Anderson * anyway. 2263ea4666eSDouglas Anderson */ 2273ea4666eSDouglas Anderson if (shift < 0) 2283ea4666eSDouglas Anderson return -EINVAL; 2293ea4666eSDouglas Anderson 2303ea4666eSDouglas Anderson if (sdhci_arasan->soc_ctl_map->hiword_update) 2313ea4666eSDouglas Anderson ret = regmap_write(soc_ctl_base, reg, 2323ea4666eSDouglas Anderson HIWORD_UPDATE(val, GENMASK(width, 0), 2333ea4666eSDouglas Anderson shift)); 2343ea4666eSDouglas Anderson else 2353ea4666eSDouglas Anderson ret = regmap_update_bits(soc_ctl_base, reg, 2363ea4666eSDouglas Anderson GENMASK(shift + width, shift), 2373ea4666eSDouglas Anderson val << shift); 2383ea4666eSDouglas Anderson 2393ea4666eSDouglas Anderson /* Yell about (unexpected) regmap errors */ 2403ea4666eSDouglas Anderson if (ret) 2413ea4666eSDouglas Anderson pr_warn("%s: Regmap write fail: %d\n", 2423ea4666eSDouglas Anderson mmc_hostname(host->mmc), ret); 2433ea4666eSDouglas Anderson 2443ea4666eSDouglas Anderson return ret; 2453ea4666eSDouglas Anderson } 2463ea4666eSDouglas Anderson 247802ac39aSShawn Lin static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) 248802ac39aSShawn Lin { 249802ac39aSShawn Lin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 250802ac39aSShawn Lin struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 251f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 2526fc09244SDouglas Anderson bool ctrl_phy = false; 253802ac39aSShawn Lin 254b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy)) { 255b2db9c67SDouglas Anderson if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) { 256b2db9c67SDouglas Anderson /* 257b2db9c67SDouglas Anderson * If PHY off, set clock to max speed and power PHY on. 258b2db9c67SDouglas Anderson * 259b2db9c67SDouglas Anderson * Although PHY docs apparently suggest power cycling 260b2db9c67SDouglas Anderson * when changing the clock the PHY doesn't like to be 261b2db9c67SDouglas Anderson * powered on while at low speeds like those used in ID 262b2db9c67SDouglas Anderson * mode. Even worse is powering the PHY on while the 263b2db9c67SDouglas Anderson * clock is off. 264b2db9c67SDouglas Anderson * 265b2db9c67SDouglas Anderson * To workaround the PHY limitations, the best we can 266b2db9c67SDouglas Anderson * do is to power it on at a faster speed and then slam 267b2db9c67SDouglas Anderson * through low speeds without power cycling. 268b2db9c67SDouglas Anderson */ 269b2db9c67SDouglas Anderson sdhci_set_clock(host, host->max_clk); 270b2db9c67SDouglas Anderson phy_power_on(sdhci_arasan->phy); 271b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 272802ac39aSShawn Lin 273b2db9c67SDouglas Anderson /* 274b2db9c67SDouglas Anderson * We'll now fall through to the below case with 275b2db9c67SDouglas Anderson * ctrl_phy = false (so we won't turn off/on). The 276b2db9c67SDouglas Anderson * sdhci_set_clock() will set the real clock. 277b2db9c67SDouglas Anderson */ 278b2db9c67SDouglas Anderson } else if (clock > PHY_CLK_TOO_SLOW_HZ) { 279b2db9c67SDouglas Anderson /* 280b2db9c67SDouglas Anderson * At higher clock speeds the PHY is fine being power 281b2db9c67SDouglas Anderson * cycled and docs say you _should_ power cycle when 282b2db9c67SDouglas Anderson * changing clock speeds. 283b2db9c67SDouglas Anderson */ 284b2db9c67SDouglas Anderson ctrl_phy = true; 285b2db9c67SDouglas Anderson } 286b2db9c67SDouglas Anderson } 287b2db9c67SDouglas Anderson 288b2db9c67SDouglas Anderson if (ctrl_phy && sdhci_arasan->is_phy_on) { 289802ac39aSShawn Lin phy_power_off(sdhci_arasan->phy); 290b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = false; 291802ac39aSShawn Lin } 292802ac39aSShawn Lin 293f3dafc37SManish Narani /* Set the Input and Output Clock Phase Delays */ 294f3dafc37SManish Narani if (clk_data->set_clk_delays) 295f3dafc37SManish Narani clk_data->set_clk_delays(host); 296f3dafc37SManish Narani 297802ac39aSShawn Lin sdhci_set_clock(host, clock); 298802ac39aSShawn Lin 2993f2c7d5dSHelmut Grohne if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE) 3003f2c7d5dSHelmut Grohne /* 3013f2c7d5dSHelmut Grohne * Some controllers immediately report SDHCI_CLOCK_INT_STABLE 3023f2c7d5dSHelmut Grohne * after enabling the clock even though the clock is not 3033f2c7d5dSHelmut Grohne * stable. Trying to use a clock without waiting here results 3043f2c7d5dSHelmut Grohne * in EILSEQ while detecting some older/slower cards. The 3053f2c7d5dSHelmut Grohne * chosen delay is the maximum delay from sdhci_set_clock. 3063f2c7d5dSHelmut Grohne */ 3073f2c7d5dSHelmut Grohne msleep(20); 3083f2c7d5dSHelmut Grohne 3096fc09244SDouglas Anderson if (ctrl_phy) { 310802ac39aSShawn Lin phy_power_on(sdhci_arasan->phy); 311b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 312802ac39aSShawn Lin } 313802ac39aSShawn Lin } 314802ac39aSShawn Lin 315a05c8465SShawn Lin static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, 316a05c8465SShawn Lin struct mmc_ios *ios) 317a05c8465SShawn Lin { 318a05c8465SShawn Lin u32 vendor; 319a05c8465SShawn Lin struct sdhci_host *host = mmc_priv(mmc); 320a05c8465SShawn Lin 3210daf72feSJean-Francois Dagenais vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER); 322a05c8465SShawn Lin if (ios->enhanced_strobe) 323a05c8465SShawn Lin vendor |= VENDOR_ENHANCED_STROBE; 324a05c8465SShawn Lin else 325a05c8465SShawn Lin vendor &= ~VENDOR_ENHANCED_STROBE; 326a05c8465SShawn Lin 3270daf72feSJean-Francois Dagenais sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER); 328a05c8465SShawn Lin } 329a05c8465SShawn Lin 33013d62fd2SWei Yongjun static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) 3313794c542SZach Brown { 3323794c542SZach Brown u8 ctrl; 3333794c542SZach Brown struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3343794c542SZach Brown struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 3353794c542SZach Brown 3363794c542SZach Brown sdhci_reset(host, mask); 3373794c542SZach Brown 3383794c542SZach Brown if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) { 3393794c542SZach Brown ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 3403794c542SZach Brown ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN; 3413794c542SZach Brown sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 3423794c542SZach Brown } 3433794c542SZach Brown } 3443794c542SZach Brown 3458a3bee9bSShawn Lin static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, 3468a3bee9bSShawn Lin struct mmc_ios *ios) 3478a3bee9bSShawn Lin { 3488a3bee9bSShawn Lin switch (ios->signal_voltage) { 3498a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_180: 3508a3bee9bSShawn Lin /* 3518a3bee9bSShawn Lin * Plese don't switch to 1V8 as arasan,5.1 doesn't 3528a3bee9bSShawn Lin * actually refer to this setting to indicate the 3538a3bee9bSShawn Lin * signal voltage and the state machine will be broken 3548a3bee9bSShawn Lin * actually if we force to enable 1V8. That's something 3558a3bee9bSShawn Lin * like broken quirk but we could work around here. 3568a3bee9bSShawn Lin */ 3578a3bee9bSShawn Lin return 0; 3588a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_330: 3598a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_120: 3608a3bee9bSShawn Lin /* We don't support 3V3 and 1V2 */ 3618a3bee9bSShawn Lin break; 3628a3bee9bSShawn Lin } 3638a3bee9bSShawn Lin 3648a3bee9bSShawn Lin return -EINVAL; 3658a3bee9bSShawn Lin } 3668a3bee9bSShawn Lin 367a81dae3aSJulia Lawall static const struct sdhci_ops sdhci_arasan_ops = { 368802ac39aSShawn Lin .set_clock = sdhci_arasan_set_clock, 369e3ec3a3dSSoren Brinkmann .get_max_clock = sdhci_pltfm_clk_get_max_clock, 3708cc35289SShawn Lin .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 3712317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 3723794c542SZach Brown .reset = sdhci_arasan_reset, 37396d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 374c2c5252cSNicolas Saenz Julienne .set_power = sdhci_set_power_and_bus_voltage, 375e3ec3a3dSSoren Brinkmann }; 376e3ec3a3dSSoren Brinkmann 37784362d79SShawn Lin static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) 37884362d79SShawn Lin { 37984362d79SShawn Lin int cmd_error = 0; 38084362d79SShawn Lin int data_error = 0; 38184362d79SShawn Lin 38284362d79SShawn Lin if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 38384362d79SShawn Lin return intmask; 38484362d79SShawn Lin 38584362d79SShawn Lin cqhci_irq(host->mmc, intmask, cmd_error, data_error); 38684362d79SShawn Lin 38784362d79SShawn Lin return 0; 38884362d79SShawn Lin } 38984362d79SShawn Lin 39084362d79SShawn Lin static void sdhci_arasan_dumpregs(struct mmc_host *mmc) 39184362d79SShawn Lin { 39284362d79SShawn Lin sdhci_dumpregs(mmc_priv(mmc)); 39384362d79SShawn Lin } 39484362d79SShawn Lin 39584362d79SShawn Lin static void sdhci_arasan_cqe_enable(struct mmc_host *mmc) 39684362d79SShawn Lin { 39784362d79SShawn Lin struct sdhci_host *host = mmc_priv(mmc); 39884362d79SShawn Lin u32 reg; 39984362d79SShawn Lin 40084362d79SShawn Lin reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 40184362d79SShawn Lin while (reg & SDHCI_DATA_AVAILABLE) { 40284362d79SShawn Lin sdhci_readl(host, SDHCI_BUFFER); 40384362d79SShawn Lin reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 40484362d79SShawn Lin } 40584362d79SShawn Lin 40684362d79SShawn Lin sdhci_cqe_enable(mmc); 40784362d79SShawn Lin } 40884362d79SShawn Lin 40984362d79SShawn Lin static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = { 41084362d79SShawn Lin .enable = sdhci_arasan_cqe_enable, 41184362d79SShawn Lin .disable = sdhci_cqe_disable, 41284362d79SShawn Lin .dumpregs = sdhci_arasan_dumpregs, 41384362d79SShawn Lin }; 41484362d79SShawn Lin 41584362d79SShawn Lin static const struct sdhci_ops sdhci_arasan_cqe_ops = { 41684362d79SShawn Lin .set_clock = sdhci_arasan_set_clock, 41784362d79SShawn Lin .get_max_clock = sdhci_pltfm_clk_get_max_clock, 41884362d79SShawn Lin .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 41984362d79SShawn Lin .set_bus_width = sdhci_set_bus_width, 42084362d79SShawn Lin .reset = sdhci_arasan_reset, 42184362d79SShawn Lin .set_uhs_signaling = sdhci_set_uhs_signaling, 422c2c5252cSNicolas Saenz Julienne .set_power = sdhci_set_power_and_bus_voltage, 42384362d79SShawn Lin .irq = sdhci_arasan_cqhci_irq, 42484362d79SShawn Lin }; 42584362d79SShawn Lin 42684362d79SShawn Lin static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { 42784362d79SShawn Lin .ops = &sdhci_arasan_cqe_ops, 42884362d79SShawn Lin .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 42984362d79SShawn Lin .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 43084362d79SShawn Lin SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, 43184362d79SShawn Lin }; 43284362d79SShawn Lin 433e3ec3a3dSSoren Brinkmann #ifdef CONFIG_PM_SLEEP 434e3ec3a3dSSoren Brinkmann /** 435e3ec3a3dSSoren Brinkmann * sdhci_arasan_suspend - Suspend method for the driver 436e3ec3a3dSSoren Brinkmann * @dev: Address of the device structure 437e3ec3a3dSSoren Brinkmann * 438e3ec3a3dSSoren Brinkmann * Put the device in a low power state. 4394908460eSManish Narani * 4404908460eSManish Narani * Return: 0 on success and error value on error 441e3ec3a3dSSoren Brinkmann */ 442e3ec3a3dSSoren Brinkmann static int sdhci_arasan_suspend(struct device *dev) 443e3ec3a3dSSoren Brinkmann { 444970f2d90SWolfram Sang struct sdhci_host *host = dev_get_drvdata(dev); 445e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 44689211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 447e3ec3a3dSSoren Brinkmann int ret; 448e3ec3a3dSSoren Brinkmann 449d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 450d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 451d38dcad4SAdrian Hunter 45284362d79SShawn Lin if (sdhci_arasan->has_cqe) { 45384362d79SShawn Lin ret = cqhci_suspend(host->mmc); 45484362d79SShawn Lin if (ret) 45584362d79SShawn Lin return ret; 45684362d79SShawn Lin } 45784362d79SShawn Lin 458e3ec3a3dSSoren Brinkmann ret = sdhci_suspend_host(host); 459e3ec3a3dSSoren Brinkmann if (ret) 460e3ec3a3dSSoren Brinkmann return ret; 461e3ec3a3dSSoren Brinkmann 462b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) { 46391aa3661SShawn Lin ret = phy_power_off(sdhci_arasan->phy); 46491aa3661SShawn Lin if (ret) { 46591aa3661SShawn Lin dev_err(dev, "Cannot power off phy.\n"); 46691aa3661SShawn Lin sdhci_resume_host(host); 46791aa3661SShawn Lin return ret; 46891aa3661SShawn Lin } 469b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = false; 47091aa3661SShawn Lin } 47191aa3661SShawn Lin 472e3ec3a3dSSoren Brinkmann clk_disable(pltfm_host->clk); 473e3ec3a3dSSoren Brinkmann clk_disable(sdhci_arasan->clk_ahb); 474e3ec3a3dSSoren Brinkmann 475e3ec3a3dSSoren Brinkmann return 0; 476e3ec3a3dSSoren Brinkmann } 477e3ec3a3dSSoren Brinkmann 478e3ec3a3dSSoren Brinkmann /** 479e3ec3a3dSSoren Brinkmann * sdhci_arasan_resume - Resume method for the driver 480e3ec3a3dSSoren Brinkmann * @dev: Address of the device structure 481e3ec3a3dSSoren Brinkmann * 482e3ec3a3dSSoren Brinkmann * Resume operation after suspend 4834908460eSManish Narani * 4844908460eSManish Narani * Return: 0 on success and error value on error 485e3ec3a3dSSoren Brinkmann */ 486e3ec3a3dSSoren Brinkmann static int sdhci_arasan_resume(struct device *dev) 487e3ec3a3dSSoren Brinkmann { 488970f2d90SWolfram Sang struct sdhci_host *host = dev_get_drvdata(dev); 489e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 49089211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 491e3ec3a3dSSoren Brinkmann int ret; 492e3ec3a3dSSoren Brinkmann 493e3ec3a3dSSoren Brinkmann ret = clk_enable(sdhci_arasan->clk_ahb); 494e3ec3a3dSSoren Brinkmann if (ret) { 495e3ec3a3dSSoren Brinkmann dev_err(dev, "Cannot enable AHB clock.\n"); 496e3ec3a3dSSoren Brinkmann return ret; 497e3ec3a3dSSoren Brinkmann } 498e3ec3a3dSSoren Brinkmann 499e3ec3a3dSSoren Brinkmann ret = clk_enable(pltfm_host->clk); 500e3ec3a3dSSoren Brinkmann if (ret) { 501e3ec3a3dSSoren Brinkmann dev_err(dev, "Cannot enable SD clock.\n"); 502e3ec3a3dSSoren Brinkmann return ret; 503e3ec3a3dSSoren Brinkmann } 504e3ec3a3dSSoren Brinkmann 505b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) { 50691aa3661SShawn Lin ret = phy_power_on(sdhci_arasan->phy); 50791aa3661SShawn Lin if (ret) { 50891aa3661SShawn Lin dev_err(dev, "Cannot power on phy.\n"); 50991aa3661SShawn Lin return ret; 51091aa3661SShawn Lin } 511b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 51291aa3661SShawn Lin } 51391aa3661SShawn Lin 51484362d79SShawn Lin ret = sdhci_resume_host(host); 51584362d79SShawn Lin if (ret) { 51684362d79SShawn Lin dev_err(dev, "Cannot resume host.\n"); 51784362d79SShawn Lin return ret; 51884362d79SShawn Lin } 51984362d79SShawn Lin 52084362d79SShawn Lin if (sdhci_arasan->has_cqe) 52184362d79SShawn Lin return cqhci_resume(host->mmc); 52284362d79SShawn Lin 52384362d79SShawn Lin return 0; 524e3ec3a3dSSoren Brinkmann } 525e3ec3a3dSSoren Brinkmann #endif /* ! CONFIG_PM_SLEEP */ 526e3ec3a3dSSoren Brinkmann 527e3ec3a3dSSoren Brinkmann static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, 528e3ec3a3dSSoren Brinkmann sdhci_arasan_resume); 529e3ec3a3dSSoren Brinkmann 5303ea4666eSDouglas Anderson /** 531c390f211SDouglas Anderson * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate 532c390f211SDouglas Anderson * 5334908460eSManish Narani * @hw: Pointer to the hardware clock structure. 5344908460eSManish Narani * @parent_rate: The parent rate (should be rate of clk_xin). 5354908460eSManish Narani * 536c390f211SDouglas Anderson * Return the current actual rate of the SD card clock. This can be used 537c390f211SDouglas Anderson * to communicate with out PHY. 538c390f211SDouglas Anderson * 5394908460eSManish Narani * Return: The card clock rate. 540c390f211SDouglas Anderson */ 541c390f211SDouglas Anderson static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, 542c390f211SDouglas Anderson unsigned long parent_rate) 543c390f211SDouglas Anderson { 544e1463618SManish Narani struct sdhci_arasan_clk_data *clk_data = 545e1463618SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 546c390f211SDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = 547e1463618SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 548c390f211SDouglas Anderson struct sdhci_host *host = sdhci_arasan->host; 549c390f211SDouglas Anderson 550c390f211SDouglas Anderson return host->mmc->actual_clock; 551c390f211SDouglas Anderson } 552c390f211SDouglas Anderson 553c390f211SDouglas Anderson static const struct clk_ops arasan_sdcardclk_ops = { 554c390f211SDouglas Anderson .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 555c390f211SDouglas Anderson }; 556c390f211SDouglas Anderson 557c390f211SDouglas Anderson /** 55807a14d1dSManish Narani * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate 55907a14d1dSManish Narani * 5604908460eSManish Narani * @hw: Pointer to the hardware clock structure. 5614908460eSManish Narani * @parent_rate: The parent rate (should be rate of clk_xin). 5624908460eSManish Narani * 56307a14d1dSManish Narani * Return the current actual rate of the sampling clock. This can be used 56407a14d1dSManish Narani * to communicate with out PHY. 56507a14d1dSManish Narani * 5664908460eSManish Narani * Return: The sample clock rate. 56707a14d1dSManish Narani */ 56807a14d1dSManish Narani static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, 56907a14d1dSManish Narani unsigned long parent_rate) 57007a14d1dSManish Narani { 57107a14d1dSManish Narani struct sdhci_arasan_clk_data *clk_data = 57207a14d1dSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 57307a14d1dSManish Narani struct sdhci_arasan_data *sdhci_arasan = 57407a14d1dSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 57507a14d1dSManish Narani struct sdhci_host *host = sdhci_arasan->host; 57607a14d1dSManish Narani 57707a14d1dSManish Narani return host->mmc->actual_clock; 57807a14d1dSManish Narani } 57907a14d1dSManish Narani 58007a14d1dSManish Narani static const struct clk_ops arasan_sampleclk_ops = { 58107a14d1dSManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 58207a14d1dSManish Narani }; 58307a14d1dSManish Narani 58407a14d1dSManish Narani /** 585a5c8b2aeSManish Narani * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays 586a5c8b2aeSManish Narani * 5874908460eSManish Narani * @hw: Pointer to the hardware clock structure. 5884908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 5894908460eSManish Narani * 590a5c8b2aeSManish Narani * Set the SD Output Clock Tap Delays for Output path 591a5c8b2aeSManish Narani * 592a5c8b2aeSManish Narani * Return: 0 on success and error value on error 593a5c8b2aeSManish Narani */ 594a5c8b2aeSManish Narani static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) 595a5c8b2aeSManish Narani { 596a5c8b2aeSManish Narani struct sdhci_arasan_clk_data *clk_data = 597a5c8b2aeSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 598a5c8b2aeSManish Narani struct sdhci_arasan_data *sdhci_arasan = 599a5c8b2aeSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 600a5c8b2aeSManish Narani struct sdhci_host *host = sdhci_arasan->host; 601a5c8b2aeSManish Narani const char *clk_name = clk_hw_get_name(hw); 602a5c8b2aeSManish Narani u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1; 603a5c8b2aeSManish Narani u8 tap_delay, tap_max = 0; 604a5c8b2aeSManish Narani int ret; 605a5c8b2aeSManish Narani 6069e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 6079e953432SManish Narani if (host->version < SDHCI_SPEC_300) 608a5c8b2aeSManish Narani return 0; 609a5c8b2aeSManish Narani 610a5c8b2aeSManish Narani switch (host->timing) { 611a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS: 612a5c8b2aeSManish Narani case MMC_TIMING_SD_HS: 613a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR25: 614a5c8b2aeSManish Narani case MMC_TIMING_UHS_DDR50: 615a5c8b2aeSManish Narani case MMC_TIMING_MMC_DDR52: 616a5c8b2aeSManish Narani /* For 50MHz clock, 30 Taps are available */ 617a5c8b2aeSManish Narani tap_max = 30; 618a5c8b2aeSManish Narani break; 619a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR50: 620a5c8b2aeSManish Narani /* For 100MHz clock, 15 Taps are available */ 621a5c8b2aeSManish Narani tap_max = 15; 622a5c8b2aeSManish Narani break; 623a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR104: 624a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS200: 625a5c8b2aeSManish Narani /* For 200MHz clock, 8 Taps are available */ 626a5c8b2aeSManish Narani tap_max = 8; 627a3096ec6SGustavo A. R. Silva break; 628a5c8b2aeSManish Narani default: 629a5c8b2aeSManish Narani break; 630a5c8b2aeSManish Narani } 631a5c8b2aeSManish Narani 632a5c8b2aeSManish Narani tap_delay = (degrees * tap_max) / 360; 633a5c8b2aeSManish Narani 634a5c8b2aeSManish Narani /* Set the Clock Phase */ 635426c8d85SRajan Vaja ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay); 636a5c8b2aeSManish Narani if (ret) 637a5c8b2aeSManish Narani pr_err("Error setting Output Tap Delay\n"); 638a5c8b2aeSManish Narani 639d06d60d5SManish Narani /* Release DLL Reset */ 640d06d60d5SManish Narani zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE); 641d06d60d5SManish Narani 642a5c8b2aeSManish Narani return ret; 643a5c8b2aeSManish Narani } 644a5c8b2aeSManish Narani 645a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sdcardclk_ops = { 646a5c8b2aeSManish Narani .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 647a5c8b2aeSManish Narani .set_phase = sdhci_zynqmp_sdcardclk_set_phase, 648a5c8b2aeSManish Narani }; 649a5c8b2aeSManish Narani 650a5c8b2aeSManish Narani /** 651a5c8b2aeSManish Narani * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays 652a5c8b2aeSManish Narani * 6534908460eSManish Narani * @hw: Pointer to the hardware clock structure. 6544908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 6554908460eSManish Narani * 656a5c8b2aeSManish Narani * Set the SD Input Clock Tap Delays for Input path 657a5c8b2aeSManish Narani * 658a5c8b2aeSManish Narani * Return: 0 on success and error value on error 659a5c8b2aeSManish Narani */ 660a5c8b2aeSManish Narani static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) 661a5c8b2aeSManish Narani { 662a5c8b2aeSManish Narani struct sdhci_arasan_clk_data *clk_data = 663a5c8b2aeSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 664a5c8b2aeSManish Narani struct sdhci_arasan_data *sdhci_arasan = 665a5c8b2aeSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 666a5c8b2aeSManish Narani struct sdhci_host *host = sdhci_arasan->host; 667a5c8b2aeSManish Narani const char *clk_name = clk_hw_get_name(hw); 668a5c8b2aeSManish Narani u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1; 669a5c8b2aeSManish Narani u8 tap_delay, tap_max = 0; 670a5c8b2aeSManish Narani int ret; 671a5c8b2aeSManish Narani 6729e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 6739e953432SManish Narani if (host->version < SDHCI_SPEC_300) 674a5c8b2aeSManish Narani return 0; 675a5c8b2aeSManish Narani 676d06d60d5SManish Narani /* Assert DLL Reset */ 677d06d60d5SManish Narani zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT); 678d06d60d5SManish Narani 679a5c8b2aeSManish Narani switch (host->timing) { 680a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS: 681a5c8b2aeSManish Narani case MMC_TIMING_SD_HS: 682a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR25: 683a5c8b2aeSManish Narani case MMC_TIMING_UHS_DDR50: 684a5c8b2aeSManish Narani case MMC_TIMING_MMC_DDR52: 685a5c8b2aeSManish Narani /* For 50MHz clock, 120 Taps are available */ 686a5c8b2aeSManish Narani tap_max = 120; 687a5c8b2aeSManish Narani break; 688a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR50: 689a5c8b2aeSManish Narani /* For 100MHz clock, 60 Taps are available */ 690a5c8b2aeSManish Narani tap_max = 60; 691a5c8b2aeSManish Narani break; 692a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR104: 693a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS200: 694a5c8b2aeSManish Narani /* For 200MHz clock, 30 Taps are available */ 695a5c8b2aeSManish Narani tap_max = 30; 696a3096ec6SGustavo A. R. Silva break; 697a5c8b2aeSManish Narani default: 698a5c8b2aeSManish Narani break; 699a5c8b2aeSManish Narani } 700a5c8b2aeSManish Narani 701a5c8b2aeSManish Narani tap_delay = (degrees * tap_max) / 360; 702a5c8b2aeSManish Narani 703a5c8b2aeSManish Narani /* Set the Clock Phase */ 704426c8d85SRajan Vaja ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay); 705a5c8b2aeSManish Narani if (ret) 706a5c8b2aeSManish Narani pr_err("Error setting Input Tap Delay\n"); 707a5c8b2aeSManish Narani 708a5c8b2aeSManish Narani return ret; 709a5c8b2aeSManish Narani } 710a5c8b2aeSManish Narani 711a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sampleclk_ops = { 712a5c8b2aeSManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 713a5c8b2aeSManish Narani .set_phase = sdhci_zynqmp_sampleclk_set_phase, 714a5c8b2aeSManish Narani }; 715a5c8b2aeSManish Narani 7161a470721SManish Narani /** 7171a470721SManish Narani * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays 7181a470721SManish Narani * 7194908460eSManish Narani * @hw: Pointer to the hardware clock structure. 7204908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 7214908460eSManish Narani * 7221a470721SManish Narani * Set the SD Output Clock Tap Delays for Output path 7231a470721SManish Narani * 7241a470721SManish Narani * Return: 0 on success and error value on error 7251a470721SManish Narani */ 7261a470721SManish Narani static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) 7271a470721SManish Narani { 7281a470721SManish Narani struct sdhci_arasan_clk_data *clk_data = 7291a470721SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 7301a470721SManish Narani struct sdhci_arasan_data *sdhci_arasan = 7311a470721SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 7321a470721SManish Narani struct sdhci_host *host = sdhci_arasan->host; 7331a470721SManish Narani u8 tap_delay, tap_max = 0; 7341a470721SManish Narani 7359e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 7369e953432SManish Narani if (host->version < SDHCI_SPEC_300) 7371a470721SManish Narani return 0; 7381a470721SManish Narani 7391a470721SManish Narani switch (host->timing) { 7401a470721SManish Narani case MMC_TIMING_MMC_HS: 7411a470721SManish Narani case MMC_TIMING_SD_HS: 7421a470721SManish Narani case MMC_TIMING_UHS_SDR25: 7431a470721SManish Narani case MMC_TIMING_UHS_DDR50: 7441a470721SManish Narani case MMC_TIMING_MMC_DDR52: 7451a470721SManish Narani /* For 50MHz clock, 30 Taps are available */ 7461a470721SManish Narani tap_max = 30; 7471a470721SManish Narani break; 7481a470721SManish Narani case MMC_TIMING_UHS_SDR50: 7491a470721SManish Narani /* For 100MHz clock, 15 Taps are available */ 7501a470721SManish Narani tap_max = 15; 7511a470721SManish Narani break; 7521a470721SManish Narani case MMC_TIMING_UHS_SDR104: 7531a470721SManish Narani case MMC_TIMING_MMC_HS200: 7541a470721SManish Narani /* For 200MHz clock, 8 Taps are available */ 7551a470721SManish Narani tap_max = 8; 756a3096ec6SGustavo A. R. Silva break; 7571a470721SManish Narani default: 7581a470721SManish Narani break; 7591a470721SManish Narani } 7601a470721SManish Narani 7611a470721SManish Narani tap_delay = (degrees * tap_max) / 360; 7621a470721SManish Narani 7631a470721SManish Narani /* Set the Clock Phase */ 7641a470721SManish Narani if (tap_delay) { 7651a470721SManish Narani u32 regval; 7661a470721SManish Narani 7671a470721SManish Narani regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER); 7681a470721SManish Narani regval |= SDHCI_OTAPDLY_ENABLE; 7691a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); 770d338c6d0SManish Narani regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK; 7711a470721SManish Narani regval |= tap_delay; 7721a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); 7731a470721SManish Narani } 7741a470721SManish Narani 775098c408bSNathan Chancellor return 0; 7761a470721SManish Narani } 7771a470721SManish Narani 7781a470721SManish Narani static const struct clk_ops versal_sdcardclk_ops = { 7791a470721SManish Narani .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 7801a470721SManish Narani .set_phase = sdhci_versal_sdcardclk_set_phase, 7811a470721SManish Narani }; 7821a470721SManish Narani 7831a470721SManish Narani /** 7841a470721SManish Narani * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays 7851a470721SManish Narani * 7864908460eSManish Narani * @hw: Pointer to the hardware clock structure. 7874908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 7884908460eSManish Narani * 7891a470721SManish Narani * Set the SD Input Clock Tap Delays for Input path 7901a470721SManish Narani * 7911a470721SManish Narani * Return: 0 on success and error value on error 7921a470721SManish Narani */ 7931a470721SManish Narani static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) 7941a470721SManish Narani { 7951a470721SManish Narani struct sdhci_arasan_clk_data *clk_data = 7961a470721SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 7971a470721SManish Narani struct sdhci_arasan_data *sdhci_arasan = 7981a470721SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 7991a470721SManish Narani struct sdhci_host *host = sdhci_arasan->host; 8001a470721SManish Narani u8 tap_delay, tap_max = 0; 8011a470721SManish Narani 8029e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 8039e953432SManish Narani if (host->version < SDHCI_SPEC_300) 8041a470721SManish Narani return 0; 8051a470721SManish Narani 8061a470721SManish Narani switch (host->timing) { 8071a470721SManish Narani case MMC_TIMING_MMC_HS: 8081a470721SManish Narani case MMC_TIMING_SD_HS: 8091a470721SManish Narani case MMC_TIMING_UHS_SDR25: 8101a470721SManish Narani case MMC_TIMING_UHS_DDR50: 8111a470721SManish Narani case MMC_TIMING_MMC_DDR52: 8121a470721SManish Narani /* For 50MHz clock, 120 Taps are available */ 8131a470721SManish Narani tap_max = 120; 8141a470721SManish Narani break; 8151a470721SManish Narani case MMC_TIMING_UHS_SDR50: 8161a470721SManish Narani /* For 100MHz clock, 60 Taps are available */ 8171a470721SManish Narani tap_max = 60; 8181a470721SManish Narani break; 8191a470721SManish Narani case MMC_TIMING_UHS_SDR104: 8201a470721SManish Narani case MMC_TIMING_MMC_HS200: 8211a470721SManish Narani /* For 200MHz clock, 30 Taps are available */ 8221a470721SManish Narani tap_max = 30; 823a3096ec6SGustavo A. R. Silva break; 8241a470721SManish Narani default: 8251a470721SManish Narani break; 8261a470721SManish Narani } 8271a470721SManish Narani 8281a470721SManish Narani tap_delay = (degrees * tap_max) / 360; 8291a470721SManish Narani 8301a470721SManish Narani /* Set the Clock Phase */ 8311a470721SManish Narani if (tap_delay) { 8321a470721SManish Narani u32 regval; 8331a470721SManish Narani 8341a470721SManish Narani regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER); 8351a470721SManish Narani regval |= SDHCI_ITAPDLY_CHGWIN; 8361a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8371a470721SManish Narani regval |= SDHCI_ITAPDLY_ENABLE; 8381a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 839d338c6d0SManish Narani regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK; 8401a470721SManish Narani regval |= tap_delay; 8411a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8421a470721SManish Narani regval &= ~SDHCI_ITAPDLY_CHGWIN; 8431a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8441a470721SManish Narani } 8451a470721SManish Narani 846098c408bSNathan Chancellor return 0; 8471a470721SManish Narani } 8481a470721SManish Narani 8491a470721SManish Narani static const struct clk_ops versal_sampleclk_ops = { 8501a470721SManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 8511a470721SManish Narani .set_phase = sdhci_versal_sampleclk_set_phase, 8521a470721SManish Narani }; 8531a470721SManish Narani 8548d2e3343SManish Narani static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid) 8558d2e3343SManish Narani { 8568d2e3343SManish Narani u16 clk; 8578d2e3343SManish Narani 8588d2e3343SManish Narani clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 8598d2e3343SManish Narani clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); 8608d2e3343SManish Narani sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 8618d2e3343SManish Narani 8628d2e3343SManish Narani /* Issue DLL Reset */ 863426c8d85SRajan Vaja zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE); 8648d2e3343SManish Narani 8658d2e3343SManish Narani clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 8668d2e3343SManish Narani 8678d2e3343SManish Narani sdhci_enable_clk(host, clk); 8688d2e3343SManish Narani } 8698d2e3343SManish Narani 8708d2e3343SManish Narani static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) 8718d2e3343SManish Narani { 8728d2e3343SManish Narani struct sdhci_host *host = mmc_priv(mmc); 8738d2e3343SManish Narani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 8748d2e3343SManish Narani struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 8758d2e3343SManish Narani struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw; 8768d2e3343SManish Narani const char *clk_name = clk_hw_get_name(hw); 8778d2e3343SManish Narani u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : 8788d2e3343SManish Narani NODE_SD_1; 8798d2e3343SManish Narani int err; 8808d2e3343SManish Narani 8818d2e3343SManish Narani arasan_zynqmp_dll_reset(host, device_id); 8828d2e3343SManish Narani 8838d2e3343SManish Narani err = sdhci_execute_tuning(mmc, opcode); 8848d2e3343SManish Narani if (err) 8858d2e3343SManish Narani return err; 8868d2e3343SManish Narani 8878d2e3343SManish Narani arasan_zynqmp_dll_reset(host, device_id); 8888d2e3343SManish Narani 8898d2e3343SManish Narani return 0; 8908d2e3343SManish Narani } 8918d2e3343SManish Narani 892a5c8b2aeSManish Narani /** 893b2ca77c9SShawn Lin * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier 894b2ca77c9SShawn Lin * 8954908460eSManish Narani * @host: The sdhci_host 8964908460eSManish Narani * @value: The value to write 8974908460eSManish Narani * 898b2ca77c9SShawn Lin * The corecfg_clockmultiplier is supposed to contain clock multiplier 899b2ca77c9SShawn Lin * value of programmable clock generator. 900b2ca77c9SShawn Lin * 901b2ca77c9SShawn Lin * NOTES: 902b2ca77c9SShawn Lin * - Many existing devices don't seem to do this and work fine. To keep 903b2ca77c9SShawn Lin * compatibility for old hardware where the device tree doesn't provide a 904b2ca77c9SShawn Lin * register map, this function is a noop if a soc_ctl_map hasn't been provided 905b2ca77c9SShawn Lin * for this platform. 906b2ca77c9SShawn Lin * - The value of corecfg_clockmultiplier should sync with that of corresponding 907b2ca77c9SShawn Lin * value reading from sdhci_capability_register. So this function is called 908b2ca77c9SShawn Lin * once at probe time and never called again. 909b2ca77c9SShawn Lin */ 910b2ca77c9SShawn Lin static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, 911b2ca77c9SShawn Lin u32 value) 912b2ca77c9SShawn Lin { 913b2ca77c9SShawn Lin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 914b2ca77c9SShawn Lin struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 915b2ca77c9SShawn Lin const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 916b2ca77c9SShawn Lin sdhci_arasan->soc_ctl_map; 917b2ca77c9SShawn Lin 918b2ca77c9SShawn Lin /* Having a map is optional */ 919b2ca77c9SShawn Lin if (!soc_ctl_map) 920b2ca77c9SShawn Lin return; 921b2ca77c9SShawn Lin 922b2ca77c9SShawn Lin /* If we have a map, we expect to have a syscon */ 923b2ca77c9SShawn Lin if (!sdhci_arasan->soc_ctl_base) { 924b2ca77c9SShawn Lin pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 925b2ca77c9SShawn Lin mmc_hostname(host->mmc)); 926b2ca77c9SShawn Lin return; 927b2ca77c9SShawn Lin } 928b2ca77c9SShawn Lin 929b2ca77c9SShawn Lin sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value); 930b2ca77c9SShawn Lin } 931b2ca77c9SShawn Lin 932b2ca77c9SShawn Lin /** 9333ea4666eSDouglas Anderson * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq 9343ea4666eSDouglas Anderson * 9354908460eSManish Narani * @host: The sdhci_host 9364908460eSManish Narani * 9373ea4666eSDouglas Anderson * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This 9383ea4666eSDouglas Anderson * function can be used to make that happen. 9393ea4666eSDouglas Anderson * 9403ea4666eSDouglas Anderson * NOTES: 9413ea4666eSDouglas Anderson * - Many existing devices don't seem to do this and work fine. To keep 9423ea4666eSDouglas Anderson * compatibility for old hardware where the device tree doesn't provide a 9433ea4666eSDouglas Anderson * register map, this function is a noop if a soc_ctl_map hasn't been provided 9443ea4666eSDouglas Anderson * for this platform. 9453ea4666eSDouglas Anderson * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider 9463ea4666eSDouglas Anderson * to achieve lower clock rates. That means that this function is called once 9473ea4666eSDouglas Anderson * at probe time and never called again. 9483ea4666eSDouglas Anderson */ 9493ea4666eSDouglas Anderson static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) 9503ea4666eSDouglas Anderson { 9513ea4666eSDouglas Anderson struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9523ea4666eSDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 9533ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 9543ea4666eSDouglas Anderson sdhci_arasan->soc_ctl_map; 9553ea4666eSDouglas Anderson u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000); 9563ea4666eSDouglas Anderson 9573ea4666eSDouglas Anderson /* Having a map is optional */ 9583ea4666eSDouglas Anderson if (!soc_ctl_map) 9593ea4666eSDouglas Anderson return; 9603ea4666eSDouglas Anderson 9613ea4666eSDouglas Anderson /* If we have a map, we expect to have a syscon */ 9623ea4666eSDouglas Anderson if (!sdhci_arasan->soc_ctl_base) { 9633ea4666eSDouglas Anderson pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 9643ea4666eSDouglas Anderson mmc_hostname(host->mmc)); 9653ea4666eSDouglas Anderson return; 9663ea4666eSDouglas Anderson } 9673ea4666eSDouglas Anderson 9683ea4666eSDouglas Anderson sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz); 9693ea4666eSDouglas Anderson } 9703ea4666eSDouglas Anderson 971f3dafc37SManish Narani static void sdhci_arasan_set_clk_delays(struct sdhci_host *host) 972f3dafc37SManish Narani { 973f3dafc37SManish Narani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 974f3dafc37SManish Narani struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 975f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 976f3dafc37SManish Narani 977f3dafc37SManish Narani clk_set_phase(clk_data->sampleclk, 978f3dafc37SManish Narani clk_data->clk_phase_in[host->timing]); 979f3dafc37SManish Narani clk_set_phase(clk_data->sdcardclk, 980f3dafc37SManish Narani clk_data->clk_phase_out[host->timing]); 981f3dafc37SManish Narani } 982f3dafc37SManish Narani 983f3dafc37SManish Narani static void arasan_dt_read_clk_phase(struct device *dev, 984f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data, 985f3dafc37SManish Narani unsigned int timing, const char *prop) 986f3dafc37SManish Narani { 987f3dafc37SManish Narani struct device_node *np = dev->of_node; 988f3dafc37SManish Narani 989f3dafc37SManish Narani int clk_phase[2] = {0}; 990f3dafc37SManish Narani 991f3dafc37SManish Narani /* 992f3dafc37SManish Narani * Read Tap Delay values from DT, if the DT does not contain the 993f3dafc37SManish Narani * Tap Values then use the pre-defined values. 994f3dafc37SManish Narani */ 995f3dafc37SManish Narani if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], 996f3dafc37SManish Narani 2, 0)) { 997f3dafc37SManish Narani dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", 998f3dafc37SManish Narani prop, clk_data->clk_phase_in[timing], 999f3dafc37SManish Narani clk_data->clk_phase_out[timing]); 1000f3dafc37SManish Narani return; 1001f3dafc37SManish Narani } 1002f3dafc37SManish Narani 1003f3dafc37SManish Narani /* The values read are Input and Output Clock Delays in order */ 1004f3dafc37SManish Narani clk_data->clk_phase_in[timing] = clk_phase[0]; 1005f3dafc37SManish Narani clk_data->clk_phase_out[timing] = clk_phase[1]; 1006f3dafc37SManish Narani } 1007f3dafc37SManish Narani 1008f3dafc37SManish Narani /** 1009f3dafc37SManish Narani * arasan_dt_parse_clk_phases - Read Clock Delay values from DT 1010f3dafc37SManish Narani * 1011f3dafc37SManish Narani * @dev: Pointer to our struct device. 1012f3dafc37SManish Narani * @clk_data: Pointer to the Clock Data structure 10134908460eSManish Narani * 10144908460eSManish Narani * Called at initialization to parse the values of Clock Delays. 1015f3dafc37SManish Narani */ 1016f3dafc37SManish Narani static void arasan_dt_parse_clk_phases(struct device *dev, 1017f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data) 1018f3dafc37SManish Narani { 1019a5c8b2aeSManish Narani u32 mio_bank = 0; 1020a5c8b2aeSManish Narani int i; 1021a5c8b2aeSManish Narani 1022f3dafc37SManish Narani /* 1023f3dafc37SManish Narani * This has been kept as a pointer and is assigned a function here. 1024f3dafc37SManish Narani * So that different controller variants can assign their own handling 1025f3dafc37SManish Narani * function. 1026f3dafc37SManish Narani */ 1027f3dafc37SManish Narani clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; 1028f3dafc37SManish Narani 1029a5c8b2aeSManish Narani if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { 103088e1d0b1SManish Narani u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = 103188e1d0b1SManish Narani ZYNQMP_ICLK_PHASE; 103288e1d0b1SManish Narani u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = 103388e1d0b1SManish Narani ZYNQMP_OCLK_PHASE; 1034a5c8b2aeSManish Narani 1035a5c8b2aeSManish Narani of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank); 1036a5c8b2aeSManish Narani if (mio_bank == 2) { 103788e1d0b1SManish Narani zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90; 103888e1d0b1SManish Narani zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90; 1039a5c8b2aeSManish Narani } 1040a5c8b2aeSManish Narani 1041a5c8b2aeSManish Narani for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { 104288e1d0b1SManish Narani clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i]; 104388e1d0b1SManish Narani clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i]; 1044a5c8b2aeSManish Narani } 1045a5c8b2aeSManish Narani } 1046a5c8b2aeSManish Narani 10471a470721SManish Narani if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) { 104888e1d0b1SManish Narani u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = 104988e1d0b1SManish Narani VERSAL_ICLK_PHASE; 105088e1d0b1SManish Narani u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = 105188e1d0b1SManish Narani VERSAL_OCLK_PHASE; 10521a470721SManish Narani 10531a470721SManish Narani for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { 105488e1d0b1SManish Narani clk_data->clk_phase_in[i] = versal_iclk_phase[i]; 105588e1d0b1SManish Narani clk_data->clk_phase_out[i] = versal_oclk_phase[i]; 10561a470721SManish Narani } 10571a470721SManish Narani } 10581a470721SManish Narani 1059f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, 1060f3dafc37SManish Narani "clk-phase-legacy"); 1061f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, 1062f3dafc37SManish Narani "clk-phase-mmc-hs"); 1063f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, 1064f3dafc37SManish Narani "clk-phase-sd-hs"); 1065f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, 1066f3dafc37SManish Narani "clk-phase-uhs-sdr12"); 1067f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, 1068f3dafc37SManish Narani "clk-phase-uhs-sdr25"); 1069f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, 1070f3dafc37SManish Narani "clk-phase-uhs-sdr50"); 1071f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, 1072f3dafc37SManish Narani "clk-phase-uhs-sdr104"); 1073f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, 1074f3dafc37SManish Narani "clk-phase-uhs-ddr50"); 1075f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, 1076f3dafc37SManish Narani "clk-phase-mmc-ddr52"); 1077f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, 1078f3dafc37SManish Narani "clk-phase-mmc-hs200"); 1079f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, 1080f3dafc37SManish Narani "clk-phase-mmc-hs400"); 1081f3dafc37SManish Narani } 1082f3dafc37SManish Narani 108337d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_pdata = { 108437d3ee7cSManish Narani .ops = &sdhci_arasan_ops, 108537d3ee7cSManish Narani .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 108637d3ee7cSManish Narani .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 108737d3ee7cSManish Narani SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 108837d3ee7cSManish Narani SDHCI_QUIRK2_STOP_WITH_TC, 108937d3ee7cSManish Narani }; 109037d3ee7cSManish Narani 109116ada730SManish Narani static const struct sdhci_arasan_clk_ops arasan_clk_ops = { 109216ada730SManish Narani .sdcardclk_ops = &arasan_sdcardclk_ops, 109316ada730SManish Narani .sampleclk_ops = &arasan_sampleclk_ops, 109416ada730SManish Narani }; 109516ada730SManish Narani 109637d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { 109737d3ee7cSManish Narani .pdata = &sdhci_arasan_pdata, 109816ada730SManish Narani .clk_ops = &arasan_clk_ops, 109937d3ee7cSManish Narani }; 110037d3ee7cSManish Narani 110136c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { 110236c6aadaSWan Ahmad Zainie .ops = &sdhci_arasan_cqe_ops, 110336c6aadaSWan Ahmad Zainie .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 110436c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 110536c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_LED | 110636c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_ADDR | 110736c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_SIZE | 110836c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_ADMA_SIZE, 110936c6aadaSWan Ahmad Zainie .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 111036c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 111136c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | 111236c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_STOP_WITH_TC | 111336c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 111436c6aadaSWan Ahmad Zainie }; 111536c6aadaSWan Ahmad Zainie 111636c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = { 111736c6aadaSWan Ahmad Zainie .ops = &sdhci_arasan_ops, 111836c6aadaSWan Ahmad Zainie .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 111936c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 112036c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_LED | 112136c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_ADDR | 112236c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_SIZE | 112336c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_ADMA_SIZE, 112436c6aadaSWan Ahmad Zainie .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 112536c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 112636c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | 112736c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_STOP_WITH_TC | 112836c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 112936c6aadaSWan Ahmad Zainie }; 113036c6aadaSWan Ahmad Zainie 113136c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = { 113236c6aadaSWan Ahmad Zainie .ops = &sdhci_arasan_ops, 113336c6aadaSWan Ahmad Zainie .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 113436c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 113536c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_LED | 113636c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_ADDR | 113736c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_SIZE | 113836c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_ADMA_SIZE, 113936c6aadaSWan Ahmad Zainie .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 114036c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 114136c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_HOST_OFF_CARD_ON | 114236c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 114336c6aadaSWan Ahmad Zainie }; 114436c6aadaSWan Ahmad Zainie 114537d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { 114637d3ee7cSManish Narani .soc_ctl_map = &rk3399_soc_ctl_map, 114737d3ee7cSManish Narani .pdata = &sdhci_arasan_cqe_pdata, 114816ada730SManish Narani .clk_ops = &arasan_clk_ops, 114937d3ee7cSManish Narani }; 115037d3ee7cSManish Narani 115137d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_emmc_data = { 115237d3ee7cSManish Narani .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, 115337d3ee7cSManish Narani .pdata = &sdhci_arasan_cqe_pdata, 115416ada730SManish Narani .clk_ops = &arasan_clk_ops, 115537d3ee7cSManish Narani }; 115637d3ee7cSManish Narani 115737d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { 115837d3ee7cSManish Narani .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, 115937d3ee7cSManish Narani .pdata = &sdhci_arasan_cqe_pdata, 116016ada730SManish Narani .clk_ops = &arasan_clk_ops, 116137d3ee7cSManish Narani }; 116237d3ee7cSManish Narani 116337d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { 116437d3ee7cSManish Narani .ops = &sdhci_arasan_ops, 116537d3ee7cSManish Narani .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 116637d3ee7cSManish Narani SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 116737d3ee7cSManish Narani SDHCI_QUIRK2_STOP_WITH_TC, 116837d3ee7cSManish Narani }; 116937d3ee7cSManish Narani 117016ada730SManish Narani static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = { 117116ada730SManish Narani .sdcardclk_ops = &zynqmp_sdcardclk_ops, 117216ada730SManish Narani .sampleclk_ops = &zynqmp_sampleclk_ops, 117316ada730SManish Narani }; 117416ada730SManish Narani 117537d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { 117637d3ee7cSManish Narani .pdata = &sdhci_arasan_zynqmp_pdata, 117716ada730SManish Narani .clk_ops = &zynqmp_clk_ops, 117816ada730SManish Narani }; 117916ada730SManish Narani 118016ada730SManish Narani static const struct sdhci_arasan_clk_ops versal_clk_ops = { 118116ada730SManish Narani .sdcardclk_ops = &versal_sdcardclk_ops, 118216ada730SManish Narani .sampleclk_ops = &versal_sampleclk_ops, 118337d3ee7cSManish Narani }; 118437d3ee7cSManish Narani 118537d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { 118637d3ee7cSManish Narani .pdata = &sdhci_arasan_zynqmp_pdata, 118716ada730SManish Narani .clk_ops = &versal_clk_ops, 118837d3ee7cSManish Narani }; 118937d3ee7cSManish Narani 119036c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_emmc_data = { 119136c6aadaSWan Ahmad Zainie .soc_ctl_map = &intel_keembay_soc_ctl_map, 119236c6aadaSWan Ahmad Zainie .pdata = &sdhci_keembay_emmc_pdata, 1193a42a7ec9SMuhammad Husaini Zulkifli .clk_ops = &arasan_clk_ops, 119436c6aadaSWan Ahmad Zainie }; 119536c6aadaSWan Ahmad Zainie 119636c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sd_data = { 119736c6aadaSWan Ahmad Zainie .soc_ctl_map = &intel_keembay_soc_ctl_map, 119836c6aadaSWan Ahmad Zainie .pdata = &sdhci_keembay_sd_pdata, 1199a42a7ec9SMuhammad Husaini Zulkifli .clk_ops = &arasan_clk_ops, 120036c6aadaSWan Ahmad Zainie }; 120136c6aadaSWan Ahmad Zainie 120236c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sdio_data = { 120336c6aadaSWan Ahmad Zainie .soc_ctl_map = &intel_keembay_soc_ctl_map, 120436c6aadaSWan Ahmad Zainie .pdata = &sdhci_keembay_sdio_pdata, 1205a42a7ec9SMuhammad Husaini Zulkifli .clk_ops = &arasan_clk_ops, 120636c6aadaSWan Ahmad Zainie }; 120736c6aadaSWan Ahmad Zainie 120837d3ee7cSManish Narani static const struct of_device_id sdhci_arasan_of_match[] = { 120937d3ee7cSManish Narani /* SoC-specific compatible strings w/ soc_ctl_map */ 121037d3ee7cSManish Narani { 121137d3ee7cSManish Narani .compatible = "rockchip,rk3399-sdhci-5.1", 121237d3ee7cSManish Narani .data = &sdhci_arasan_rk3399_data, 121337d3ee7cSManish Narani }, 121437d3ee7cSManish Narani { 121537d3ee7cSManish Narani .compatible = "intel,lgm-sdhci-5.1-emmc", 121637d3ee7cSManish Narani .data = &intel_lgm_emmc_data, 121737d3ee7cSManish Narani }, 121837d3ee7cSManish Narani { 121937d3ee7cSManish Narani .compatible = "intel,lgm-sdhci-5.1-sdxc", 122037d3ee7cSManish Narani .data = &intel_lgm_sdxc_data, 122137d3ee7cSManish Narani }, 122236c6aadaSWan Ahmad Zainie { 122336c6aadaSWan Ahmad Zainie .compatible = "intel,keembay-sdhci-5.1-emmc", 122436c6aadaSWan Ahmad Zainie .data = &intel_keembay_emmc_data, 122536c6aadaSWan Ahmad Zainie }, 122636c6aadaSWan Ahmad Zainie { 122736c6aadaSWan Ahmad Zainie .compatible = "intel,keembay-sdhci-5.1-sd", 122836c6aadaSWan Ahmad Zainie .data = &intel_keembay_sd_data, 122936c6aadaSWan Ahmad Zainie }, 123036c6aadaSWan Ahmad Zainie { 123136c6aadaSWan Ahmad Zainie .compatible = "intel,keembay-sdhci-5.1-sdio", 123236c6aadaSWan Ahmad Zainie .data = &intel_keembay_sdio_data, 123336c6aadaSWan Ahmad Zainie }, 123437d3ee7cSManish Narani /* Generic compatible below here */ 123537d3ee7cSManish Narani { 123637d3ee7cSManish Narani .compatible = "arasan,sdhci-8.9a", 123737d3ee7cSManish Narani .data = &sdhci_arasan_generic_data, 123837d3ee7cSManish Narani }, 123937d3ee7cSManish Narani { 124037d3ee7cSManish Narani .compatible = "arasan,sdhci-5.1", 124137d3ee7cSManish Narani .data = &sdhci_arasan_generic_data, 124237d3ee7cSManish Narani }, 124337d3ee7cSManish Narani { 124437d3ee7cSManish Narani .compatible = "arasan,sdhci-4.9a", 124537d3ee7cSManish Narani .data = &sdhci_arasan_generic_data, 124637d3ee7cSManish Narani }, 124737d3ee7cSManish Narani { 124837d3ee7cSManish Narani .compatible = "xlnx,zynqmp-8.9a", 124937d3ee7cSManish Narani .data = &sdhci_arasan_zynqmp_data, 125037d3ee7cSManish Narani }, 125137d3ee7cSManish Narani { 125237d3ee7cSManish Narani .compatible = "xlnx,versal-8.9a", 125337d3ee7cSManish Narani .data = &sdhci_arasan_versal_data, 125437d3ee7cSManish Narani }, 125537d3ee7cSManish Narani { /* sentinel */ } 125637d3ee7cSManish Narani }; 125737d3ee7cSManish Narani MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); 125837d3ee7cSManish Narani 1259c390f211SDouglas Anderson /** 126007a14d1dSManish Narani * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use 1261c390f211SDouglas Anderson * 12624908460eSManish Narani * @sdhci_arasan: Our private data structure. 12634908460eSManish Narani * @clk_xin: Pointer to the functional clock 12644908460eSManish Narani * @dev: Pointer to our struct device. 12654908460eSManish Narani * 1266c390f211SDouglas Anderson * Some PHY devices need to know what the actual card clock is. In order for 1267c390f211SDouglas Anderson * them to find out, we'll provide a clock through the common clock framework 1268c390f211SDouglas Anderson * for them to query. 1269c390f211SDouglas Anderson * 12704908460eSManish Narani * Return: 0 on success and error value on error 1271c390f211SDouglas Anderson */ 127207a14d1dSManish Narani static int 127307a14d1dSManish Narani sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, 1274c390f211SDouglas Anderson struct clk *clk_xin, 1275c390f211SDouglas Anderson struct device *dev) 1276c390f211SDouglas Anderson { 1277e1463618SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 1278c390f211SDouglas Anderson struct device_node *np = dev->of_node; 1279c390f211SDouglas Anderson struct clk_init_data sdcardclk_init; 1280c390f211SDouglas Anderson const char *parent_clk_name; 1281c390f211SDouglas Anderson int ret; 1282c390f211SDouglas Anderson 1283c390f211SDouglas Anderson ret = of_property_read_string_index(np, "clock-output-names", 0, 1284c390f211SDouglas Anderson &sdcardclk_init.name); 1285c390f211SDouglas Anderson if (ret) { 1286c390f211SDouglas Anderson dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 1287c390f211SDouglas Anderson return ret; 1288c390f211SDouglas Anderson } 1289c390f211SDouglas Anderson 1290c390f211SDouglas Anderson parent_clk_name = __clk_get_name(clk_xin); 1291c390f211SDouglas Anderson sdcardclk_init.parent_names = &parent_clk_name; 1292c390f211SDouglas Anderson sdcardclk_init.num_parents = 1; 1293c390f211SDouglas Anderson sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; 129416ada730SManish Narani sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops; 1295c390f211SDouglas Anderson 1296e1463618SManish Narani clk_data->sdcardclk_hw.init = &sdcardclk_init; 1297e1463618SManish Narani clk_data->sdcardclk = 1298e1463618SManish Narani devm_clk_register(dev, &clk_data->sdcardclk_hw); 1299c99e1d0cSChuhong Yuan if (IS_ERR(clk_data->sdcardclk)) 1300c99e1d0cSChuhong Yuan return PTR_ERR(clk_data->sdcardclk); 1301e1463618SManish Narani clk_data->sdcardclk_hw.init = NULL; 1302c390f211SDouglas Anderson 1303c390f211SDouglas Anderson ret = of_clk_add_provider(np, of_clk_src_simple_get, 1304e1463618SManish Narani clk_data->sdcardclk); 1305c390f211SDouglas Anderson if (ret) 130607a14d1dSManish Narani dev_err(dev, "Failed to add sdcard clock provider\n"); 130707a14d1dSManish Narani 130807a14d1dSManish Narani return ret; 130907a14d1dSManish Narani } 131007a14d1dSManish Narani 131107a14d1dSManish Narani /** 131207a14d1dSManish Narani * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use 131307a14d1dSManish Narani * 13144908460eSManish Narani * @sdhci_arasan: Our private data structure. 13154908460eSManish Narani * @clk_xin: Pointer to the functional clock 13164908460eSManish Narani * @dev: Pointer to our struct device. 13174908460eSManish Narani * 131807a14d1dSManish Narani * Some PHY devices need to know what the actual card clock is. In order for 131907a14d1dSManish Narani * them to find out, we'll provide a clock through the common clock framework 132007a14d1dSManish Narani * for them to query. 132107a14d1dSManish Narani * 13224908460eSManish Narani * Return: 0 on success and error value on error 132307a14d1dSManish Narani */ 132407a14d1dSManish Narani static int 132507a14d1dSManish Narani sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, 132607a14d1dSManish Narani struct clk *clk_xin, 132707a14d1dSManish Narani struct device *dev) 132807a14d1dSManish Narani { 132907a14d1dSManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 133007a14d1dSManish Narani struct device_node *np = dev->of_node; 133107a14d1dSManish Narani struct clk_init_data sampleclk_init; 133207a14d1dSManish Narani const char *parent_clk_name; 133307a14d1dSManish Narani int ret; 133407a14d1dSManish Narani 133507a14d1dSManish Narani ret = of_property_read_string_index(np, "clock-output-names", 1, 133607a14d1dSManish Narani &sampleclk_init.name); 133707a14d1dSManish Narani if (ret) { 133807a14d1dSManish Narani dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 133907a14d1dSManish Narani return ret; 134007a14d1dSManish Narani } 134107a14d1dSManish Narani 134207a14d1dSManish Narani parent_clk_name = __clk_get_name(clk_xin); 134307a14d1dSManish Narani sampleclk_init.parent_names = &parent_clk_name; 134407a14d1dSManish Narani sampleclk_init.num_parents = 1; 134507a14d1dSManish Narani sampleclk_init.flags = CLK_GET_RATE_NOCACHE; 134616ada730SManish Narani sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops; 134707a14d1dSManish Narani 134807a14d1dSManish Narani clk_data->sampleclk_hw.init = &sampleclk_init; 134907a14d1dSManish Narani clk_data->sampleclk = 135007a14d1dSManish Narani devm_clk_register(dev, &clk_data->sampleclk_hw); 1351c99e1d0cSChuhong Yuan if (IS_ERR(clk_data->sampleclk)) 1352c99e1d0cSChuhong Yuan return PTR_ERR(clk_data->sampleclk); 135307a14d1dSManish Narani clk_data->sampleclk_hw.init = NULL; 135407a14d1dSManish Narani 135507a14d1dSManish Narani ret = of_clk_add_provider(np, of_clk_src_simple_get, 135607a14d1dSManish Narani clk_data->sampleclk); 135707a14d1dSManish Narani if (ret) 135807a14d1dSManish Narani dev_err(dev, "Failed to add sample clock provider\n"); 1359c390f211SDouglas Anderson 1360c390f211SDouglas Anderson return ret; 1361c390f211SDouglas Anderson } 1362c390f211SDouglas Anderson 1363c390f211SDouglas Anderson /** 1364c390f211SDouglas Anderson * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() 1365c390f211SDouglas Anderson * 13664908460eSManish Narani * @dev: Pointer to our struct device. 13674908460eSManish Narani * 1368c390f211SDouglas Anderson * Should be called any time we're exiting and sdhci_arasan_register_sdclk() 1369c390f211SDouglas Anderson * returned success. 1370c390f211SDouglas Anderson */ 1371c390f211SDouglas Anderson static void sdhci_arasan_unregister_sdclk(struct device *dev) 1372c390f211SDouglas Anderson { 1373c390f211SDouglas Anderson struct device_node *np = dev->of_node; 1374c390f211SDouglas Anderson 1375c390f211SDouglas Anderson if (!of_find_property(np, "#clock-cells", NULL)) 1376c390f211SDouglas Anderson return; 1377c390f211SDouglas Anderson 1378c390f211SDouglas Anderson of_clk_del_provider(dev->of_node); 1379c390f211SDouglas Anderson } 1380c390f211SDouglas Anderson 138107a14d1dSManish Narani /** 138236c6aadaSWan Ahmad Zainie * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support) 1383973c7c99SMuhammad Husaini Zulkifli * @host: The sdhci_host 1384973c7c99SMuhammad Husaini Zulkifli * @value: The value to write 138536c6aadaSWan Ahmad Zainie * 138636c6aadaSWan Ahmad Zainie * This should be set based on the System Address Bus. 138736c6aadaSWan Ahmad Zainie * 0: the Core supports only 32-bit System Address Bus. 138836c6aadaSWan Ahmad Zainie * 1: the Core supports 64-bit System Address Bus. 138936c6aadaSWan Ahmad Zainie * 1390973c7c99SMuhammad Husaini Zulkifli * NOTE: 1391973c7c99SMuhammad Husaini Zulkifli * For Keem Bay, it is required to clear this bit. Its default value is 1'b1. 139236c6aadaSWan Ahmad Zainie * Keem Bay does not support 64-bit access. 139336c6aadaSWan Ahmad Zainie */ 139436c6aadaSWan Ahmad Zainie static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value) 139536c6aadaSWan Ahmad Zainie { 139636c6aadaSWan Ahmad Zainie struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 139736c6aadaSWan Ahmad Zainie struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 1398db845093SMuhammad Husaini Zulkifli const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 139936c6aadaSWan Ahmad Zainie 140036c6aadaSWan Ahmad Zainie /* Having a map is optional */ 1401db845093SMuhammad Husaini Zulkifli soc_ctl_map = sdhci_arasan->soc_ctl_map; 140236c6aadaSWan Ahmad Zainie if (!soc_ctl_map) 140336c6aadaSWan Ahmad Zainie return; 140436c6aadaSWan Ahmad Zainie 140536c6aadaSWan Ahmad Zainie /* If we have a map, we expect to have a syscon */ 140636c6aadaSWan Ahmad Zainie if (!sdhci_arasan->soc_ctl_base) { 140736c6aadaSWan Ahmad Zainie pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 140836c6aadaSWan Ahmad Zainie mmc_hostname(host->mmc)); 140936c6aadaSWan Ahmad Zainie return; 141036c6aadaSWan Ahmad Zainie } 141136c6aadaSWan Ahmad Zainie 141236c6aadaSWan Ahmad Zainie sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value); 141336c6aadaSWan Ahmad Zainie } 141436c6aadaSWan Ahmad Zainie 141536c6aadaSWan Ahmad Zainie /** 141607a14d1dSManish Narani * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use 141707a14d1dSManish Narani * 14184908460eSManish Narani * @sdhci_arasan: Our private data structure. 14194908460eSManish Narani * @clk_xin: Pointer to the functional clock 14204908460eSManish Narani * @dev: Pointer to our struct device. 14214908460eSManish Narani * 142207a14d1dSManish Narani * Some PHY devices need to know what the actual card clock is. In order for 142307a14d1dSManish Narani * them to find out, we'll provide a clock through the common clock framework 142407a14d1dSManish Narani * for them to query. 142507a14d1dSManish Narani * 142607a14d1dSManish Narani * Note: without seriously re-architecting SDHCI's clock code and testing on 142707a14d1dSManish Narani * all platforms, there's no way to create a totally beautiful clock here 142807a14d1dSManish Narani * with all clock ops implemented. Instead, we'll just create a clock that can 142907a14d1dSManish Narani * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock 143007a14d1dSManish Narani * framework that we're doing things behind its back. This should be sufficient 143107a14d1dSManish Narani * to create nice clean device tree bindings and later (if needed) we can try 143207a14d1dSManish Narani * re-architecting SDHCI if we see some benefit to it. 143307a14d1dSManish Narani * 14344908460eSManish Narani * Return: 0 on success and error value on error 143507a14d1dSManish Narani */ 143607a14d1dSManish Narani static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, 143707a14d1dSManish Narani struct clk *clk_xin, 143807a14d1dSManish Narani struct device *dev) 143907a14d1dSManish Narani { 144007a14d1dSManish Narani struct device_node *np = dev->of_node; 144107a14d1dSManish Narani u32 num_clks = 0; 144207a14d1dSManish Narani int ret; 144307a14d1dSManish Narani 144407a14d1dSManish Narani /* Providing a clock to the PHY is optional; no error if missing */ 144507a14d1dSManish Narani if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0) 144607a14d1dSManish Narani return 0; 144707a14d1dSManish Narani 144807a14d1dSManish Narani ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev); 144907a14d1dSManish Narani if (ret) 145007a14d1dSManish Narani return ret; 145107a14d1dSManish Narani 145207a14d1dSManish Narani if (num_clks) { 145307a14d1dSManish Narani ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin, 145407a14d1dSManish Narani dev); 145507a14d1dSManish Narani if (ret) { 145607a14d1dSManish Narani sdhci_arasan_unregister_sdclk(dev); 145707a14d1dSManish Narani return ret; 145807a14d1dSManish Narani } 145907a14d1dSManish Narani } 146007a14d1dSManish Narani 146107a14d1dSManish Narani return 0; 146207a14d1dSManish Narani } 146307a14d1dSManish Narani 146484362d79SShawn Lin static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan) 146584362d79SShawn Lin { 146684362d79SShawn Lin struct sdhci_host *host = sdhci_arasan->host; 146784362d79SShawn Lin struct cqhci_host *cq_host; 146884362d79SShawn Lin bool dma64; 146984362d79SShawn Lin int ret; 147084362d79SShawn Lin 147184362d79SShawn Lin if (!sdhci_arasan->has_cqe) 147284362d79SShawn Lin return sdhci_add_host(host); 147384362d79SShawn Lin 147484362d79SShawn Lin ret = sdhci_setup_host(host); 147584362d79SShawn Lin if (ret) 147684362d79SShawn Lin return ret; 147784362d79SShawn Lin 147884362d79SShawn Lin cq_host = devm_kzalloc(host->mmc->parent, 147984362d79SShawn Lin sizeof(*cq_host), GFP_KERNEL); 148084362d79SShawn Lin if (!cq_host) { 148184362d79SShawn Lin ret = -ENOMEM; 148284362d79SShawn Lin goto cleanup; 148384362d79SShawn Lin } 148484362d79SShawn Lin 148584362d79SShawn Lin cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR; 148684362d79SShawn Lin cq_host->ops = &sdhci_arasan_cqhci_ops; 148784362d79SShawn Lin 148884362d79SShawn Lin dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 148984362d79SShawn Lin if (dma64) 149084362d79SShawn Lin cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 149184362d79SShawn Lin 149284362d79SShawn Lin ret = cqhci_init(cq_host, host->mmc, dma64); 149384362d79SShawn Lin if (ret) 149484362d79SShawn Lin goto cleanup; 149584362d79SShawn Lin 149684362d79SShawn Lin ret = __sdhci_add_host(host); 149784362d79SShawn Lin if (ret) 149884362d79SShawn Lin goto cleanup; 149984362d79SShawn Lin 150084362d79SShawn Lin return 0; 150184362d79SShawn Lin 150284362d79SShawn Lin cleanup: 150384362d79SShawn Lin sdhci_cleanup_host(host); 150484362d79SShawn Lin return ret; 150584362d79SShawn Lin } 150684362d79SShawn Lin 1507e3ec3a3dSSoren Brinkmann static int sdhci_arasan_probe(struct platform_device *pdev) 1508e3ec3a3dSSoren Brinkmann { 1509e3ec3a3dSSoren Brinkmann int ret; 15103ea4666eSDouglas Anderson struct device_node *node; 1511e3ec3a3dSSoren Brinkmann struct clk *clk_xin; 1512e3ec3a3dSSoren Brinkmann struct sdhci_host *host; 1513e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host; 15142ff0b85dSMuhammad Husaini Zulkifli struct device *dev = &pdev->dev; 15152ff0b85dSMuhammad Husaini Zulkifli struct device_node *np = dev->of_node; 1516e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data *sdhci_arasan; 151706b23ca0SFaiz Abbas const struct sdhci_arasan_of_data *data; 1518e3ec3a3dSSoren Brinkmann 15192ff0b85dSMuhammad Husaini Zulkifli data = of_device_get_match_data(dev); 152006b23ca0SFaiz Abbas host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan)); 152184362d79SShawn Lin 152289211418SJisheng Zhang if (IS_ERR(host)) 152389211418SJisheng Zhang return PTR_ERR(host); 152489211418SJisheng Zhang 152589211418SJisheng Zhang pltfm_host = sdhci_priv(host); 152689211418SJisheng Zhang sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 1527c390f211SDouglas Anderson sdhci_arasan->host = host; 1528e3ec3a3dSSoren Brinkmann 152906b23ca0SFaiz Abbas sdhci_arasan->soc_ctl_map = data->soc_ctl_map; 153016ada730SManish Narani sdhci_arasan->clk_ops = data->clk_ops; 15313ea4666eSDouglas Anderson 153280d41efeSMuhammad Husaini Zulkifli node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0); 15333ea4666eSDouglas Anderson if (node) { 15343ea4666eSDouglas Anderson sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node); 15353ea4666eSDouglas Anderson of_node_put(node); 15363ea4666eSDouglas Anderson 15373ea4666eSDouglas Anderson if (IS_ERR(sdhci_arasan->soc_ctl_base)) { 15382ff0b85dSMuhammad Husaini Zulkifli ret = dev_err_probe(dev, 153972ea817dSKrzysztof Kozlowski PTR_ERR(sdhci_arasan->soc_ctl_base), 154072ea817dSKrzysztof Kozlowski "Can't get syscon\n"); 15413ea4666eSDouglas Anderson goto err_pltfm_free; 15423ea4666eSDouglas Anderson } 15433ea4666eSDouglas Anderson } 15443ea4666eSDouglas Anderson 15452ff0b85dSMuhammad Husaini Zulkifli sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb"); 1546e3ec3a3dSSoren Brinkmann if (IS_ERR(sdhci_arasan->clk_ahb)) { 1547*ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb), 1548*ffd68f35SMuhammad Husaini Zulkifli "clk_ahb clock not found.\n"); 1549278d0962SShawn Lin goto err_pltfm_free; 1550e3ec3a3dSSoren Brinkmann } 1551e3ec3a3dSSoren Brinkmann 15522ff0b85dSMuhammad Husaini Zulkifli clk_xin = devm_clk_get(dev, "clk_xin"); 1553e3ec3a3dSSoren Brinkmann if (IS_ERR(clk_xin)) { 1554*ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n"); 1555278d0962SShawn Lin goto err_pltfm_free; 1556e3ec3a3dSSoren Brinkmann } 1557e3ec3a3dSSoren Brinkmann 1558e3ec3a3dSSoren Brinkmann ret = clk_prepare_enable(sdhci_arasan->clk_ahb); 1559e3ec3a3dSSoren Brinkmann if (ret) { 15602ff0b85dSMuhammad Husaini Zulkifli dev_err(dev, "Unable to enable AHB clock.\n"); 1561278d0962SShawn Lin goto err_pltfm_free; 1562e3ec3a3dSSoren Brinkmann } 1563e3ec3a3dSSoren Brinkmann 1564e3ec3a3dSSoren Brinkmann ret = clk_prepare_enable(clk_xin); 1565e3ec3a3dSSoren Brinkmann if (ret) { 15662ff0b85dSMuhammad Husaini Zulkifli dev_err(dev, "Unable to enable SD clock.\n"); 1567e3ec3a3dSSoren Brinkmann goto clk_dis_ahb; 1568e3ec3a3dSSoren Brinkmann } 1569e3ec3a3dSSoren Brinkmann 1570e3ec3a3dSSoren Brinkmann sdhci_get_of_property(pdev); 15713794c542SZach Brown 15723794c542SZach Brown if (of_property_read_bool(np, "xlnx,fails-without-test-cd")) 15733794c542SZach Brown sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST; 15743794c542SZach Brown 15753f2c7d5dSHelmut Grohne if (of_property_read_bool(np, "xlnx,int-clock-stable-broken")) 15763f2c7d5dSHelmut Grohne sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE; 15773f2c7d5dSHelmut Grohne 1578e3ec3a3dSSoren Brinkmann pltfm_host->clk = clk_xin; 1579e3ec3a3dSSoren Brinkmann 158080d41efeSMuhammad Husaini Zulkifli if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1")) 1581b2ca77c9SShawn Lin sdhci_arasan_update_clockmultiplier(host, 0x0); 1582b2ca77c9SShawn Lin 158336c6aadaSWan Ahmad Zainie if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || 158436c6aadaSWan Ahmad Zainie of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || 158536c6aadaSWan Ahmad Zainie of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { 158636c6aadaSWan Ahmad Zainie sdhci_arasan_update_clockmultiplier(host, 0x0); 158736c6aadaSWan Ahmad Zainie sdhci_arasan_update_support64b(host, 0x0); 158836c6aadaSWan Ahmad Zainie 158936c6aadaSWan Ahmad Zainie host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; 159036c6aadaSWan Ahmad Zainie } 159136c6aadaSWan Ahmad Zainie 15923ea4666eSDouglas Anderson sdhci_arasan_update_baseclkfreq(host); 15933ea4666eSDouglas Anderson 15942ff0b85dSMuhammad Husaini Zulkifli ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev); 1595c390f211SDouglas Anderson if (ret) 1596c390f211SDouglas Anderson goto clk_disable_all; 1597c390f211SDouglas Anderson 1598a5c8b2aeSManish Narani if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { 15998d2e3343SManish Narani host->mmc_host_ops.execute_tuning = 16008d2e3343SManish Narani arasan_zynqmp_execute_tuning; 1601a5c8b2aeSManish Narani } 1602a5c8b2aeSManish Narani 16032ff0b85dSMuhammad Husaini Zulkifli arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data); 1604f3dafc37SManish Narani 160516b23787SMichal Simek ret = mmc_of_parse(host->mmc); 160616b23787SMichal Simek if (ret) { 1607*ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, ret, "parsing dt failed.\n"); 1608c390f211SDouglas Anderson goto unreg_clk; 160916b23787SMichal Simek } 161016b23787SMichal Simek 161191aa3661SShawn Lin sdhci_arasan->phy = ERR_PTR(-ENODEV); 161280d41efeSMuhammad Husaini Zulkifli if (of_device_is_compatible(np, "arasan,sdhci-5.1")) { 16132ff0b85dSMuhammad Husaini Zulkifli sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan"); 161491aa3661SShawn Lin if (IS_ERR(sdhci_arasan->phy)) { 1615*ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->phy), 1616*ffd68f35SMuhammad Husaini Zulkifli "No phy for arasan,sdhci-5.1.\n"); 1617c390f211SDouglas Anderson goto unreg_clk; 161891aa3661SShawn Lin } 161991aa3661SShawn Lin 162091aa3661SShawn Lin ret = phy_init(sdhci_arasan->phy); 162191aa3661SShawn Lin if (ret < 0) { 16222ff0b85dSMuhammad Husaini Zulkifli dev_err(dev, "phy_init err.\n"); 1623c390f211SDouglas Anderson goto unreg_clk; 162491aa3661SShawn Lin } 162591aa3661SShawn Lin 1626a05c8465SShawn Lin host->mmc_host_ops.hs400_enhanced_strobe = 1627a05c8465SShawn Lin sdhci_arasan_hs400_enhanced_strobe; 16288a3bee9bSShawn Lin host->mmc_host_ops.start_signal_voltage_switch = 16298a3bee9bSShawn Lin sdhci_arasan_voltage_switch; 163084362d79SShawn Lin sdhci_arasan->has_cqe = true; 16317bda9482SChristoph Muellner host->mmc->caps2 |= MMC_CAP2_CQE; 16327bda9482SChristoph Muellner 16337bda9482SChristoph Muellner if (!of_property_read_bool(np, "disable-cqe-dcmd")) 16347bda9482SChristoph Muellner host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; 163591aa3661SShawn Lin } 163691aa3661SShawn Lin 163784362d79SShawn Lin ret = sdhci_arasan_add_host(sdhci_arasan); 1638b1df9de7SMike Looijmans if (ret) 163991aa3661SShawn Lin goto err_add_host; 1640e3ec3a3dSSoren Brinkmann 1641e3ec3a3dSSoren Brinkmann return 0; 1642e3ec3a3dSSoren Brinkmann 164391aa3661SShawn Lin err_add_host: 164491aa3661SShawn Lin if (!IS_ERR(sdhci_arasan->phy)) 164591aa3661SShawn Lin phy_exit(sdhci_arasan->phy); 1646c390f211SDouglas Anderson unreg_clk: 16472ff0b85dSMuhammad Husaini Zulkifli sdhci_arasan_unregister_sdclk(dev); 1648e3ec3a3dSSoren Brinkmann clk_disable_all: 1649e3ec3a3dSSoren Brinkmann clk_disable_unprepare(clk_xin); 1650e3ec3a3dSSoren Brinkmann clk_dis_ahb: 1651e3ec3a3dSSoren Brinkmann clk_disable_unprepare(sdhci_arasan->clk_ahb); 1652278d0962SShawn Lin err_pltfm_free: 1653278d0962SShawn Lin sdhci_pltfm_free(pdev); 1654e3ec3a3dSSoren Brinkmann return ret; 1655e3ec3a3dSSoren Brinkmann } 1656e3ec3a3dSSoren Brinkmann 1657e3ec3a3dSSoren Brinkmann static int sdhci_arasan_remove(struct platform_device *pdev) 1658e3ec3a3dSSoren Brinkmann { 16590c7fe32eSJisheng Zhang int ret; 1660e3ec3a3dSSoren Brinkmann struct sdhci_host *host = platform_get_drvdata(pdev); 1661e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 166289211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 166389211418SJisheng Zhang struct clk *clk_ahb = sdhci_arasan->clk_ahb; 1664e3ec3a3dSSoren Brinkmann 166591aa3661SShawn Lin if (!IS_ERR(sdhci_arasan->phy)) { 1666b2db9c67SDouglas Anderson if (sdhci_arasan->is_phy_on) 166791aa3661SShawn Lin phy_power_off(sdhci_arasan->phy); 166891aa3661SShawn Lin phy_exit(sdhci_arasan->phy); 166991aa3661SShawn Lin } 167091aa3661SShawn Lin 1671c390f211SDouglas Anderson sdhci_arasan_unregister_sdclk(&pdev->dev); 1672c390f211SDouglas Anderson 16730c7fe32eSJisheng Zhang ret = sdhci_pltfm_unregister(pdev); 16740c7fe32eSJisheng Zhang 167589211418SJisheng Zhang clk_disable_unprepare(clk_ahb); 1676e3ec3a3dSSoren Brinkmann 16770c7fe32eSJisheng Zhang return ret; 1678e3ec3a3dSSoren Brinkmann } 1679e3ec3a3dSSoren Brinkmann 1680e3ec3a3dSSoren Brinkmann static struct platform_driver sdhci_arasan_driver = { 1681e3ec3a3dSSoren Brinkmann .driver = { 1682e3ec3a3dSSoren Brinkmann .name = "sdhci-arasan", 168321b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1684e3ec3a3dSSoren Brinkmann .of_match_table = sdhci_arasan_of_match, 1685e3ec3a3dSSoren Brinkmann .pm = &sdhci_arasan_dev_pm_ops, 1686e3ec3a3dSSoren Brinkmann }, 1687e3ec3a3dSSoren Brinkmann .probe = sdhci_arasan_probe, 1688e3ec3a3dSSoren Brinkmann .remove = sdhci_arasan_remove, 1689e3ec3a3dSSoren Brinkmann }; 1690e3ec3a3dSSoren Brinkmann 1691e3ec3a3dSSoren Brinkmann module_platform_driver(sdhci_arasan_driver); 1692e3ec3a3dSSoren Brinkmann 1693e3ec3a3dSSoren Brinkmann MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller"); 1694e3ec3a3dSSoren Brinkmann MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>"); 1695e3ec3a3dSSoren Brinkmann MODULE_LICENSE("GPL"); 1696