14cdc2ec1Saddy ke /* 24cdc2ec1Saddy ke * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 34cdc2ec1Saddy ke * 44cdc2ec1Saddy ke * This program is free software; you can redistribute it and/or modify 54cdc2ec1Saddy ke * it under the terms of the GNU General Public License as published by 64cdc2ec1Saddy ke * the Free Software Foundation; either version 2 of the License, or 74cdc2ec1Saddy ke * (at your option) any later version. 84cdc2ec1Saddy ke */ 94cdc2ec1Saddy ke 104cdc2ec1Saddy ke #include <linux/module.h> 114cdc2ec1Saddy ke #include <linux/platform_device.h> 124cdc2ec1Saddy ke #include <linux/clk.h> 134cdc2ec1Saddy ke #include <linux/mmc/host.h> 144cdc2ec1Saddy ke #include <linux/mmc/dw_mmc.h> 154cdc2ec1Saddy ke #include <linux/of_address.h> 16cbb79e43SAlexandru M Stan #include <linux/slab.h> 174cdc2ec1Saddy ke 184cdc2ec1Saddy ke #include "dw_mmc.h" 194cdc2ec1Saddy ke #include "dw_mmc-pltfm.h" 204cdc2ec1Saddy ke 214cdc2ec1Saddy ke #define RK3288_CLKGEN_DIV 2 224cdc2ec1Saddy ke 23cbb79e43SAlexandru M Stan struct dw_mci_rockchip_priv_data { 24cbb79e43SAlexandru M Stan struct clk *drv_clk; 25cbb79e43SAlexandru M Stan struct clk *sample_clk; 26cbb79e43SAlexandru M Stan int default_sample_phase; 27cbb79e43SAlexandru M Stan }; 28cbb79e43SAlexandru M Stan 294cdc2ec1Saddy ke static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) 304cdc2ec1Saddy ke { 31cbb79e43SAlexandru M Stan struct dw_mci_rockchip_priv_data *priv = host->priv; 324cdc2ec1Saddy ke int ret; 334cdc2ec1Saddy ke unsigned int cclkin; 344cdc2ec1Saddy ke u32 bus_hz; 354cdc2ec1Saddy ke 36e7791079SDoug Anderson if (ios->clock == 0) 37e7791079SDoug Anderson return; 38e7791079SDoug Anderson 394cdc2ec1Saddy ke /* 404cdc2ec1Saddy ke * cclkin: source clock of mmc controller 414cdc2ec1Saddy ke * bus_hz: card interface clock generated by CLKGEN 424cdc2ec1Saddy ke * bus_hz = cclkin / RK3288_CLKGEN_DIV 434cdc2ec1Saddy ke * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div)) 444cdc2ec1Saddy ke * 454cdc2ec1Saddy ke * Note: div can only be 0 or 1 464cdc2ec1Saddy ke * if DDR50 8bit mode(only emmc work in 8bit mode), 474cdc2ec1Saddy ke * div must be set 1 484cdc2ec1Saddy ke */ 494cdc2ec1Saddy ke if (ios->bus_width == MMC_BUS_WIDTH_8 && 504cdc2ec1Saddy ke ios->timing == MMC_TIMING_MMC_DDR52) 514cdc2ec1Saddy ke cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV; 524cdc2ec1Saddy ke else 534cdc2ec1Saddy ke cclkin = ios->clock * RK3288_CLKGEN_DIV; 544cdc2ec1Saddy ke 554cdc2ec1Saddy ke ret = clk_set_rate(host->ciu_clk, cclkin); 564cdc2ec1Saddy ke if (ret) 574cdc2ec1Saddy ke dev_warn(host->dev, "failed to set rate %uHz\n", ios->clock); 584cdc2ec1Saddy ke 594cdc2ec1Saddy ke bus_hz = clk_get_rate(host->ciu_clk) / RK3288_CLKGEN_DIV; 604cdc2ec1Saddy ke if (bus_hz != host->bus_hz) { 614cdc2ec1Saddy ke host->bus_hz = bus_hz; 624cdc2ec1Saddy ke /* force dw_mci_setup_bus() */ 634cdc2ec1Saddy ke host->current_speed = 0; 644cdc2ec1Saddy ke } 65cbb79e43SAlexandru M Stan 66cbb79e43SAlexandru M Stan /* Make sure we use phases which we can enumerate with */ 67cbb79e43SAlexandru M Stan if (!IS_ERR(priv->sample_clk)) 68cbb79e43SAlexandru M Stan clk_set_phase(priv->sample_clk, priv->default_sample_phase); 69d4aa908cSDouglas Anderson 70d4aa908cSDouglas Anderson /* 71d4aa908cSDouglas Anderson * Set the drive phase offset based on speed mode to achieve hold times. 72d4aa908cSDouglas Anderson * 73d4aa908cSDouglas Anderson * NOTE: this is _not_ a value that is dynamically tuned and is also 74d4aa908cSDouglas Anderson * _not_ a value that will vary from board to board. It is a value 75d4aa908cSDouglas Anderson * that could vary between different SoC models if they had massively 76d4aa908cSDouglas Anderson * different output clock delays inside their dw_mmc IP block (delay_o), 77d4aa908cSDouglas Anderson * but since it's OK to overshoot a little we don't need to do complex 78d4aa908cSDouglas Anderson * calculations and can pick values that will just work for everyone. 79d4aa908cSDouglas Anderson * 80d4aa908cSDouglas Anderson * When picking values we'll stick with picking 0/90/180/270 since 81d4aa908cSDouglas Anderson * those can be made very accurately on all known Rockchip SoCs. 82d4aa908cSDouglas Anderson * 83d4aa908cSDouglas Anderson * Note that these values match values from the DesignWare Databook 84d4aa908cSDouglas Anderson * tables for the most part except for SDR12 and "ID mode". For those 85d4aa908cSDouglas Anderson * two modes the databook calculations assume a clock in of 50MHz. As 86d4aa908cSDouglas Anderson * seen above, we always use a clock in rate that is exactly the 87d4aa908cSDouglas Anderson * card's input clock (times RK3288_CLKGEN_DIV, but that gets divided 88d4aa908cSDouglas Anderson * back out before the controller sees it). 89d4aa908cSDouglas Anderson * 90d4aa908cSDouglas Anderson * From measurement of a single device, it appears that delay_o is 91d4aa908cSDouglas Anderson * about .5 ns. Since we try to leave a bit of margin, it's expected 92d4aa908cSDouglas Anderson * that numbers here will be fine even with much larger delay_o 93d4aa908cSDouglas Anderson * (the 1.4 ns assumed by the DesignWare Databook would result in the 94d4aa908cSDouglas Anderson * same results, for instance). 95d4aa908cSDouglas Anderson */ 96d4aa908cSDouglas Anderson if (!IS_ERR(priv->drv_clk)) { 97d4aa908cSDouglas Anderson int phase; 98d4aa908cSDouglas Anderson 99d4aa908cSDouglas Anderson /* 100d4aa908cSDouglas Anderson * In almost all cases a 90 degree phase offset will provide 101d4aa908cSDouglas Anderson * sufficient hold times across all valid input clock rates 102d4aa908cSDouglas Anderson * assuming delay_o is not absurd for a given SoC. We'll use 103d4aa908cSDouglas Anderson * that as a default. 104d4aa908cSDouglas Anderson */ 105d4aa908cSDouglas Anderson phase = 90; 106d4aa908cSDouglas Anderson 107d4aa908cSDouglas Anderson switch (ios->timing) { 108d4aa908cSDouglas Anderson case MMC_TIMING_MMC_DDR52: 109d4aa908cSDouglas Anderson /* 110d4aa908cSDouglas Anderson * Since clock in rate with MMC_DDR52 is doubled when 111d4aa908cSDouglas Anderson * bus width is 8 we need to double the phase offset 112d4aa908cSDouglas Anderson * to get the same timings. 113d4aa908cSDouglas Anderson */ 114d4aa908cSDouglas Anderson if (ios->bus_width == MMC_BUS_WIDTH_8) 115d4aa908cSDouglas Anderson phase = 180; 116d4aa908cSDouglas Anderson break; 117d4aa908cSDouglas Anderson case MMC_TIMING_UHS_SDR104: 118d4aa908cSDouglas Anderson case MMC_TIMING_MMC_HS200: 119d4aa908cSDouglas Anderson /* 120d4aa908cSDouglas Anderson * In the case of 150 MHz clock (typical max for 121d4aa908cSDouglas Anderson * Rockchip SoCs), 90 degree offset will add a delay 122d4aa908cSDouglas Anderson * of 1.67 ns. That will meet min hold time of .8 ns 123d4aa908cSDouglas Anderson * as long as clock output delay is < .87 ns. On 124d4aa908cSDouglas Anderson * SoCs measured this seems to be OK, but it doesn't 125d4aa908cSDouglas Anderson * hurt to give margin here, so we use 180. 126d4aa908cSDouglas Anderson */ 127d4aa908cSDouglas Anderson phase = 180; 128d4aa908cSDouglas Anderson break; 129d4aa908cSDouglas Anderson } 130d4aa908cSDouglas Anderson 131d4aa908cSDouglas Anderson clk_set_phase(priv->drv_clk, phase); 132d4aa908cSDouglas Anderson } 133cbb79e43SAlexandru M Stan } 134cbb79e43SAlexandru M Stan 135cbb79e43SAlexandru M Stan #define NUM_PHASES 360 136cbb79e43SAlexandru M Stan #define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES)) 137cbb79e43SAlexandru M Stan 1389979dbe5SChaotian Jing static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) 139cbb79e43SAlexandru M Stan { 140cbb79e43SAlexandru M Stan struct dw_mci *host = slot->host; 141cbb79e43SAlexandru M Stan struct dw_mci_rockchip_priv_data *priv = host->priv; 142cbb79e43SAlexandru M Stan struct mmc_host *mmc = slot->mmc; 143cbb79e43SAlexandru M Stan int ret = 0; 144cbb79e43SAlexandru M Stan int i; 145cbb79e43SAlexandru M Stan bool v, prev_v = 0, first_v; 146cbb79e43SAlexandru M Stan struct range_t { 147cbb79e43SAlexandru M Stan int start; 148cbb79e43SAlexandru M Stan int end; /* inclusive */ 149cbb79e43SAlexandru M Stan }; 150cbb79e43SAlexandru M Stan struct range_t *ranges; 151cbb79e43SAlexandru M Stan unsigned int range_count = 0; 152cbb79e43SAlexandru M Stan int longest_range_len = -1; 153cbb79e43SAlexandru M Stan int longest_range = -1; 154cbb79e43SAlexandru M Stan int middle_phase; 155cbb79e43SAlexandru M Stan 156cbb79e43SAlexandru M Stan if (IS_ERR(priv->sample_clk)) { 157cbb79e43SAlexandru M Stan dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n"); 158cbb79e43SAlexandru M Stan return -EIO; 159cbb79e43SAlexandru M Stan } 160cbb79e43SAlexandru M Stan 161cbb79e43SAlexandru M Stan ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL); 162cbb79e43SAlexandru M Stan if (!ranges) 163cbb79e43SAlexandru M Stan return -ENOMEM; 164cbb79e43SAlexandru M Stan 165cbb79e43SAlexandru M Stan /* Try each phase and extract good ranges */ 166cbb79e43SAlexandru M Stan for (i = 0; i < NUM_PHASES; ) { 167cbb79e43SAlexandru M Stan clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i)); 168cbb79e43SAlexandru M Stan 1699979dbe5SChaotian Jing v = !mmc_send_tuning(mmc, opcode, NULL); 170cbb79e43SAlexandru M Stan 171cbb79e43SAlexandru M Stan if (i == 0) 172cbb79e43SAlexandru M Stan first_v = v; 173cbb79e43SAlexandru M Stan 174cbb79e43SAlexandru M Stan if ((!prev_v) && v) { 175cbb79e43SAlexandru M Stan range_count++; 176cbb79e43SAlexandru M Stan ranges[range_count-1].start = i; 177cbb79e43SAlexandru M Stan } 178cbb79e43SAlexandru M Stan if (v) { 179cbb79e43SAlexandru M Stan ranges[range_count-1].end = i; 180cbb79e43SAlexandru M Stan i++; 181cbb79e43SAlexandru M Stan } else if (i == NUM_PHASES - 1) { 182cbb79e43SAlexandru M Stan /* No extra skipping rules if we're at the end */ 183cbb79e43SAlexandru M Stan i++; 184cbb79e43SAlexandru M Stan } else { 185cbb79e43SAlexandru M Stan /* 186cbb79e43SAlexandru M Stan * No need to check too close to an invalid 187cbb79e43SAlexandru M Stan * one since testing bad phases is slow. Skip 188cbb79e43SAlexandru M Stan * 20 degrees. 189cbb79e43SAlexandru M Stan */ 190cbb79e43SAlexandru M Stan i += DIV_ROUND_UP(20 * NUM_PHASES, 360); 191cbb79e43SAlexandru M Stan 192cbb79e43SAlexandru M Stan /* Always test the last one */ 193cbb79e43SAlexandru M Stan if (i >= NUM_PHASES) 194cbb79e43SAlexandru M Stan i = NUM_PHASES - 1; 195cbb79e43SAlexandru M Stan } 196cbb79e43SAlexandru M Stan 197cbb79e43SAlexandru M Stan prev_v = v; 198cbb79e43SAlexandru M Stan } 199cbb79e43SAlexandru M Stan 200cbb79e43SAlexandru M Stan if (range_count == 0) { 201cbb79e43SAlexandru M Stan dev_warn(host->dev, "All phases bad!"); 202cbb79e43SAlexandru M Stan ret = -EIO; 203cbb79e43SAlexandru M Stan goto free; 204cbb79e43SAlexandru M Stan } 205cbb79e43SAlexandru M Stan 206cbb79e43SAlexandru M Stan /* wrap around case, merge the end points */ 207cbb79e43SAlexandru M Stan if ((range_count > 1) && first_v && v) { 208cbb79e43SAlexandru M Stan ranges[0].start = ranges[range_count-1].start; 209cbb79e43SAlexandru M Stan range_count--; 210cbb79e43SAlexandru M Stan } 211cbb79e43SAlexandru M Stan 212cbb79e43SAlexandru M Stan if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) { 213cbb79e43SAlexandru M Stan clk_set_phase(priv->sample_clk, priv->default_sample_phase); 214cbb79e43SAlexandru M Stan dev_info(host->dev, "All phases work, using default phase %d.", 215cbb79e43SAlexandru M Stan priv->default_sample_phase); 216cbb79e43SAlexandru M Stan goto free; 217cbb79e43SAlexandru M Stan } 218cbb79e43SAlexandru M Stan 219cbb79e43SAlexandru M Stan /* Find the longest range */ 220cbb79e43SAlexandru M Stan for (i = 0; i < range_count; i++) { 221cbb79e43SAlexandru M Stan int len = (ranges[i].end - ranges[i].start + 1); 222cbb79e43SAlexandru M Stan 223cbb79e43SAlexandru M Stan if (len < 0) 224cbb79e43SAlexandru M Stan len += NUM_PHASES; 225cbb79e43SAlexandru M Stan 226cbb79e43SAlexandru M Stan if (longest_range_len < len) { 227cbb79e43SAlexandru M Stan longest_range_len = len; 228cbb79e43SAlexandru M Stan longest_range = i; 229cbb79e43SAlexandru M Stan } 230cbb79e43SAlexandru M Stan 231cbb79e43SAlexandru M Stan dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n", 232cbb79e43SAlexandru M Stan TUNING_ITERATION_TO_PHASE(ranges[i].start), 233cbb79e43SAlexandru M Stan TUNING_ITERATION_TO_PHASE(ranges[i].end), 234cbb79e43SAlexandru M Stan len 235cbb79e43SAlexandru M Stan ); 236cbb79e43SAlexandru M Stan } 237cbb79e43SAlexandru M Stan 238cbb79e43SAlexandru M Stan dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n", 239cbb79e43SAlexandru M Stan TUNING_ITERATION_TO_PHASE(ranges[longest_range].start), 240cbb79e43SAlexandru M Stan TUNING_ITERATION_TO_PHASE(ranges[longest_range].end), 241cbb79e43SAlexandru M Stan longest_range_len 242cbb79e43SAlexandru M Stan ); 243cbb79e43SAlexandru M Stan 244cbb79e43SAlexandru M Stan middle_phase = ranges[longest_range].start + longest_range_len / 2; 245cbb79e43SAlexandru M Stan middle_phase %= NUM_PHASES; 246cbb79e43SAlexandru M Stan dev_info(host->dev, "Successfully tuned phase to %d\n", 247cbb79e43SAlexandru M Stan TUNING_ITERATION_TO_PHASE(middle_phase)); 248cbb79e43SAlexandru M Stan 249cbb79e43SAlexandru M Stan clk_set_phase(priv->sample_clk, 250cbb79e43SAlexandru M Stan TUNING_ITERATION_TO_PHASE(middle_phase)); 251cbb79e43SAlexandru M Stan 252cbb79e43SAlexandru M Stan free: 253cbb79e43SAlexandru M Stan kfree(ranges); 254cbb79e43SAlexandru M Stan return ret; 255cbb79e43SAlexandru M Stan } 256cbb79e43SAlexandru M Stan 257cbb79e43SAlexandru M Stan static int dw_mci_rk3288_parse_dt(struct dw_mci *host) 258cbb79e43SAlexandru M Stan { 259cbb79e43SAlexandru M Stan struct device_node *np = host->dev->of_node; 260cbb79e43SAlexandru M Stan struct dw_mci_rockchip_priv_data *priv; 261cbb79e43SAlexandru M Stan 262cbb79e43SAlexandru M Stan priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); 263cbb79e43SAlexandru M Stan if (!priv) 264cbb79e43SAlexandru M Stan return -ENOMEM; 265cbb79e43SAlexandru M Stan 266cbb79e43SAlexandru M Stan if (of_property_read_u32(np, "rockchip,default-sample-phase", 267cbb79e43SAlexandru M Stan &priv->default_sample_phase)) 268cbb79e43SAlexandru M Stan priv->default_sample_phase = 0; 269cbb79e43SAlexandru M Stan 270cbb79e43SAlexandru M Stan priv->drv_clk = devm_clk_get(host->dev, "ciu-drive"); 271cbb79e43SAlexandru M Stan if (IS_ERR(priv->drv_clk)) 272cbb79e43SAlexandru M Stan dev_dbg(host->dev, "ciu_drv not available\n"); 273cbb79e43SAlexandru M Stan 274cbb79e43SAlexandru M Stan priv->sample_clk = devm_clk_get(host->dev, "ciu-sample"); 275cbb79e43SAlexandru M Stan if (IS_ERR(priv->sample_clk)) 276cbb79e43SAlexandru M Stan dev_dbg(host->dev, "ciu_sample not available\n"); 277cbb79e43SAlexandru M Stan 278cbb79e43SAlexandru M Stan host->priv = priv; 279cbb79e43SAlexandru M Stan 280cbb79e43SAlexandru M Stan return 0; 2814cdc2ec1Saddy ke } 2824cdc2ec1Saddy ke 28376756234SAddy Ke static int dw_mci_rockchip_init(struct dw_mci *host) 28476756234SAddy Ke { 28576756234SAddy Ke /* It is slot 8 on Rockchip SoCs */ 28676756234SAddy Ke host->sdio_id0 = 8; 28776756234SAddy Ke 28857e10486SAddy Ke /* It needs this quirk on all Rockchip SoCs */ 28957e10486SAddy Ke host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO; 29057e10486SAddy Ke 29119756760SShawn Lin if (of_device_is_compatible(host->dev->of_node, 29219756760SShawn Lin "rockchip,rk3288-dw-mshc")) 29319756760SShawn Lin host->bus_hz /= RK3288_CLKGEN_DIV; 29419756760SShawn Lin 29576756234SAddy Ke return 0; 29676756234SAddy Ke } 29776756234SAddy Ke 298c6a9bf99SShawn Lin /* Common capabilities of RK3288 SoC */ 299c6a9bf99SShawn Lin static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { 300d57fe83eSShawn Lin MMC_CAP_ERASE | MMC_CAP_CMD23, 301d57fe83eSShawn Lin MMC_CAP_ERASE | MMC_CAP_CMD23, 302d57fe83eSShawn Lin MMC_CAP_ERASE | MMC_CAP_CMD23, 303d57fe83eSShawn Lin MMC_CAP_ERASE | MMC_CAP_CMD23, 304c6a9bf99SShawn Lin }; 305c6a9bf99SShawn Lin 3064cdc2ec1Saddy ke static const struct dw_mci_drv_data rk2928_drv_data = { 30776756234SAddy Ke .init = dw_mci_rockchip_init, 3084cdc2ec1Saddy ke }; 3094cdc2ec1Saddy ke 3104cdc2ec1Saddy ke static const struct dw_mci_drv_data rk3288_drv_data = { 311c6a9bf99SShawn Lin .caps = dw_mci_rk3288_dwmmc_caps, 3124cdc2ec1Saddy ke .set_ios = dw_mci_rk3288_set_ios, 313cbb79e43SAlexandru M Stan .execute_tuning = dw_mci_rk3288_execute_tuning, 314cbb79e43SAlexandru M Stan .parse_dt = dw_mci_rk3288_parse_dt, 31576756234SAddy Ke .init = dw_mci_rockchip_init, 3164cdc2ec1Saddy ke }; 3174cdc2ec1Saddy ke 3184cdc2ec1Saddy ke static const struct of_device_id dw_mci_rockchip_match[] = { 3194cdc2ec1Saddy ke { .compatible = "rockchip,rk2928-dw-mshc", 3204cdc2ec1Saddy ke .data = &rk2928_drv_data }, 3214cdc2ec1Saddy ke { .compatible = "rockchip,rk3288-dw-mshc", 3224cdc2ec1Saddy ke .data = &rk3288_drv_data }, 3234cdc2ec1Saddy ke {}, 3244cdc2ec1Saddy ke }; 3254cdc2ec1Saddy ke MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match); 3264cdc2ec1Saddy ke 3274cdc2ec1Saddy ke static int dw_mci_rockchip_probe(struct platform_device *pdev) 3284cdc2ec1Saddy ke { 3294cdc2ec1Saddy ke const struct dw_mci_drv_data *drv_data; 3304cdc2ec1Saddy ke const struct of_device_id *match; 3314cdc2ec1Saddy ke 3324cdc2ec1Saddy ke if (!pdev->dev.of_node) 3334cdc2ec1Saddy ke return -ENODEV; 3344cdc2ec1Saddy ke 3354cdc2ec1Saddy ke match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node); 3364cdc2ec1Saddy ke drv_data = match->data; 3374cdc2ec1Saddy ke 3384cdc2ec1Saddy ke return dw_mci_pltfm_register(pdev, drv_data); 3394cdc2ec1Saddy ke } 3404cdc2ec1Saddy ke 3414cdc2ec1Saddy ke static struct platform_driver dw_mci_rockchip_pltfm_driver = { 3424cdc2ec1Saddy ke .probe = dw_mci_rockchip_probe, 34396083379SDmitry Torokhov .remove = dw_mci_pltfm_remove, 3444cdc2ec1Saddy ke .driver = { 3454cdc2ec1Saddy ke .name = "dwmmc_rockchip", 3464cdc2ec1Saddy ke .of_match_table = dw_mci_rockchip_match, 34731fa8353SShawn Lin .pm = &dw_mci_pltfm_pmops, 3484cdc2ec1Saddy ke }, 3494cdc2ec1Saddy ke }; 3504cdc2ec1Saddy ke 3514cdc2ec1Saddy ke module_platform_driver(dw_mci_rockchip_pltfm_driver); 3524cdc2ec1Saddy ke 3534cdc2ec1Saddy ke MODULE_AUTHOR("Addy Ke <addy.ke@rock-chips.com>"); 3544cdc2ec1Saddy ke MODULE_DESCRIPTION("Rockchip Specific DW-MSHC Driver Extension"); 355a7ca2b16SZhangfei Gao MODULE_ALIAS("platform:dwmmc_rockchip"); 3564cdc2ec1Saddy ke MODULE_LICENSE("GPL v2"); 357