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) 162c0b4e411SManish Narani /* 163c0b4e411SManish Narani * Some of the Arasan variations might not have timing requirements 164c0b4e411SManish Narani * met at 25MHz for Default Speed mode, those controllers work at 165c0b4e411SManish Narani * 19MHz instead 166c0b4e411SManish Narani */ 167c0b4e411SManish Narani #define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2) 168e3ec3a3dSSoren Brinkmann }; 169e3ec3a3dSSoren Brinkmann 17006b23ca0SFaiz Abbas struct sdhci_arasan_of_data { 17106b23ca0SFaiz Abbas const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 17206b23ca0SFaiz Abbas const struct sdhci_pltfm_data *pdata; 17316ada730SManish Narani const struct sdhci_arasan_clk_ops *clk_ops; 17406b23ca0SFaiz Abbas }; 17506b23ca0SFaiz Abbas 1763ea4666eSDouglas Anderson static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { 1773ea4666eSDouglas Anderson .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 }, 178b2ca77c9SShawn Lin .clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0}, 1793ea4666eSDouglas Anderson .hiword_update = true, 1803ea4666eSDouglas Anderson }; 1813ea4666eSDouglas Anderson 1825c1a4f40SRamuthevar Vadivel Muruganx static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = { 1835c1a4f40SRamuthevar Vadivel Muruganx .baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 }, 1845c1a4f40SRamuthevar Vadivel Muruganx .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 1855c1a4f40SRamuthevar Vadivel Muruganx .hiword_update = false, 1865c1a4f40SRamuthevar Vadivel Muruganx }; 1875c1a4f40SRamuthevar Vadivel Muruganx 188d1807ad6SRamuthevar Vadivel Murugan static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { 189d1807ad6SRamuthevar Vadivel Murugan .baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 }, 190d1807ad6SRamuthevar Vadivel Murugan .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 191d1807ad6SRamuthevar Vadivel Murugan .hiword_update = false, 192d1807ad6SRamuthevar Vadivel Murugan }; 193d1807ad6SRamuthevar Vadivel Murugan 19436c6aadaSWan Ahmad Zainie static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { 19536c6aadaSWan Ahmad Zainie .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, 19636c6aadaSWan Ahmad Zainie .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, 19736c6aadaSWan Ahmad Zainie .support64b = { .reg = 0x4, .width = 1, .shift = 24 }, 19836c6aadaSWan Ahmad Zainie .hiword_update = false, 19936c6aadaSWan Ahmad Zainie }; 20036c6aadaSWan Ahmad Zainie 2013ea4666eSDouglas Anderson /** 2023ea4666eSDouglas Anderson * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers 2033ea4666eSDouglas Anderson * 2044908460eSManish Narani * @host: The sdhci_host 2054908460eSManish Narani * @fld: The field to write to 2064908460eSManish Narani * @val: The value to write 2074908460eSManish Narani * 2083ea4666eSDouglas Anderson * This function allows writing to fields in sdhci_arasan_soc_ctl_map. 2093ea4666eSDouglas Anderson * Note that if a field is specified as not available (shift < 0) then 2103ea4666eSDouglas Anderson * this function will silently return an error code. It will be noisy 2113ea4666eSDouglas Anderson * and print errors for any other (unexpected) errors. 2123ea4666eSDouglas Anderson * 2134908460eSManish Narani * Return: 0 on success and error value on error 2143ea4666eSDouglas Anderson */ 2153ea4666eSDouglas Anderson static int sdhci_arasan_syscon_write(struct sdhci_host *host, 2163ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_field *fld, 2173ea4666eSDouglas Anderson u32 val) 2183ea4666eSDouglas Anderson { 2193ea4666eSDouglas Anderson struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2203ea4666eSDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 2213ea4666eSDouglas Anderson struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base; 2223ea4666eSDouglas Anderson u32 reg = fld->reg; 2233ea4666eSDouglas Anderson u16 width = fld->width; 2243ea4666eSDouglas Anderson s16 shift = fld->shift; 2253ea4666eSDouglas Anderson int ret; 2263ea4666eSDouglas Anderson 2273ea4666eSDouglas Anderson /* 2283ea4666eSDouglas Anderson * Silently return errors for shift < 0 so caller doesn't have 2293ea4666eSDouglas Anderson * to check for fields which are optional. For fields that 2303ea4666eSDouglas Anderson * are required then caller needs to do something special 2313ea4666eSDouglas Anderson * anyway. 2323ea4666eSDouglas Anderson */ 2333ea4666eSDouglas Anderson if (shift < 0) 2343ea4666eSDouglas Anderson return -EINVAL; 2353ea4666eSDouglas Anderson 2363ea4666eSDouglas Anderson if (sdhci_arasan->soc_ctl_map->hiword_update) 2373ea4666eSDouglas Anderson ret = regmap_write(soc_ctl_base, reg, 2383ea4666eSDouglas Anderson HIWORD_UPDATE(val, GENMASK(width, 0), 2393ea4666eSDouglas Anderson shift)); 2403ea4666eSDouglas Anderson else 2413ea4666eSDouglas Anderson ret = regmap_update_bits(soc_ctl_base, reg, 2423ea4666eSDouglas Anderson GENMASK(shift + width, shift), 2433ea4666eSDouglas Anderson val << shift); 2443ea4666eSDouglas Anderson 2453ea4666eSDouglas Anderson /* Yell about (unexpected) regmap errors */ 2463ea4666eSDouglas Anderson if (ret) 2473ea4666eSDouglas Anderson pr_warn("%s: Regmap write fail: %d\n", 2483ea4666eSDouglas Anderson mmc_hostname(host->mmc), ret); 2493ea4666eSDouglas Anderson 2503ea4666eSDouglas Anderson return ret; 2513ea4666eSDouglas Anderson } 2523ea4666eSDouglas Anderson 253802ac39aSShawn Lin static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) 254802ac39aSShawn Lin { 255802ac39aSShawn Lin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 256802ac39aSShawn Lin struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 257f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 2586fc09244SDouglas Anderson bool ctrl_phy = false; 259802ac39aSShawn Lin 260b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy)) { 261b2db9c67SDouglas Anderson if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) { 262b2db9c67SDouglas Anderson /* 263b2db9c67SDouglas Anderson * If PHY off, set clock to max speed and power PHY on. 264b2db9c67SDouglas Anderson * 265b2db9c67SDouglas Anderson * Although PHY docs apparently suggest power cycling 266b2db9c67SDouglas Anderson * when changing the clock the PHY doesn't like to be 267b2db9c67SDouglas Anderson * powered on while at low speeds like those used in ID 268b2db9c67SDouglas Anderson * mode. Even worse is powering the PHY on while the 269b2db9c67SDouglas Anderson * clock is off. 270b2db9c67SDouglas Anderson * 271b2db9c67SDouglas Anderson * To workaround the PHY limitations, the best we can 272b2db9c67SDouglas Anderson * do is to power it on at a faster speed and then slam 273b2db9c67SDouglas Anderson * through low speeds without power cycling. 274b2db9c67SDouglas Anderson */ 275b2db9c67SDouglas Anderson sdhci_set_clock(host, host->max_clk); 276*66bad6edSManish Narani if (phy_power_on(sdhci_arasan->phy)) { 277*66bad6edSManish Narani pr_err("%s: Cannot power on phy.\n", 278*66bad6edSManish Narani mmc_hostname(host->mmc)); 279*66bad6edSManish Narani return; 280*66bad6edSManish Narani } 281*66bad6edSManish Narani 282b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 283802ac39aSShawn Lin 284b2db9c67SDouglas Anderson /* 285b2db9c67SDouglas Anderson * We'll now fall through to the below case with 286b2db9c67SDouglas Anderson * ctrl_phy = false (so we won't turn off/on). The 287b2db9c67SDouglas Anderson * sdhci_set_clock() will set the real clock. 288b2db9c67SDouglas Anderson */ 289b2db9c67SDouglas Anderson } else if (clock > PHY_CLK_TOO_SLOW_HZ) { 290b2db9c67SDouglas Anderson /* 291b2db9c67SDouglas Anderson * At higher clock speeds the PHY is fine being power 292b2db9c67SDouglas Anderson * cycled and docs say you _should_ power cycle when 293b2db9c67SDouglas Anderson * changing clock speeds. 294b2db9c67SDouglas Anderson */ 295b2db9c67SDouglas Anderson ctrl_phy = true; 296b2db9c67SDouglas Anderson } 297b2db9c67SDouglas Anderson } 298b2db9c67SDouglas Anderson 299b2db9c67SDouglas Anderson if (ctrl_phy && sdhci_arasan->is_phy_on) { 300802ac39aSShawn Lin phy_power_off(sdhci_arasan->phy); 301b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = false; 302802ac39aSShawn Lin } 303802ac39aSShawn Lin 304c0b4e411SManish Narani if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) { 305c0b4e411SManish Narani /* 306c0b4e411SManish Narani * Some of the Arasan variations might not have timing 307c0b4e411SManish Narani * requirements met at 25MHz for Default Speed mode, 308c0b4e411SManish Narani * those controllers work at 19MHz instead. 309c0b4e411SManish Narani */ 310c0b4e411SManish Narani if (clock == DEFAULT_SPEED_MAX_DTR) 311c0b4e411SManish Narani clock = (DEFAULT_SPEED_MAX_DTR * 19) / 25; 312c0b4e411SManish Narani } 313c0b4e411SManish Narani 314f3dafc37SManish Narani /* Set the Input and Output Clock Phase Delays */ 315f3dafc37SManish Narani if (clk_data->set_clk_delays) 316f3dafc37SManish Narani clk_data->set_clk_delays(host); 317f3dafc37SManish Narani 318802ac39aSShawn Lin sdhci_set_clock(host, clock); 319802ac39aSShawn Lin 3203f2c7d5dSHelmut Grohne if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE) 3213f2c7d5dSHelmut Grohne /* 3223f2c7d5dSHelmut Grohne * Some controllers immediately report SDHCI_CLOCK_INT_STABLE 3233f2c7d5dSHelmut Grohne * after enabling the clock even though the clock is not 3243f2c7d5dSHelmut Grohne * stable. Trying to use a clock without waiting here results 3253f2c7d5dSHelmut Grohne * in EILSEQ while detecting some older/slower cards. The 3263f2c7d5dSHelmut Grohne * chosen delay is the maximum delay from sdhci_set_clock. 3273f2c7d5dSHelmut Grohne */ 3283f2c7d5dSHelmut Grohne msleep(20); 3293f2c7d5dSHelmut Grohne 3306fc09244SDouglas Anderson if (ctrl_phy) { 331*66bad6edSManish Narani if (phy_power_on(sdhci_arasan->phy)) { 332*66bad6edSManish Narani pr_err("%s: Cannot power on phy.\n", 333*66bad6edSManish Narani mmc_hostname(host->mmc)); 334*66bad6edSManish Narani return; 335*66bad6edSManish Narani } 336*66bad6edSManish Narani 337b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 338802ac39aSShawn Lin } 339802ac39aSShawn Lin } 340802ac39aSShawn Lin 341a05c8465SShawn Lin static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, 342a05c8465SShawn Lin struct mmc_ios *ios) 343a05c8465SShawn Lin { 344a05c8465SShawn Lin u32 vendor; 345a05c8465SShawn Lin struct sdhci_host *host = mmc_priv(mmc); 346a05c8465SShawn Lin 3470daf72feSJean-Francois Dagenais vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER); 348a05c8465SShawn Lin if (ios->enhanced_strobe) 349a05c8465SShawn Lin vendor |= VENDOR_ENHANCED_STROBE; 350a05c8465SShawn Lin else 351a05c8465SShawn Lin vendor &= ~VENDOR_ENHANCED_STROBE; 352a05c8465SShawn Lin 3530daf72feSJean-Francois Dagenais sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER); 354a05c8465SShawn Lin } 355a05c8465SShawn Lin 35613d62fd2SWei Yongjun static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) 3573794c542SZach Brown { 3583794c542SZach Brown u8 ctrl; 3593794c542SZach Brown struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3603794c542SZach Brown struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 3613794c542SZach Brown 3623794c542SZach Brown sdhci_reset(host, mask); 3633794c542SZach Brown 3643794c542SZach Brown if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) { 3653794c542SZach Brown ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 3663794c542SZach Brown ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN; 3673794c542SZach Brown sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 3683794c542SZach Brown } 3693794c542SZach Brown } 3703794c542SZach Brown 3718a3bee9bSShawn Lin static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, 3728a3bee9bSShawn Lin struct mmc_ios *ios) 3738a3bee9bSShawn Lin { 3748a3bee9bSShawn Lin switch (ios->signal_voltage) { 3758a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_180: 3768a3bee9bSShawn Lin /* 3778a3bee9bSShawn Lin * Plese don't switch to 1V8 as arasan,5.1 doesn't 3788a3bee9bSShawn Lin * actually refer to this setting to indicate the 3798a3bee9bSShawn Lin * signal voltage and the state machine will be broken 3808a3bee9bSShawn Lin * actually if we force to enable 1V8. That's something 3818a3bee9bSShawn Lin * like broken quirk but we could work around here. 3828a3bee9bSShawn Lin */ 3838a3bee9bSShawn Lin return 0; 3848a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_330: 3858a3bee9bSShawn Lin case MMC_SIGNAL_VOLTAGE_120: 3868a3bee9bSShawn Lin /* We don't support 3V3 and 1V2 */ 3878a3bee9bSShawn Lin break; 3888a3bee9bSShawn Lin } 3898a3bee9bSShawn Lin 3908a3bee9bSShawn Lin return -EINVAL; 3918a3bee9bSShawn Lin } 3928a3bee9bSShawn Lin 393a81dae3aSJulia Lawall static const struct sdhci_ops sdhci_arasan_ops = { 394802ac39aSShawn Lin .set_clock = sdhci_arasan_set_clock, 395e3ec3a3dSSoren Brinkmann .get_max_clock = sdhci_pltfm_clk_get_max_clock, 3968cc35289SShawn Lin .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 3972317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 3983794c542SZach Brown .reset = sdhci_arasan_reset, 39996d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 400c2c5252cSNicolas Saenz Julienne .set_power = sdhci_set_power_and_bus_voltage, 401e3ec3a3dSSoren Brinkmann }; 402e3ec3a3dSSoren Brinkmann 40384362d79SShawn Lin static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) 40484362d79SShawn Lin { 40584362d79SShawn Lin int cmd_error = 0; 40684362d79SShawn Lin int data_error = 0; 40784362d79SShawn Lin 40884362d79SShawn Lin if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 40984362d79SShawn Lin return intmask; 41084362d79SShawn Lin 41184362d79SShawn Lin cqhci_irq(host->mmc, intmask, cmd_error, data_error); 41284362d79SShawn Lin 41384362d79SShawn Lin return 0; 41484362d79SShawn Lin } 41584362d79SShawn Lin 41684362d79SShawn Lin static void sdhci_arasan_dumpregs(struct mmc_host *mmc) 41784362d79SShawn Lin { 41884362d79SShawn Lin sdhci_dumpregs(mmc_priv(mmc)); 41984362d79SShawn Lin } 42084362d79SShawn Lin 42184362d79SShawn Lin static void sdhci_arasan_cqe_enable(struct mmc_host *mmc) 42284362d79SShawn Lin { 42384362d79SShawn Lin struct sdhci_host *host = mmc_priv(mmc); 42484362d79SShawn Lin u32 reg; 42584362d79SShawn Lin 42684362d79SShawn Lin reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 42784362d79SShawn Lin while (reg & SDHCI_DATA_AVAILABLE) { 42884362d79SShawn Lin sdhci_readl(host, SDHCI_BUFFER); 42984362d79SShawn Lin reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 43084362d79SShawn Lin } 43184362d79SShawn Lin 43284362d79SShawn Lin sdhci_cqe_enable(mmc); 43384362d79SShawn Lin } 43484362d79SShawn Lin 43584362d79SShawn Lin static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = { 43684362d79SShawn Lin .enable = sdhci_arasan_cqe_enable, 43784362d79SShawn Lin .disable = sdhci_cqe_disable, 43884362d79SShawn Lin .dumpregs = sdhci_arasan_dumpregs, 43984362d79SShawn Lin }; 44084362d79SShawn Lin 44184362d79SShawn Lin static const struct sdhci_ops sdhci_arasan_cqe_ops = { 44284362d79SShawn Lin .set_clock = sdhci_arasan_set_clock, 44384362d79SShawn Lin .get_max_clock = sdhci_pltfm_clk_get_max_clock, 44484362d79SShawn Lin .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 44584362d79SShawn Lin .set_bus_width = sdhci_set_bus_width, 44684362d79SShawn Lin .reset = sdhci_arasan_reset, 44784362d79SShawn Lin .set_uhs_signaling = sdhci_set_uhs_signaling, 448c2c5252cSNicolas Saenz Julienne .set_power = sdhci_set_power_and_bus_voltage, 44984362d79SShawn Lin .irq = sdhci_arasan_cqhci_irq, 45084362d79SShawn Lin }; 45184362d79SShawn Lin 45284362d79SShawn Lin static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { 45384362d79SShawn Lin .ops = &sdhci_arasan_cqe_ops, 45484362d79SShawn Lin .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 45584362d79SShawn Lin .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 45684362d79SShawn Lin SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, 45784362d79SShawn Lin }; 45884362d79SShawn Lin 459e3ec3a3dSSoren Brinkmann #ifdef CONFIG_PM_SLEEP 460e3ec3a3dSSoren Brinkmann /** 461e3ec3a3dSSoren Brinkmann * sdhci_arasan_suspend - Suspend method for the driver 462e3ec3a3dSSoren Brinkmann * @dev: Address of the device structure 463e3ec3a3dSSoren Brinkmann * 464e3ec3a3dSSoren Brinkmann * Put the device in a low power state. 4654908460eSManish Narani * 4664908460eSManish Narani * Return: 0 on success and error value on error 467e3ec3a3dSSoren Brinkmann */ 468e3ec3a3dSSoren Brinkmann static int sdhci_arasan_suspend(struct device *dev) 469e3ec3a3dSSoren Brinkmann { 470970f2d90SWolfram Sang struct sdhci_host *host = dev_get_drvdata(dev); 471e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 47289211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 473e3ec3a3dSSoren Brinkmann int ret; 474e3ec3a3dSSoren Brinkmann 475d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 476d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 477d38dcad4SAdrian Hunter 47884362d79SShawn Lin if (sdhci_arasan->has_cqe) { 47984362d79SShawn Lin ret = cqhci_suspend(host->mmc); 48084362d79SShawn Lin if (ret) 48184362d79SShawn Lin return ret; 48284362d79SShawn Lin } 48384362d79SShawn Lin 484e3ec3a3dSSoren Brinkmann ret = sdhci_suspend_host(host); 485e3ec3a3dSSoren Brinkmann if (ret) 486e3ec3a3dSSoren Brinkmann return ret; 487e3ec3a3dSSoren Brinkmann 488b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) { 48991aa3661SShawn Lin ret = phy_power_off(sdhci_arasan->phy); 49091aa3661SShawn Lin if (ret) { 49191aa3661SShawn Lin dev_err(dev, "Cannot power off phy.\n"); 492*66bad6edSManish Narani if (sdhci_resume_host(host)) 493*66bad6edSManish Narani dev_err(dev, "Cannot resume host.\n"); 494*66bad6edSManish Narani 49591aa3661SShawn Lin return ret; 49691aa3661SShawn Lin } 497b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = false; 49891aa3661SShawn Lin } 49991aa3661SShawn Lin 500e3ec3a3dSSoren Brinkmann clk_disable(pltfm_host->clk); 501e3ec3a3dSSoren Brinkmann clk_disable(sdhci_arasan->clk_ahb); 502e3ec3a3dSSoren Brinkmann 503e3ec3a3dSSoren Brinkmann return 0; 504e3ec3a3dSSoren Brinkmann } 505e3ec3a3dSSoren Brinkmann 506e3ec3a3dSSoren Brinkmann /** 507e3ec3a3dSSoren Brinkmann * sdhci_arasan_resume - Resume method for the driver 508e3ec3a3dSSoren Brinkmann * @dev: Address of the device structure 509e3ec3a3dSSoren Brinkmann * 510e3ec3a3dSSoren Brinkmann * Resume operation after suspend 5114908460eSManish Narani * 5124908460eSManish Narani * Return: 0 on success and error value on error 513e3ec3a3dSSoren Brinkmann */ 514e3ec3a3dSSoren Brinkmann static int sdhci_arasan_resume(struct device *dev) 515e3ec3a3dSSoren Brinkmann { 516970f2d90SWolfram Sang struct sdhci_host *host = dev_get_drvdata(dev); 517e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 51889211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 519e3ec3a3dSSoren Brinkmann int ret; 520e3ec3a3dSSoren Brinkmann 521e3ec3a3dSSoren Brinkmann ret = clk_enable(sdhci_arasan->clk_ahb); 522e3ec3a3dSSoren Brinkmann if (ret) { 523e3ec3a3dSSoren Brinkmann dev_err(dev, "Cannot enable AHB clock.\n"); 524e3ec3a3dSSoren Brinkmann return ret; 525e3ec3a3dSSoren Brinkmann } 526e3ec3a3dSSoren Brinkmann 527e3ec3a3dSSoren Brinkmann ret = clk_enable(pltfm_host->clk); 528e3ec3a3dSSoren Brinkmann if (ret) { 529e3ec3a3dSSoren Brinkmann dev_err(dev, "Cannot enable SD clock.\n"); 530e3ec3a3dSSoren Brinkmann return ret; 531e3ec3a3dSSoren Brinkmann } 532e3ec3a3dSSoren Brinkmann 533b2db9c67SDouglas Anderson if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) { 53491aa3661SShawn Lin ret = phy_power_on(sdhci_arasan->phy); 53591aa3661SShawn Lin if (ret) { 53691aa3661SShawn Lin dev_err(dev, "Cannot power on phy.\n"); 53791aa3661SShawn Lin return ret; 53891aa3661SShawn Lin } 539b2db9c67SDouglas Anderson sdhci_arasan->is_phy_on = true; 54091aa3661SShawn Lin } 54191aa3661SShawn Lin 54284362d79SShawn Lin ret = sdhci_resume_host(host); 54384362d79SShawn Lin if (ret) { 54484362d79SShawn Lin dev_err(dev, "Cannot resume host.\n"); 54584362d79SShawn Lin return ret; 54684362d79SShawn Lin } 54784362d79SShawn Lin 54884362d79SShawn Lin if (sdhci_arasan->has_cqe) 54984362d79SShawn Lin return cqhci_resume(host->mmc); 55084362d79SShawn Lin 55184362d79SShawn Lin return 0; 552e3ec3a3dSSoren Brinkmann } 553e3ec3a3dSSoren Brinkmann #endif /* ! CONFIG_PM_SLEEP */ 554e3ec3a3dSSoren Brinkmann 555e3ec3a3dSSoren Brinkmann static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, 556e3ec3a3dSSoren Brinkmann sdhci_arasan_resume); 557e3ec3a3dSSoren Brinkmann 5583ea4666eSDouglas Anderson /** 559c390f211SDouglas Anderson * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate 560c390f211SDouglas Anderson * 5614908460eSManish Narani * @hw: Pointer to the hardware clock structure. 5624908460eSManish Narani * @parent_rate: The parent rate (should be rate of clk_xin). 5634908460eSManish Narani * 564c390f211SDouglas Anderson * Return the current actual rate of the SD card clock. This can be used 565c390f211SDouglas Anderson * to communicate with out PHY. 566c390f211SDouglas Anderson * 5674908460eSManish Narani * Return: The card clock rate. 568c390f211SDouglas Anderson */ 569c390f211SDouglas Anderson static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, 570c390f211SDouglas Anderson unsigned long parent_rate) 571c390f211SDouglas Anderson { 572e1463618SManish Narani struct sdhci_arasan_clk_data *clk_data = 573e1463618SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 574c390f211SDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = 575e1463618SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 576c390f211SDouglas Anderson struct sdhci_host *host = sdhci_arasan->host; 577c390f211SDouglas Anderson 578c390f211SDouglas Anderson return host->mmc->actual_clock; 579c390f211SDouglas Anderson } 580c390f211SDouglas Anderson 581c390f211SDouglas Anderson static const struct clk_ops arasan_sdcardclk_ops = { 582c390f211SDouglas Anderson .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 583c390f211SDouglas Anderson }; 584c390f211SDouglas Anderson 585c390f211SDouglas Anderson /** 58607a14d1dSManish Narani * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate 58707a14d1dSManish Narani * 5884908460eSManish Narani * @hw: Pointer to the hardware clock structure. 5894908460eSManish Narani * @parent_rate: The parent rate (should be rate of clk_xin). 5904908460eSManish Narani * 59107a14d1dSManish Narani * Return the current actual rate of the sampling clock. This can be used 59207a14d1dSManish Narani * to communicate with out PHY. 59307a14d1dSManish Narani * 5944908460eSManish Narani * Return: The sample clock rate. 59507a14d1dSManish Narani */ 59607a14d1dSManish Narani static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, 59707a14d1dSManish Narani unsigned long parent_rate) 59807a14d1dSManish Narani { 59907a14d1dSManish Narani struct sdhci_arasan_clk_data *clk_data = 60007a14d1dSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 60107a14d1dSManish Narani struct sdhci_arasan_data *sdhci_arasan = 60207a14d1dSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 60307a14d1dSManish Narani struct sdhci_host *host = sdhci_arasan->host; 60407a14d1dSManish Narani 60507a14d1dSManish Narani return host->mmc->actual_clock; 60607a14d1dSManish Narani } 60707a14d1dSManish Narani 60807a14d1dSManish Narani static const struct clk_ops arasan_sampleclk_ops = { 60907a14d1dSManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 61007a14d1dSManish Narani }; 61107a14d1dSManish Narani 61207a14d1dSManish Narani /** 613a5c8b2aeSManish Narani * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays 614a5c8b2aeSManish Narani * 6154908460eSManish Narani * @hw: Pointer to the hardware clock structure. 6164908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 6174908460eSManish Narani * 618a5c8b2aeSManish Narani * Set the SD Output Clock Tap Delays for Output path 619a5c8b2aeSManish Narani * 620a5c8b2aeSManish Narani * Return: 0 on success and error value on error 621a5c8b2aeSManish Narani */ 622a5c8b2aeSManish Narani static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) 623a5c8b2aeSManish Narani { 624a5c8b2aeSManish Narani struct sdhci_arasan_clk_data *clk_data = 625a5c8b2aeSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 626a5c8b2aeSManish Narani struct sdhci_arasan_data *sdhci_arasan = 627a5c8b2aeSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 628a5c8b2aeSManish Narani struct sdhci_host *host = sdhci_arasan->host; 629a5c8b2aeSManish Narani const char *clk_name = clk_hw_get_name(hw); 630a5c8b2aeSManish Narani u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1; 631a5c8b2aeSManish Narani u8 tap_delay, tap_max = 0; 632a5c8b2aeSManish Narani int ret; 633a5c8b2aeSManish Narani 6349e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 6359e953432SManish Narani if (host->version < SDHCI_SPEC_300) 636a5c8b2aeSManish Narani return 0; 637a5c8b2aeSManish Narani 638a5c8b2aeSManish Narani switch (host->timing) { 639a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS: 640a5c8b2aeSManish Narani case MMC_TIMING_SD_HS: 641a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR25: 642a5c8b2aeSManish Narani case MMC_TIMING_UHS_DDR50: 643a5c8b2aeSManish Narani case MMC_TIMING_MMC_DDR52: 644a5c8b2aeSManish Narani /* For 50MHz clock, 30 Taps are available */ 645a5c8b2aeSManish Narani tap_max = 30; 646a5c8b2aeSManish Narani break; 647a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR50: 648a5c8b2aeSManish Narani /* For 100MHz clock, 15 Taps are available */ 649a5c8b2aeSManish Narani tap_max = 15; 650a5c8b2aeSManish Narani break; 651a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR104: 652a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS200: 653a5c8b2aeSManish Narani /* For 200MHz clock, 8 Taps are available */ 654a5c8b2aeSManish Narani tap_max = 8; 655a3096ec6SGustavo A. R. Silva break; 656a5c8b2aeSManish Narani default: 657a5c8b2aeSManish Narani break; 658a5c8b2aeSManish Narani } 659a5c8b2aeSManish Narani 660a5c8b2aeSManish Narani tap_delay = (degrees * tap_max) / 360; 661a5c8b2aeSManish Narani 662a5c8b2aeSManish Narani /* Set the Clock Phase */ 663426c8d85SRajan Vaja ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay); 664a5c8b2aeSManish Narani if (ret) 665a5c8b2aeSManish Narani pr_err("Error setting Output Tap Delay\n"); 666a5c8b2aeSManish Narani 667d06d60d5SManish Narani /* Release DLL Reset */ 668d06d60d5SManish Narani zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE); 669d06d60d5SManish Narani 670a5c8b2aeSManish Narani return ret; 671a5c8b2aeSManish Narani } 672a5c8b2aeSManish Narani 673a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sdcardclk_ops = { 674a5c8b2aeSManish Narani .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 675a5c8b2aeSManish Narani .set_phase = sdhci_zynqmp_sdcardclk_set_phase, 676a5c8b2aeSManish Narani }; 677a5c8b2aeSManish Narani 678a5c8b2aeSManish Narani /** 679a5c8b2aeSManish Narani * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays 680a5c8b2aeSManish Narani * 6814908460eSManish Narani * @hw: Pointer to the hardware clock structure. 6824908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 6834908460eSManish Narani * 684a5c8b2aeSManish Narani * Set the SD Input Clock Tap Delays for Input path 685a5c8b2aeSManish Narani * 686a5c8b2aeSManish Narani * Return: 0 on success and error value on error 687a5c8b2aeSManish Narani */ 688a5c8b2aeSManish Narani static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) 689a5c8b2aeSManish Narani { 690a5c8b2aeSManish Narani struct sdhci_arasan_clk_data *clk_data = 691a5c8b2aeSManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 692a5c8b2aeSManish Narani struct sdhci_arasan_data *sdhci_arasan = 693a5c8b2aeSManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 694a5c8b2aeSManish Narani struct sdhci_host *host = sdhci_arasan->host; 695a5c8b2aeSManish Narani const char *clk_name = clk_hw_get_name(hw); 696a5c8b2aeSManish Narani u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1; 697a5c8b2aeSManish Narani u8 tap_delay, tap_max = 0; 698a5c8b2aeSManish Narani int ret; 699a5c8b2aeSManish Narani 7009e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 7019e953432SManish Narani if (host->version < SDHCI_SPEC_300) 702a5c8b2aeSManish Narani return 0; 703a5c8b2aeSManish Narani 704d06d60d5SManish Narani /* Assert DLL Reset */ 705d06d60d5SManish Narani zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT); 706d06d60d5SManish Narani 707a5c8b2aeSManish Narani switch (host->timing) { 708a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS: 709a5c8b2aeSManish Narani case MMC_TIMING_SD_HS: 710a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR25: 711a5c8b2aeSManish Narani case MMC_TIMING_UHS_DDR50: 712a5c8b2aeSManish Narani case MMC_TIMING_MMC_DDR52: 713a5c8b2aeSManish Narani /* For 50MHz clock, 120 Taps are available */ 714a5c8b2aeSManish Narani tap_max = 120; 715a5c8b2aeSManish Narani break; 716a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR50: 717a5c8b2aeSManish Narani /* For 100MHz clock, 60 Taps are available */ 718a5c8b2aeSManish Narani tap_max = 60; 719a5c8b2aeSManish Narani break; 720a5c8b2aeSManish Narani case MMC_TIMING_UHS_SDR104: 721a5c8b2aeSManish Narani case MMC_TIMING_MMC_HS200: 722a5c8b2aeSManish Narani /* For 200MHz clock, 30 Taps are available */ 723a5c8b2aeSManish Narani tap_max = 30; 724a3096ec6SGustavo A. R. Silva break; 725a5c8b2aeSManish Narani default: 726a5c8b2aeSManish Narani break; 727a5c8b2aeSManish Narani } 728a5c8b2aeSManish Narani 729a5c8b2aeSManish Narani tap_delay = (degrees * tap_max) / 360; 730a5c8b2aeSManish Narani 731a5c8b2aeSManish Narani /* Set the Clock Phase */ 732426c8d85SRajan Vaja ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay); 733a5c8b2aeSManish Narani if (ret) 734a5c8b2aeSManish Narani pr_err("Error setting Input Tap Delay\n"); 735a5c8b2aeSManish Narani 736a5c8b2aeSManish Narani return ret; 737a5c8b2aeSManish Narani } 738a5c8b2aeSManish Narani 739a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sampleclk_ops = { 740a5c8b2aeSManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 741a5c8b2aeSManish Narani .set_phase = sdhci_zynqmp_sampleclk_set_phase, 742a5c8b2aeSManish Narani }; 743a5c8b2aeSManish Narani 7441a470721SManish Narani /** 7451a470721SManish Narani * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays 7461a470721SManish Narani * 7474908460eSManish Narani * @hw: Pointer to the hardware clock structure. 7484908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 7494908460eSManish Narani * 7501a470721SManish Narani * Set the SD Output Clock Tap Delays for Output path 7511a470721SManish Narani * 7521a470721SManish Narani * Return: 0 on success and error value on error 7531a470721SManish Narani */ 7541a470721SManish Narani static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) 7551a470721SManish Narani { 7561a470721SManish Narani struct sdhci_arasan_clk_data *clk_data = 7571a470721SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 7581a470721SManish Narani struct sdhci_arasan_data *sdhci_arasan = 7591a470721SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 7601a470721SManish Narani struct sdhci_host *host = sdhci_arasan->host; 7611a470721SManish Narani u8 tap_delay, tap_max = 0; 7621a470721SManish Narani 7639e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 7649e953432SManish Narani if (host->version < SDHCI_SPEC_300) 7651a470721SManish Narani return 0; 7661a470721SManish Narani 7671a470721SManish Narani switch (host->timing) { 7681a470721SManish Narani case MMC_TIMING_MMC_HS: 7691a470721SManish Narani case MMC_TIMING_SD_HS: 7701a470721SManish Narani case MMC_TIMING_UHS_SDR25: 7711a470721SManish Narani case MMC_TIMING_UHS_DDR50: 7721a470721SManish Narani case MMC_TIMING_MMC_DDR52: 7731a470721SManish Narani /* For 50MHz clock, 30 Taps are available */ 7741a470721SManish Narani tap_max = 30; 7751a470721SManish Narani break; 7761a470721SManish Narani case MMC_TIMING_UHS_SDR50: 7771a470721SManish Narani /* For 100MHz clock, 15 Taps are available */ 7781a470721SManish Narani tap_max = 15; 7791a470721SManish Narani break; 7801a470721SManish Narani case MMC_TIMING_UHS_SDR104: 7811a470721SManish Narani case MMC_TIMING_MMC_HS200: 7821a470721SManish Narani /* For 200MHz clock, 8 Taps are available */ 7831a470721SManish Narani tap_max = 8; 784a3096ec6SGustavo A. R. Silva break; 7851a470721SManish Narani default: 7861a470721SManish Narani break; 7871a470721SManish Narani } 7881a470721SManish Narani 7891a470721SManish Narani tap_delay = (degrees * tap_max) / 360; 7901a470721SManish Narani 7911a470721SManish Narani /* Set the Clock Phase */ 7921a470721SManish Narani if (tap_delay) { 7931a470721SManish Narani u32 regval; 7941a470721SManish Narani 7951a470721SManish Narani regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER); 7961a470721SManish Narani regval |= SDHCI_OTAPDLY_ENABLE; 7971a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); 798d338c6d0SManish Narani regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK; 7991a470721SManish Narani regval |= tap_delay; 8001a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); 8011a470721SManish Narani } 8021a470721SManish Narani 803098c408bSNathan Chancellor return 0; 8041a470721SManish Narani } 8051a470721SManish Narani 8061a470721SManish Narani static const struct clk_ops versal_sdcardclk_ops = { 8071a470721SManish Narani .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 8081a470721SManish Narani .set_phase = sdhci_versal_sdcardclk_set_phase, 8091a470721SManish Narani }; 8101a470721SManish Narani 8111a470721SManish Narani /** 8121a470721SManish Narani * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays 8131a470721SManish Narani * 8144908460eSManish Narani * @hw: Pointer to the hardware clock structure. 8154908460eSManish Narani * @degrees: The clock phase shift between 0 - 359. 8164908460eSManish Narani * 8171a470721SManish Narani * Set the SD Input Clock Tap Delays for Input path 8181a470721SManish Narani * 8191a470721SManish Narani * Return: 0 on success and error value on error 8201a470721SManish Narani */ 8211a470721SManish Narani static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) 8221a470721SManish Narani { 8231a470721SManish Narani struct sdhci_arasan_clk_data *clk_data = 8241a470721SManish Narani container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 8251a470721SManish Narani struct sdhci_arasan_data *sdhci_arasan = 8261a470721SManish Narani container_of(clk_data, struct sdhci_arasan_data, clk_data); 8271a470721SManish Narani struct sdhci_host *host = sdhci_arasan->host; 8281a470721SManish Narani u8 tap_delay, tap_max = 0; 8291a470721SManish Narani 8309e953432SManish Narani /* This is applicable for SDHCI_SPEC_300 and above */ 8319e953432SManish Narani if (host->version < SDHCI_SPEC_300) 8321a470721SManish Narani return 0; 8331a470721SManish Narani 8341a470721SManish Narani switch (host->timing) { 8351a470721SManish Narani case MMC_TIMING_MMC_HS: 8361a470721SManish Narani case MMC_TIMING_SD_HS: 8371a470721SManish Narani case MMC_TIMING_UHS_SDR25: 8381a470721SManish Narani case MMC_TIMING_UHS_DDR50: 8391a470721SManish Narani case MMC_TIMING_MMC_DDR52: 8401a470721SManish Narani /* For 50MHz clock, 120 Taps are available */ 8411a470721SManish Narani tap_max = 120; 8421a470721SManish Narani break; 8431a470721SManish Narani case MMC_TIMING_UHS_SDR50: 8441a470721SManish Narani /* For 100MHz clock, 60 Taps are available */ 8451a470721SManish Narani tap_max = 60; 8461a470721SManish Narani break; 8471a470721SManish Narani case MMC_TIMING_UHS_SDR104: 8481a470721SManish Narani case MMC_TIMING_MMC_HS200: 8491a470721SManish Narani /* For 200MHz clock, 30 Taps are available */ 8501a470721SManish Narani tap_max = 30; 851a3096ec6SGustavo A. R. Silva break; 8521a470721SManish Narani default: 8531a470721SManish Narani break; 8541a470721SManish Narani } 8551a470721SManish Narani 8561a470721SManish Narani tap_delay = (degrees * tap_max) / 360; 8571a470721SManish Narani 8581a470721SManish Narani /* Set the Clock Phase */ 8591a470721SManish Narani if (tap_delay) { 8601a470721SManish Narani u32 regval; 8611a470721SManish Narani 8621a470721SManish Narani regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER); 8631a470721SManish Narani regval |= SDHCI_ITAPDLY_CHGWIN; 8641a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8651a470721SManish Narani regval |= SDHCI_ITAPDLY_ENABLE; 8661a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 867d338c6d0SManish Narani regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK; 8681a470721SManish Narani regval |= tap_delay; 8691a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8701a470721SManish Narani regval &= ~SDHCI_ITAPDLY_CHGWIN; 8711a470721SManish Narani sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8721a470721SManish Narani } 8731a470721SManish Narani 874098c408bSNathan Chancellor return 0; 8751a470721SManish Narani } 8761a470721SManish Narani 8771a470721SManish Narani static const struct clk_ops versal_sampleclk_ops = { 8781a470721SManish Narani .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 8791a470721SManish Narani .set_phase = sdhci_versal_sampleclk_set_phase, 8801a470721SManish Narani }; 8811a470721SManish Narani 8828d2e3343SManish Narani static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid) 8838d2e3343SManish Narani { 8848d2e3343SManish Narani u16 clk; 8858d2e3343SManish Narani 8868d2e3343SManish Narani clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 8878d2e3343SManish Narani clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); 8888d2e3343SManish Narani sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 8898d2e3343SManish Narani 8908d2e3343SManish Narani /* Issue DLL Reset */ 891426c8d85SRajan Vaja zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE); 8928d2e3343SManish Narani 8938d2e3343SManish Narani clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 8948d2e3343SManish Narani 8958d2e3343SManish Narani sdhci_enable_clk(host, clk); 8968d2e3343SManish Narani } 8978d2e3343SManish Narani 8988d2e3343SManish Narani static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) 8998d2e3343SManish Narani { 9008d2e3343SManish Narani struct sdhci_host *host = mmc_priv(mmc); 9018d2e3343SManish Narani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9028d2e3343SManish Narani struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 9038d2e3343SManish Narani struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw; 9048d2e3343SManish Narani const char *clk_name = clk_hw_get_name(hw); 9058d2e3343SManish Narani u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : 9068d2e3343SManish Narani NODE_SD_1; 9078d2e3343SManish Narani int err; 9088d2e3343SManish Narani 909256e4e4eSManish Narani /* ZynqMP SD controller does not perform auto tuning in DDR50 mode */ 910256e4e4eSManish Narani if (mmc->ios.timing == MMC_TIMING_UHS_DDR50) 911256e4e4eSManish Narani return 0; 912256e4e4eSManish Narani 9138d2e3343SManish Narani arasan_zynqmp_dll_reset(host, device_id); 9148d2e3343SManish Narani 9158d2e3343SManish Narani err = sdhci_execute_tuning(mmc, opcode); 9168d2e3343SManish Narani if (err) 9178d2e3343SManish Narani return err; 9188d2e3343SManish Narani 9198d2e3343SManish Narani arasan_zynqmp_dll_reset(host, device_id); 9208d2e3343SManish Narani 9218d2e3343SManish Narani return 0; 9228d2e3343SManish Narani } 9238d2e3343SManish Narani 924a5c8b2aeSManish Narani /** 925b2ca77c9SShawn Lin * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier 926b2ca77c9SShawn Lin * 9274908460eSManish Narani * @host: The sdhci_host 9284908460eSManish Narani * @value: The value to write 9294908460eSManish Narani * 930b2ca77c9SShawn Lin * The corecfg_clockmultiplier is supposed to contain clock multiplier 931b2ca77c9SShawn Lin * value of programmable clock generator. 932b2ca77c9SShawn Lin * 933b2ca77c9SShawn Lin * NOTES: 934b2ca77c9SShawn Lin * - Many existing devices don't seem to do this and work fine. To keep 935b2ca77c9SShawn Lin * compatibility for old hardware where the device tree doesn't provide a 936b2ca77c9SShawn Lin * register map, this function is a noop if a soc_ctl_map hasn't been provided 937b2ca77c9SShawn Lin * for this platform. 938b2ca77c9SShawn Lin * - The value of corecfg_clockmultiplier should sync with that of corresponding 939b2ca77c9SShawn Lin * value reading from sdhci_capability_register. So this function is called 940b2ca77c9SShawn Lin * once at probe time and never called again. 941b2ca77c9SShawn Lin */ 942b2ca77c9SShawn Lin static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, 943b2ca77c9SShawn Lin u32 value) 944b2ca77c9SShawn Lin { 945b2ca77c9SShawn Lin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 946b2ca77c9SShawn Lin struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 947b2ca77c9SShawn Lin const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 948b2ca77c9SShawn Lin sdhci_arasan->soc_ctl_map; 949b2ca77c9SShawn Lin 950b2ca77c9SShawn Lin /* Having a map is optional */ 951b2ca77c9SShawn Lin if (!soc_ctl_map) 952b2ca77c9SShawn Lin return; 953b2ca77c9SShawn Lin 954b2ca77c9SShawn Lin /* If we have a map, we expect to have a syscon */ 955b2ca77c9SShawn Lin if (!sdhci_arasan->soc_ctl_base) { 956b2ca77c9SShawn Lin pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 957b2ca77c9SShawn Lin mmc_hostname(host->mmc)); 958b2ca77c9SShawn Lin return; 959b2ca77c9SShawn Lin } 960b2ca77c9SShawn Lin 961b2ca77c9SShawn Lin sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value); 962b2ca77c9SShawn Lin } 963b2ca77c9SShawn Lin 964b2ca77c9SShawn Lin /** 9653ea4666eSDouglas Anderson * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq 9663ea4666eSDouglas Anderson * 9674908460eSManish Narani * @host: The sdhci_host 9684908460eSManish Narani * 9693ea4666eSDouglas Anderson * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This 9703ea4666eSDouglas Anderson * function can be used to make that happen. 9713ea4666eSDouglas Anderson * 9723ea4666eSDouglas Anderson * NOTES: 9733ea4666eSDouglas Anderson * - Many existing devices don't seem to do this and work fine. To keep 9743ea4666eSDouglas Anderson * compatibility for old hardware where the device tree doesn't provide a 9753ea4666eSDouglas Anderson * register map, this function is a noop if a soc_ctl_map hasn't been provided 9763ea4666eSDouglas Anderson * for this platform. 9773ea4666eSDouglas Anderson * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider 9783ea4666eSDouglas Anderson * to achieve lower clock rates. That means that this function is called once 9793ea4666eSDouglas Anderson * at probe time and never called again. 9803ea4666eSDouglas Anderson */ 9813ea4666eSDouglas Anderson static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) 9823ea4666eSDouglas Anderson { 9833ea4666eSDouglas Anderson struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9843ea4666eSDouglas Anderson struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 9853ea4666eSDouglas Anderson const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 9863ea4666eSDouglas Anderson sdhci_arasan->soc_ctl_map; 9873ea4666eSDouglas Anderson u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000); 9883ea4666eSDouglas Anderson 9893ea4666eSDouglas Anderson /* Having a map is optional */ 9903ea4666eSDouglas Anderson if (!soc_ctl_map) 9913ea4666eSDouglas Anderson return; 9923ea4666eSDouglas Anderson 9933ea4666eSDouglas Anderson /* If we have a map, we expect to have a syscon */ 9943ea4666eSDouglas Anderson if (!sdhci_arasan->soc_ctl_base) { 9953ea4666eSDouglas Anderson pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 9963ea4666eSDouglas Anderson mmc_hostname(host->mmc)); 9973ea4666eSDouglas Anderson return; 9983ea4666eSDouglas Anderson } 9993ea4666eSDouglas Anderson 10003ea4666eSDouglas Anderson sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz); 10013ea4666eSDouglas Anderson } 10023ea4666eSDouglas Anderson 1003f3dafc37SManish Narani static void sdhci_arasan_set_clk_delays(struct sdhci_host *host) 1004f3dafc37SManish Narani { 1005f3dafc37SManish Narani struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1006f3dafc37SManish Narani struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 1007f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 1008f3dafc37SManish Narani 1009f3dafc37SManish Narani clk_set_phase(clk_data->sampleclk, 1010f3dafc37SManish Narani clk_data->clk_phase_in[host->timing]); 1011f3dafc37SManish Narani clk_set_phase(clk_data->sdcardclk, 1012f3dafc37SManish Narani clk_data->clk_phase_out[host->timing]); 1013f3dafc37SManish Narani } 1014f3dafc37SManish Narani 1015f3dafc37SManish Narani static void arasan_dt_read_clk_phase(struct device *dev, 1016f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data, 1017f3dafc37SManish Narani unsigned int timing, const char *prop) 1018f3dafc37SManish Narani { 1019f3dafc37SManish Narani struct device_node *np = dev->of_node; 1020f3dafc37SManish Narani 1021f3dafc37SManish Narani int clk_phase[2] = {0}; 1022f3dafc37SManish Narani 1023f3dafc37SManish Narani /* 1024f3dafc37SManish Narani * Read Tap Delay values from DT, if the DT does not contain the 1025f3dafc37SManish Narani * Tap Values then use the pre-defined values. 1026f3dafc37SManish Narani */ 1027f3dafc37SManish Narani if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], 1028f3dafc37SManish Narani 2, 0)) { 1029f3dafc37SManish Narani dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", 1030f3dafc37SManish Narani prop, clk_data->clk_phase_in[timing], 1031f3dafc37SManish Narani clk_data->clk_phase_out[timing]); 1032f3dafc37SManish Narani return; 1033f3dafc37SManish Narani } 1034f3dafc37SManish Narani 1035f3dafc37SManish Narani /* The values read are Input and Output Clock Delays in order */ 1036f3dafc37SManish Narani clk_data->clk_phase_in[timing] = clk_phase[0]; 1037f3dafc37SManish Narani clk_data->clk_phase_out[timing] = clk_phase[1]; 1038f3dafc37SManish Narani } 1039f3dafc37SManish Narani 1040f3dafc37SManish Narani /** 1041f3dafc37SManish Narani * arasan_dt_parse_clk_phases - Read Clock Delay values from DT 1042f3dafc37SManish Narani * 1043f3dafc37SManish Narani * @dev: Pointer to our struct device. 1044f3dafc37SManish Narani * @clk_data: Pointer to the Clock Data structure 10454908460eSManish Narani * 10464908460eSManish Narani * Called at initialization to parse the values of Clock Delays. 1047f3dafc37SManish Narani */ 1048f3dafc37SManish Narani static void arasan_dt_parse_clk_phases(struct device *dev, 1049f3dafc37SManish Narani struct sdhci_arasan_clk_data *clk_data) 1050f3dafc37SManish Narani { 1051a5c8b2aeSManish Narani u32 mio_bank = 0; 1052a5c8b2aeSManish Narani int i; 1053a5c8b2aeSManish Narani 1054f3dafc37SManish Narani /* 1055f3dafc37SManish Narani * This has been kept as a pointer and is assigned a function here. 1056f3dafc37SManish Narani * So that different controller variants can assign their own handling 1057f3dafc37SManish Narani * function. 1058f3dafc37SManish Narani */ 1059f3dafc37SManish Narani clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; 1060f3dafc37SManish Narani 1061a5c8b2aeSManish Narani if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { 106288e1d0b1SManish Narani u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = 106388e1d0b1SManish Narani ZYNQMP_ICLK_PHASE; 106488e1d0b1SManish Narani u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = 106588e1d0b1SManish Narani ZYNQMP_OCLK_PHASE; 1066a5c8b2aeSManish Narani 1067a5c8b2aeSManish Narani of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank); 1068a5c8b2aeSManish Narani if (mio_bank == 2) { 106988e1d0b1SManish Narani zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90; 107088e1d0b1SManish Narani zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90; 1071a5c8b2aeSManish Narani } 1072a5c8b2aeSManish Narani 1073a5c8b2aeSManish Narani for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { 107488e1d0b1SManish Narani clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i]; 107588e1d0b1SManish Narani clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i]; 1076a5c8b2aeSManish Narani } 1077a5c8b2aeSManish Narani } 1078a5c8b2aeSManish Narani 10791a470721SManish Narani if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) { 108088e1d0b1SManish Narani u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = 108188e1d0b1SManish Narani VERSAL_ICLK_PHASE; 108288e1d0b1SManish Narani u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = 108388e1d0b1SManish Narani VERSAL_OCLK_PHASE; 10841a470721SManish Narani 10851a470721SManish Narani for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { 108688e1d0b1SManish Narani clk_data->clk_phase_in[i] = versal_iclk_phase[i]; 108788e1d0b1SManish Narani clk_data->clk_phase_out[i] = versal_oclk_phase[i]; 10881a470721SManish Narani } 10891a470721SManish Narani } 10901a470721SManish Narani 1091f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, 1092f3dafc37SManish Narani "clk-phase-legacy"); 1093f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, 1094f3dafc37SManish Narani "clk-phase-mmc-hs"); 1095f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, 1096f3dafc37SManish Narani "clk-phase-sd-hs"); 1097f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, 1098f3dafc37SManish Narani "clk-phase-uhs-sdr12"); 1099f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, 1100f3dafc37SManish Narani "clk-phase-uhs-sdr25"); 1101f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, 1102f3dafc37SManish Narani "clk-phase-uhs-sdr50"); 1103f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, 1104f3dafc37SManish Narani "clk-phase-uhs-sdr104"); 1105f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, 1106f3dafc37SManish Narani "clk-phase-uhs-ddr50"); 1107f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, 1108f3dafc37SManish Narani "clk-phase-mmc-ddr52"); 1109f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, 1110f3dafc37SManish Narani "clk-phase-mmc-hs200"); 1111f3dafc37SManish Narani arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, 1112f3dafc37SManish Narani "clk-phase-mmc-hs400"); 1113f3dafc37SManish Narani } 1114f3dafc37SManish Narani 111537d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_pdata = { 111637d3ee7cSManish Narani .ops = &sdhci_arasan_ops, 111737d3ee7cSManish Narani .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 111837d3ee7cSManish Narani .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 111937d3ee7cSManish Narani SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 112037d3ee7cSManish Narani SDHCI_QUIRK2_STOP_WITH_TC, 112137d3ee7cSManish Narani }; 112237d3ee7cSManish Narani 112316ada730SManish Narani static const struct sdhci_arasan_clk_ops arasan_clk_ops = { 112416ada730SManish Narani .sdcardclk_ops = &arasan_sdcardclk_ops, 112516ada730SManish Narani .sampleclk_ops = &arasan_sampleclk_ops, 112616ada730SManish Narani }; 112716ada730SManish Narani 112837d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { 112937d3ee7cSManish Narani .pdata = &sdhci_arasan_pdata, 113016ada730SManish Narani .clk_ops = &arasan_clk_ops, 113137d3ee7cSManish Narani }; 113237d3ee7cSManish Narani 113336c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { 113436c6aadaSWan Ahmad Zainie .ops = &sdhci_arasan_cqe_ops, 113536c6aadaSWan Ahmad Zainie .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 113636c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 113736c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_LED | 113836c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_ADDR | 113936c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_SIZE | 114036c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_ADMA_SIZE, 114136c6aadaSWan Ahmad Zainie .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 114236c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 114336c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | 114436c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_STOP_WITH_TC | 114536c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 114636c6aadaSWan Ahmad Zainie }; 114736c6aadaSWan Ahmad Zainie 114836c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = { 114936c6aadaSWan Ahmad Zainie .ops = &sdhci_arasan_ops, 115036c6aadaSWan Ahmad Zainie .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 115136c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 115236c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_LED | 115336c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_ADDR | 115436c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_SIZE | 115536c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_ADMA_SIZE, 115636c6aadaSWan Ahmad Zainie .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 115736c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 115836c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | 115936c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_STOP_WITH_TC | 116036c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 116136c6aadaSWan Ahmad Zainie }; 116236c6aadaSWan Ahmad Zainie 116336c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = { 116436c6aadaSWan Ahmad Zainie .ops = &sdhci_arasan_ops, 116536c6aadaSWan Ahmad Zainie .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 116636c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 116736c6aadaSWan Ahmad Zainie SDHCI_QUIRK_NO_LED | 116836c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_ADDR | 116936c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_DMA_SIZE | 117036c6aadaSWan Ahmad Zainie SDHCI_QUIRK_32BIT_ADMA_SIZE, 117136c6aadaSWan Ahmad Zainie .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 117236c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 117336c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_HOST_OFF_CARD_ON | 117436c6aadaSWan Ahmad Zainie SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 117536c6aadaSWan Ahmad Zainie }; 117636c6aadaSWan Ahmad Zainie 117737d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { 117837d3ee7cSManish Narani .soc_ctl_map = &rk3399_soc_ctl_map, 117937d3ee7cSManish Narani .pdata = &sdhci_arasan_cqe_pdata, 118016ada730SManish Narani .clk_ops = &arasan_clk_ops, 118137d3ee7cSManish Narani }; 118237d3ee7cSManish Narani 118337d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_emmc_data = { 118437d3ee7cSManish Narani .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, 118537d3ee7cSManish Narani .pdata = &sdhci_arasan_cqe_pdata, 118616ada730SManish Narani .clk_ops = &arasan_clk_ops, 118737d3ee7cSManish Narani }; 118837d3ee7cSManish Narani 118937d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { 119037d3ee7cSManish Narani .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, 119137d3ee7cSManish Narani .pdata = &sdhci_arasan_cqe_pdata, 119216ada730SManish Narani .clk_ops = &arasan_clk_ops, 119337d3ee7cSManish Narani }; 119437d3ee7cSManish Narani 119537d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { 119637d3ee7cSManish Narani .ops = &sdhci_arasan_ops, 119737d3ee7cSManish Narani .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 119837d3ee7cSManish Narani SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 119937d3ee7cSManish Narani SDHCI_QUIRK2_STOP_WITH_TC, 120037d3ee7cSManish Narani }; 120137d3ee7cSManish Narani 120216ada730SManish Narani static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = { 120316ada730SManish Narani .sdcardclk_ops = &zynqmp_sdcardclk_ops, 120416ada730SManish Narani .sampleclk_ops = &zynqmp_sampleclk_ops, 120516ada730SManish Narani }; 120616ada730SManish Narani 120737d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { 120837d3ee7cSManish Narani .pdata = &sdhci_arasan_zynqmp_pdata, 120916ada730SManish Narani .clk_ops = &zynqmp_clk_ops, 121016ada730SManish Narani }; 121116ada730SManish Narani 121216ada730SManish Narani static const struct sdhci_arasan_clk_ops versal_clk_ops = { 121316ada730SManish Narani .sdcardclk_ops = &versal_sdcardclk_ops, 121416ada730SManish Narani .sampleclk_ops = &versal_sampleclk_ops, 121537d3ee7cSManish Narani }; 121637d3ee7cSManish Narani 121737d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { 121837d3ee7cSManish Narani .pdata = &sdhci_arasan_zynqmp_pdata, 121916ada730SManish Narani .clk_ops = &versal_clk_ops, 122037d3ee7cSManish Narani }; 122137d3ee7cSManish Narani 122236c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_emmc_data = { 122336c6aadaSWan Ahmad Zainie .soc_ctl_map = &intel_keembay_soc_ctl_map, 122436c6aadaSWan Ahmad Zainie .pdata = &sdhci_keembay_emmc_pdata, 1225a42a7ec9SMuhammad Husaini Zulkifli .clk_ops = &arasan_clk_ops, 122636c6aadaSWan Ahmad Zainie }; 122736c6aadaSWan Ahmad Zainie 122836c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sd_data = { 122936c6aadaSWan Ahmad Zainie .soc_ctl_map = &intel_keembay_soc_ctl_map, 123036c6aadaSWan Ahmad Zainie .pdata = &sdhci_keembay_sd_pdata, 1231a42a7ec9SMuhammad Husaini Zulkifli .clk_ops = &arasan_clk_ops, 123236c6aadaSWan Ahmad Zainie }; 123336c6aadaSWan Ahmad Zainie 123436c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sdio_data = { 123536c6aadaSWan Ahmad Zainie .soc_ctl_map = &intel_keembay_soc_ctl_map, 123636c6aadaSWan Ahmad Zainie .pdata = &sdhci_keembay_sdio_pdata, 1237a42a7ec9SMuhammad Husaini Zulkifli .clk_ops = &arasan_clk_ops, 123836c6aadaSWan Ahmad Zainie }; 123936c6aadaSWan Ahmad Zainie 124037d3ee7cSManish Narani static const struct of_device_id sdhci_arasan_of_match[] = { 124137d3ee7cSManish Narani /* SoC-specific compatible strings w/ soc_ctl_map */ 124237d3ee7cSManish Narani { 124337d3ee7cSManish Narani .compatible = "rockchip,rk3399-sdhci-5.1", 124437d3ee7cSManish Narani .data = &sdhci_arasan_rk3399_data, 124537d3ee7cSManish Narani }, 124637d3ee7cSManish Narani { 124737d3ee7cSManish Narani .compatible = "intel,lgm-sdhci-5.1-emmc", 124837d3ee7cSManish Narani .data = &intel_lgm_emmc_data, 124937d3ee7cSManish Narani }, 125037d3ee7cSManish Narani { 125137d3ee7cSManish Narani .compatible = "intel,lgm-sdhci-5.1-sdxc", 125237d3ee7cSManish Narani .data = &intel_lgm_sdxc_data, 125337d3ee7cSManish Narani }, 125436c6aadaSWan Ahmad Zainie { 125536c6aadaSWan Ahmad Zainie .compatible = "intel,keembay-sdhci-5.1-emmc", 125636c6aadaSWan Ahmad Zainie .data = &intel_keembay_emmc_data, 125736c6aadaSWan Ahmad Zainie }, 125836c6aadaSWan Ahmad Zainie { 125936c6aadaSWan Ahmad Zainie .compatible = "intel,keembay-sdhci-5.1-sd", 126036c6aadaSWan Ahmad Zainie .data = &intel_keembay_sd_data, 126136c6aadaSWan Ahmad Zainie }, 126236c6aadaSWan Ahmad Zainie { 126336c6aadaSWan Ahmad Zainie .compatible = "intel,keembay-sdhci-5.1-sdio", 126436c6aadaSWan Ahmad Zainie .data = &intel_keembay_sdio_data, 126536c6aadaSWan Ahmad Zainie }, 126637d3ee7cSManish Narani /* Generic compatible below here */ 126737d3ee7cSManish Narani { 126837d3ee7cSManish Narani .compatible = "arasan,sdhci-8.9a", 126937d3ee7cSManish Narani .data = &sdhci_arasan_generic_data, 127037d3ee7cSManish Narani }, 127137d3ee7cSManish Narani { 127237d3ee7cSManish Narani .compatible = "arasan,sdhci-5.1", 127337d3ee7cSManish Narani .data = &sdhci_arasan_generic_data, 127437d3ee7cSManish Narani }, 127537d3ee7cSManish Narani { 127637d3ee7cSManish Narani .compatible = "arasan,sdhci-4.9a", 127737d3ee7cSManish Narani .data = &sdhci_arasan_generic_data, 127837d3ee7cSManish Narani }, 127937d3ee7cSManish Narani { 128037d3ee7cSManish Narani .compatible = "xlnx,zynqmp-8.9a", 128137d3ee7cSManish Narani .data = &sdhci_arasan_zynqmp_data, 128237d3ee7cSManish Narani }, 128337d3ee7cSManish Narani { 128437d3ee7cSManish Narani .compatible = "xlnx,versal-8.9a", 128537d3ee7cSManish Narani .data = &sdhci_arasan_versal_data, 128637d3ee7cSManish Narani }, 128737d3ee7cSManish Narani { /* sentinel */ } 128837d3ee7cSManish Narani }; 128937d3ee7cSManish Narani MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); 129037d3ee7cSManish Narani 1291c390f211SDouglas Anderson /** 129207a14d1dSManish Narani * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use 1293c390f211SDouglas Anderson * 12944908460eSManish Narani * @sdhci_arasan: Our private data structure. 12954908460eSManish Narani * @clk_xin: Pointer to the functional clock 12964908460eSManish Narani * @dev: Pointer to our struct device. 12974908460eSManish Narani * 1298c390f211SDouglas Anderson * Some PHY devices need to know what the actual card clock is. In order for 1299c390f211SDouglas Anderson * them to find out, we'll provide a clock through the common clock framework 1300c390f211SDouglas Anderson * for them to query. 1301c390f211SDouglas Anderson * 13024908460eSManish Narani * Return: 0 on success and error value on error 1303c390f211SDouglas Anderson */ 130407a14d1dSManish Narani static int 130507a14d1dSManish Narani sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, 1306c390f211SDouglas Anderson struct clk *clk_xin, 1307c390f211SDouglas Anderson struct device *dev) 1308c390f211SDouglas Anderson { 1309e1463618SManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 1310c390f211SDouglas Anderson struct device_node *np = dev->of_node; 1311c390f211SDouglas Anderson struct clk_init_data sdcardclk_init; 1312c390f211SDouglas Anderson const char *parent_clk_name; 1313c390f211SDouglas Anderson int ret; 1314c390f211SDouglas Anderson 1315c390f211SDouglas Anderson ret = of_property_read_string_index(np, "clock-output-names", 0, 1316c390f211SDouglas Anderson &sdcardclk_init.name); 1317c390f211SDouglas Anderson if (ret) { 1318c390f211SDouglas Anderson dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 1319c390f211SDouglas Anderson return ret; 1320c390f211SDouglas Anderson } 1321c390f211SDouglas Anderson 1322c390f211SDouglas Anderson parent_clk_name = __clk_get_name(clk_xin); 1323c390f211SDouglas Anderson sdcardclk_init.parent_names = &parent_clk_name; 1324c390f211SDouglas Anderson sdcardclk_init.num_parents = 1; 1325c390f211SDouglas Anderson sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; 132616ada730SManish Narani sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops; 1327c390f211SDouglas Anderson 1328e1463618SManish Narani clk_data->sdcardclk_hw.init = &sdcardclk_init; 1329e1463618SManish Narani clk_data->sdcardclk = 1330e1463618SManish Narani devm_clk_register(dev, &clk_data->sdcardclk_hw); 1331c99e1d0cSChuhong Yuan if (IS_ERR(clk_data->sdcardclk)) 1332c99e1d0cSChuhong Yuan return PTR_ERR(clk_data->sdcardclk); 1333e1463618SManish Narani clk_data->sdcardclk_hw.init = NULL; 1334c390f211SDouglas Anderson 1335c390f211SDouglas Anderson ret = of_clk_add_provider(np, of_clk_src_simple_get, 1336e1463618SManish Narani clk_data->sdcardclk); 1337c390f211SDouglas Anderson if (ret) 133807a14d1dSManish Narani dev_err(dev, "Failed to add sdcard clock provider\n"); 133907a14d1dSManish Narani 134007a14d1dSManish Narani return ret; 134107a14d1dSManish Narani } 134207a14d1dSManish Narani 134307a14d1dSManish Narani /** 134407a14d1dSManish Narani * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use 134507a14d1dSManish Narani * 13464908460eSManish Narani * @sdhci_arasan: Our private data structure. 13474908460eSManish Narani * @clk_xin: Pointer to the functional clock 13484908460eSManish Narani * @dev: Pointer to our struct device. 13494908460eSManish Narani * 135007a14d1dSManish Narani * Some PHY devices need to know what the actual card clock is. In order for 135107a14d1dSManish Narani * them to find out, we'll provide a clock through the common clock framework 135207a14d1dSManish Narani * for them to query. 135307a14d1dSManish Narani * 13544908460eSManish Narani * Return: 0 on success and error value on error 135507a14d1dSManish Narani */ 135607a14d1dSManish Narani static int 135707a14d1dSManish Narani sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, 135807a14d1dSManish Narani struct clk *clk_xin, 135907a14d1dSManish Narani struct device *dev) 136007a14d1dSManish Narani { 136107a14d1dSManish Narani struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 136207a14d1dSManish Narani struct device_node *np = dev->of_node; 136307a14d1dSManish Narani struct clk_init_data sampleclk_init; 136407a14d1dSManish Narani const char *parent_clk_name; 136507a14d1dSManish Narani int ret; 136607a14d1dSManish Narani 136707a14d1dSManish Narani ret = of_property_read_string_index(np, "clock-output-names", 1, 136807a14d1dSManish Narani &sampleclk_init.name); 136907a14d1dSManish Narani if (ret) { 137007a14d1dSManish Narani dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 137107a14d1dSManish Narani return ret; 137207a14d1dSManish Narani } 137307a14d1dSManish Narani 137407a14d1dSManish Narani parent_clk_name = __clk_get_name(clk_xin); 137507a14d1dSManish Narani sampleclk_init.parent_names = &parent_clk_name; 137607a14d1dSManish Narani sampleclk_init.num_parents = 1; 137707a14d1dSManish Narani sampleclk_init.flags = CLK_GET_RATE_NOCACHE; 137816ada730SManish Narani sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops; 137907a14d1dSManish Narani 138007a14d1dSManish Narani clk_data->sampleclk_hw.init = &sampleclk_init; 138107a14d1dSManish Narani clk_data->sampleclk = 138207a14d1dSManish Narani devm_clk_register(dev, &clk_data->sampleclk_hw); 1383c99e1d0cSChuhong Yuan if (IS_ERR(clk_data->sampleclk)) 1384c99e1d0cSChuhong Yuan return PTR_ERR(clk_data->sampleclk); 138507a14d1dSManish Narani clk_data->sampleclk_hw.init = NULL; 138607a14d1dSManish Narani 138707a14d1dSManish Narani ret = of_clk_add_provider(np, of_clk_src_simple_get, 138807a14d1dSManish Narani clk_data->sampleclk); 138907a14d1dSManish Narani if (ret) 139007a14d1dSManish Narani dev_err(dev, "Failed to add sample clock provider\n"); 1391c390f211SDouglas Anderson 1392c390f211SDouglas Anderson return ret; 1393c390f211SDouglas Anderson } 1394c390f211SDouglas Anderson 1395c390f211SDouglas Anderson /** 1396c390f211SDouglas Anderson * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() 1397c390f211SDouglas Anderson * 13984908460eSManish Narani * @dev: Pointer to our struct device. 13994908460eSManish Narani * 1400c390f211SDouglas Anderson * Should be called any time we're exiting and sdhci_arasan_register_sdclk() 1401c390f211SDouglas Anderson * returned success. 1402c390f211SDouglas Anderson */ 1403c390f211SDouglas Anderson static void sdhci_arasan_unregister_sdclk(struct device *dev) 1404c390f211SDouglas Anderson { 1405c390f211SDouglas Anderson struct device_node *np = dev->of_node; 1406c390f211SDouglas Anderson 1407c390f211SDouglas Anderson if (!of_find_property(np, "#clock-cells", NULL)) 1408c390f211SDouglas Anderson return; 1409c390f211SDouglas Anderson 1410c390f211SDouglas Anderson of_clk_del_provider(dev->of_node); 1411c390f211SDouglas Anderson } 1412c390f211SDouglas Anderson 141307a14d1dSManish Narani /** 141436c6aadaSWan Ahmad Zainie * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support) 1415973c7c99SMuhammad Husaini Zulkifli * @host: The sdhci_host 1416973c7c99SMuhammad Husaini Zulkifli * @value: The value to write 141736c6aadaSWan Ahmad Zainie * 141836c6aadaSWan Ahmad Zainie * This should be set based on the System Address Bus. 141936c6aadaSWan Ahmad Zainie * 0: the Core supports only 32-bit System Address Bus. 142036c6aadaSWan Ahmad Zainie * 1: the Core supports 64-bit System Address Bus. 142136c6aadaSWan Ahmad Zainie * 1422973c7c99SMuhammad Husaini Zulkifli * NOTE: 1423973c7c99SMuhammad Husaini Zulkifli * For Keem Bay, it is required to clear this bit. Its default value is 1'b1. 142436c6aadaSWan Ahmad Zainie * Keem Bay does not support 64-bit access. 142536c6aadaSWan Ahmad Zainie */ 142636c6aadaSWan Ahmad Zainie static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value) 142736c6aadaSWan Ahmad Zainie { 142836c6aadaSWan Ahmad Zainie struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 142936c6aadaSWan Ahmad Zainie struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 1430db845093SMuhammad Husaini Zulkifli const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 143136c6aadaSWan Ahmad Zainie 143236c6aadaSWan Ahmad Zainie /* Having a map is optional */ 1433db845093SMuhammad Husaini Zulkifli soc_ctl_map = sdhci_arasan->soc_ctl_map; 143436c6aadaSWan Ahmad Zainie if (!soc_ctl_map) 143536c6aadaSWan Ahmad Zainie return; 143636c6aadaSWan Ahmad Zainie 143736c6aadaSWan Ahmad Zainie /* If we have a map, we expect to have a syscon */ 143836c6aadaSWan Ahmad Zainie if (!sdhci_arasan->soc_ctl_base) { 143936c6aadaSWan Ahmad Zainie pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 144036c6aadaSWan Ahmad Zainie mmc_hostname(host->mmc)); 144136c6aadaSWan Ahmad Zainie return; 144236c6aadaSWan Ahmad Zainie } 144336c6aadaSWan Ahmad Zainie 144436c6aadaSWan Ahmad Zainie sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value); 144536c6aadaSWan Ahmad Zainie } 144636c6aadaSWan Ahmad Zainie 144736c6aadaSWan Ahmad Zainie /** 144807a14d1dSManish Narani * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use 144907a14d1dSManish Narani * 14504908460eSManish Narani * @sdhci_arasan: Our private data structure. 14514908460eSManish Narani * @clk_xin: Pointer to the functional clock 14524908460eSManish Narani * @dev: Pointer to our struct device. 14534908460eSManish Narani * 145407a14d1dSManish Narani * Some PHY devices need to know what the actual card clock is. In order for 145507a14d1dSManish Narani * them to find out, we'll provide a clock through the common clock framework 145607a14d1dSManish Narani * for them to query. 145707a14d1dSManish Narani * 145807a14d1dSManish Narani * Note: without seriously re-architecting SDHCI's clock code and testing on 145907a14d1dSManish Narani * all platforms, there's no way to create a totally beautiful clock here 146007a14d1dSManish Narani * with all clock ops implemented. Instead, we'll just create a clock that can 146107a14d1dSManish Narani * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock 146207a14d1dSManish Narani * framework that we're doing things behind its back. This should be sufficient 146307a14d1dSManish Narani * to create nice clean device tree bindings and later (if needed) we can try 146407a14d1dSManish Narani * re-architecting SDHCI if we see some benefit to it. 146507a14d1dSManish Narani * 14664908460eSManish Narani * Return: 0 on success and error value on error 146707a14d1dSManish Narani */ 146807a14d1dSManish Narani static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, 146907a14d1dSManish Narani struct clk *clk_xin, 147007a14d1dSManish Narani struct device *dev) 147107a14d1dSManish Narani { 147207a14d1dSManish Narani struct device_node *np = dev->of_node; 147307a14d1dSManish Narani u32 num_clks = 0; 147407a14d1dSManish Narani int ret; 147507a14d1dSManish Narani 147607a14d1dSManish Narani /* Providing a clock to the PHY is optional; no error if missing */ 147707a14d1dSManish Narani if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0) 147807a14d1dSManish Narani return 0; 147907a14d1dSManish Narani 148007a14d1dSManish Narani ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev); 148107a14d1dSManish Narani if (ret) 148207a14d1dSManish Narani return ret; 148307a14d1dSManish Narani 148407a14d1dSManish Narani if (num_clks) { 148507a14d1dSManish Narani ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin, 148607a14d1dSManish Narani dev); 148707a14d1dSManish Narani if (ret) { 148807a14d1dSManish Narani sdhci_arasan_unregister_sdclk(dev); 148907a14d1dSManish Narani return ret; 149007a14d1dSManish Narani } 149107a14d1dSManish Narani } 149207a14d1dSManish Narani 149307a14d1dSManish Narani return 0; 149407a14d1dSManish Narani } 149507a14d1dSManish Narani 149684362d79SShawn Lin static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan) 149784362d79SShawn Lin { 149884362d79SShawn Lin struct sdhci_host *host = sdhci_arasan->host; 149984362d79SShawn Lin struct cqhci_host *cq_host; 150084362d79SShawn Lin bool dma64; 150184362d79SShawn Lin int ret; 150284362d79SShawn Lin 150384362d79SShawn Lin if (!sdhci_arasan->has_cqe) 150484362d79SShawn Lin return sdhci_add_host(host); 150584362d79SShawn Lin 150684362d79SShawn Lin ret = sdhci_setup_host(host); 150784362d79SShawn Lin if (ret) 150884362d79SShawn Lin return ret; 150984362d79SShawn Lin 151084362d79SShawn Lin cq_host = devm_kzalloc(host->mmc->parent, 151184362d79SShawn Lin sizeof(*cq_host), GFP_KERNEL); 151284362d79SShawn Lin if (!cq_host) { 151384362d79SShawn Lin ret = -ENOMEM; 151484362d79SShawn Lin goto cleanup; 151584362d79SShawn Lin } 151684362d79SShawn Lin 151784362d79SShawn Lin cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR; 151884362d79SShawn Lin cq_host->ops = &sdhci_arasan_cqhci_ops; 151984362d79SShawn Lin 152084362d79SShawn Lin dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 152184362d79SShawn Lin if (dma64) 152284362d79SShawn Lin cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 152384362d79SShawn Lin 152484362d79SShawn Lin ret = cqhci_init(cq_host, host->mmc, dma64); 152584362d79SShawn Lin if (ret) 152684362d79SShawn Lin goto cleanup; 152784362d79SShawn Lin 152884362d79SShawn Lin ret = __sdhci_add_host(host); 152984362d79SShawn Lin if (ret) 153084362d79SShawn Lin goto cleanup; 153184362d79SShawn Lin 153284362d79SShawn Lin return 0; 153384362d79SShawn Lin 153484362d79SShawn Lin cleanup: 153584362d79SShawn Lin sdhci_cleanup_host(host); 153684362d79SShawn Lin return ret; 153784362d79SShawn Lin } 153884362d79SShawn Lin 1539e3ec3a3dSSoren Brinkmann static int sdhci_arasan_probe(struct platform_device *pdev) 1540e3ec3a3dSSoren Brinkmann { 1541e3ec3a3dSSoren Brinkmann int ret; 15423ea4666eSDouglas Anderson struct device_node *node; 1543e3ec3a3dSSoren Brinkmann struct clk *clk_xin; 1544e3ec3a3dSSoren Brinkmann struct sdhci_host *host; 1545e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host; 15462ff0b85dSMuhammad Husaini Zulkifli struct device *dev = &pdev->dev; 15472ff0b85dSMuhammad Husaini Zulkifli struct device_node *np = dev->of_node; 1548e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data *sdhci_arasan; 154906b23ca0SFaiz Abbas const struct sdhci_arasan_of_data *data; 1550e3ec3a3dSSoren Brinkmann 15512ff0b85dSMuhammad Husaini Zulkifli data = of_device_get_match_data(dev); 155206b23ca0SFaiz Abbas host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan)); 155384362d79SShawn Lin 155489211418SJisheng Zhang if (IS_ERR(host)) 155589211418SJisheng Zhang return PTR_ERR(host); 155689211418SJisheng Zhang 155789211418SJisheng Zhang pltfm_host = sdhci_priv(host); 155889211418SJisheng Zhang sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 1559c390f211SDouglas Anderson sdhci_arasan->host = host; 1560e3ec3a3dSSoren Brinkmann 156106b23ca0SFaiz Abbas sdhci_arasan->soc_ctl_map = data->soc_ctl_map; 156216ada730SManish Narani sdhci_arasan->clk_ops = data->clk_ops; 15633ea4666eSDouglas Anderson 156480d41efeSMuhammad Husaini Zulkifli node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0); 15653ea4666eSDouglas Anderson if (node) { 15663ea4666eSDouglas Anderson sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node); 15673ea4666eSDouglas Anderson of_node_put(node); 15683ea4666eSDouglas Anderson 15693ea4666eSDouglas Anderson if (IS_ERR(sdhci_arasan->soc_ctl_base)) { 15702ff0b85dSMuhammad Husaini Zulkifli ret = dev_err_probe(dev, 157172ea817dSKrzysztof Kozlowski PTR_ERR(sdhci_arasan->soc_ctl_base), 157272ea817dSKrzysztof Kozlowski "Can't get syscon\n"); 15733ea4666eSDouglas Anderson goto err_pltfm_free; 15743ea4666eSDouglas Anderson } 15753ea4666eSDouglas Anderson } 15763ea4666eSDouglas Anderson 1577b2af3227SRashmi A sdhci_get_of_property(pdev); 1578b2af3227SRashmi A 15792ff0b85dSMuhammad Husaini Zulkifli sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb"); 1580e3ec3a3dSSoren Brinkmann if (IS_ERR(sdhci_arasan->clk_ahb)) { 1581ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb), 1582ffd68f35SMuhammad Husaini Zulkifli "clk_ahb clock not found.\n"); 1583278d0962SShawn Lin goto err_pltfm_free; 1584e3ec3a3dSSoren Brinkmann } 1585e3ec3a3dSSoren Brinkmann 15862ff0b85dSMuhammad Husaini Zulkifli clk_xin = devm_clk_get(dev, "clk_xin"); 1587e3ec3a3dSSoren Brinkmann if (IS_ERR(clk_xin)) { 1588ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n"); 1589278d0962SShawn Lin goto err_pltfm_free; 1590e3ec3a3dSSoren Brinkmann } 1591e3ec3a3dSSoren Brinkmann 1592e3ec3a3dSSoren Brinkmann ret = clk_prepare_enable(sdhci_arasan->clk_ahb); 1593e3ec3a3dSSoren Brinkmann if (ret) { 15942ff0b85dSMuhammad Husaini Zulkifli dev_err(dev, "Unable to enable AHB clock.\n"); 1595278d0962SShawn Lin goto err_pltfm_free; 1596e3ec3a3dSSoren Brinkmann } 1597e3ec3a3dSSoren Brinkmann 1598b2af3227SRashmi A /* If clock-frequency property is set, use the provided value */ 1599b2af3227SRashmi A if (pltfm_host->clock && 1600b2af3227SRashmi A pltfm_host->clock != clk_get_rate(clk_xin)) { 1601b2af3227SRashmi A ret = clk_set_rate(clk_xin, pltfm_host->clock); 1602b2af3227SRashmi A if (ret) { 1603b2af3227SRashmi A dev_err(&pdev->dev, "Failed to set SD clock rate\n"); 1604b2af3227SRashmi A goto clk_dis_ahb; 1605b2af3227SRashmi A } 1606b2af3227SRashmi A } 1607b2af3227SRashmi A 1608e3ec3a3dSSoren Brinkmann ret = clk_prepare_enable(clk_xin); 1609e3ec3a3dSSoren Brinkmann if (ret) { 16102ff0b85dSMuhammad Husaini Zulkifli dev_err(dev, "Unable to enable SD clock.\n"); 1611e3ec3a3dSSoren Brinkmann goto clk_dis_ahb; 1612e3ec3a3dSSoren Brinkmann } 1613e3ec3a3dSSoren Brinkmann 16143794c542SZach Brown if (of_property_read_bool(np, "xlnx,fails-without-test-cd")) 16153794c542SZach Brown sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST; 16163794c542SZach Brown 16173f2c7d5dSHelmut Grohne if (of_property_read_bool(np, "xlnx,int-clock-stable-broken")) 16183f2c7d5dSHelmut Grohne sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE; 16193f2c7d5dSHelmut Grohne 1620e3ec3a3dSSoren Brinkmann pltfm_host->clk = clk_xin; 1621e3ec3a3dSSoren Brinkmann 162280d41efeSMuhammad Husaini Zulkifli if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1")) 1623b2ca77c9SShawn Lin sdhci_arasan_update_clockmultiplier(host, 0x0); 1624b2ca77c9SShawn Lin 162536c6aadaSWan Ahmad Zainie if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || 162636c6aadaSWan Ahmad Zainie of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || 162736c6aadaSWan Ahmad Zainie of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { 162836c6aadaSWan Ahmad Zainie sdhci_arasan_update_clockmultiplier(host, 0x0); 162936c6aadaSWan Ahmad Zainie sdhci_arasan_update_support64b(host, 0x0); 163036c6aadaSWan Ahmad Zainie 163136c6aadaSWan Ahmad Zainie host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; 163236c6aadaSWan Ahmad Zainie } 163336c6aadaSWan Ahmad Zainie 16343ea4666eSDouglas Anderson sdhci_arasan_update_baseclkfreq(host); 16353ea4666eSDouglas Anderson 16362ff0b85dSMuhammad Husaini Zulkifli ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev); 1637c390f211SDouglas Anderson if (ret) 1638c390f211SDouglas Anderson goto clk_disable_all; 1639c390f211SDouglas Anderson 1640a5c8b2aeSManish Narani if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { 16418d2e3343SManish Narani host->mmc_host_ops.execute_tuning = 16428d2e3343SManish Narani arasan_zynqmp_execute_tuning; 1643c0b4e411SManish Narani 1644c0b4e411SManish Narani sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN; 164525a91664SManish Narani host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; 1646a5c8b2aeSManish Narani } 1647a5c8b2aeSManish Narani 16482ff0b85dSMuhammad Husaini Zulkifli arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data); 1649f3dafc37SManish Narani 165016b23787SMichal Simek ret = mmc_of_parse(host->mmc); 165116b23787SMichal Simek if (ret) { 1652ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, ret, "parsing dt failed.\n"); 1653c390f211SDouglas Anderson goto unreg_clk; 165416b23787SMichal Simek } 165516b23787SMichal Simek 165691aa3661SShawn Lin sdhci_arasan->phy = ERR_PTR(-ENODEV); 165780d41efeSMuhammad Husaini Zulkifli if (of_device_is_compatible(np, "arasan,sdhci-5.1")) { 16582ff0b85dSMuhammad Husaini Zulkifli sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan"); 165991aa3661SShawn Lin if (IS_ERR(sdhci_arasan->phy)) { 1660ffd68f35SMuhammad Husaini Zulkifli ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->phy), 1661ffd68f35SMuhammad Husaini Zulkifli "No phy for arasan,sdhci-5.1.\n"); 1662c390f211SDouglas Anderson goto unreg_clk; 166391aa3661SShawn Lin } 166491aa3661SShawn Lin 166591aa3661SShawn Lin ret = phy_init(sdhci_arasan->phy); 166691aa3661SShawn Lin if (ret < 0) { 16672ff0b85dSMuhammad Husaini Zulkifli dev_err(dev, "phy_init err.\n"); 1668c390f211SDouglas Anderson goto unreg_clk; 166991aa3661SShawn Lin } 167091aa3661SShawn Lin 1671a05c8465SShawn Lin host->mmc_host_ops.hs400_enhanced_strobe = 1672a05c8465SShawn Lin sdhci_arasan_hs400_enhanced_strobe; 16738a3bee9bSShawn Lin host->mmc_host_ops.start_signal_voltage_switch = 16748a3bee9bSShawn Lin sdhci_arasan_voltage_switch; 167584362d79SShawn Lin sdhci_arasan->has_cqe = true; 16767bda9482SChristoph Muellner host->mmc->caps2 |= MMC_CAP2_CQE; 16777bda9482SChristoph Muellner 16787bda9482SChristoph Muellner if (!of_property_read_bool(np, "disable-cqe-dcmd")) 16797bda9482SChristoph Muellner host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; 168091aa3661SShawn Lin } 168191aa3661SShawn Lin 168284362d79SShawn Lin ret = sdhci_arasan_add_host(sdhci_arasan); 1683b1df9de7SMike Looijmans if (ret) 168491aa3661SShawn Lin goto err_add_host; 1685e3ec3a3dSSoren Brinkmann 1686e3ec3a3dSSoren Brinkmann return 0; 1687e3ec3a3dSSoren Brinkmann 168891aa3661SShawn Lin err_add_host: 168991aa3661SShawn Lin if (!IS_ERR(sdhci_arasan->phy)) 169091aa3661SShawn Lin phy_exit(sdhci_arasan->phy); 1691c390f211SDouglas Anderson unreg_clk: 16922ff0b85dSMuhammad Husaini Zulkifli sdhci_arasan_unregister_sdclk(dev); 1693e3ec3a3dSSoren Brinkmann clk_disable_all: 1694e3ec3a3dSSoren Brinkmann clk_disable_unprepare(clk_xin); 1695e3ec3a3dSSoren Brinkmann clk_dis_ahb: 1696e3ec3a3dSSoren Brinkmann clk_disable_unprepare(sdhci_arasan->clk_ahb); 1697278d0962SShawn Lin err_pltfm_free: 1698278d0962SShawn Lin sdhci_pltfm_free(pdev); 1699e3ec3a3dSSoren Brinkmann return ret; 1700e3ec3a3dSSoren Brinkmann } 1701e3ec3a3dSSoren Brinkmann 1702e3ec3a3dSSoren Brinkmann static int sdhci_arasan_remove(struct platform_device *pdev) 1703e3ec3a3dSSoren Brinkmann { 17040c7fe32eSJisheng Zhang int ret; 1705e3ec3a3dSSoren Brinkmann struct sdhci_host *host = platform_get_drvdata(pdev); 1706e3ec3a3dSSoren Brinkmann struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 170789211418SJisheng Zhang struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 170889211418SJisheng Zhang struct clk *clk_ahb = sdhci_arasan->clk_ahb; 1709e3ec3a3dSSoren Brinkmann 171091aa3661SShawn Lin if (!IS_ERR(sdhci_arasan->phy)) { 1711b2db9c67SDouglas Anderson if (sdhci_arasan->is_phy_on) 171291aa3661SShawn Lin phy_power_off(sdhci_arasan->phy); 171391aa3661SShawn Lin phy_exit(sdhci_arasan->phy); 171491aa3661SShawn Lin } 171591aa3661SShawn Lin 1716c390f211SDouglas Anderson sdhci_arasan_unregister_sdclk(&pdev->dev); 1717c390f211SDouglas Anderson 17180c7fe32eSJisheng Zhang ret = sdhci_pltfm_unregister(pdev); 17190c7fe32eSJisheng Zhang 172089211418SJisheng Zhang clk_disable_unprepare(clk_ahb); 1721e3ec3a3dSSoren Brinkmann 17220c7fe32eSJisheng Zhang return ret; 1723e3ec3a3dSSoren Brinkmann } 1724e3ec3a3dSSoren Brinkmann 1725e3ec3a3dSSoren Brinkmann static struct platform_driver sdhci_arasan_driver = { 1726e3ec3a3dSSoren Brinkmann .driver = { 1727e3ec3a3dSSoren Brinkmann .name = "sdhci-arasan", 172821b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1729e3ec3a3dSSoren Brinkmann .of_match_table = sdhci_arasan_of_match, 1730e3ec3a3dSSoren Brinkmann .pm = &sdhci_arasan_dev_pm_ops, 1731e3ec3a3dSSoren Brinkmann }, 1732e3ec3a3dSSoren Brinkmann .probe = sdhci_arasan_probe, 1733e3ec3a3dSSoren Brinkmann .remove = sdhci_arasan_remove, 1734e3ec3a3dSSoren Brinkmann }; 1735e3ec3a3dSSoren Brinkmann 1736e3ec3a3dSSoren Brinkmann module_platform_driver(sdhci_arasan_driver); 1737e3ec3a3dSSoren Brinkmann 1738e3ec3a3dSSoren Brinkmann MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller"); 1739e3ec3a3dSSoren Brinkmann MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>"); 1740e3ec3a3dSSoren Brinkmann MODULE_LICENSE("GPL"); 1741