Home | History | Annotate | Download | only in mmc
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2015 Atmel Corporation
      4  *		      Wenyou.Yang <wenyou.yang (at) atmel.com>
      5  */
      6 
      7 #include <common.h>
      8 #include <clk.h>
      9 #include <dm.h>
     10 #include <malloc.h>
     11 #include <sdhci.h>
     12 #include <asm/arch/clk.h>
     13 
     14 #define ATMEL_SDHC_MIN_FREQ	400000
     15 #define ATMEL_SDHC_GCK_RATE	240000000
     16 
     17 #ifndef CONFIG_DM_MMC
     18 int atmel_sdhci_init(void *regbase, u32 id)
     19 {
     20 	struct sdhci_host *host;
     21 	u32 max_clk, min_clk = ATMEL_SDHC_MIN_FREQ;
     22 
     23 	host = (struct sdhci_host *)calloc(1, sizeof(struct sdhci_host));
     24 	if (!host) {
     25 		printf("%s: sdhci_host calloc failed\n", __func__);
     26 		return -ENOMEM;
     27 	}
     28 
     29 	host->name = "atmel_sdhci";
     30 	host->ioaddr = regbase;
     31 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
     32 	max_clk = at91_get_periph_generated_clk(id);
     33 	if (!max_clk) {
     34 		printf("%s: Failed to get the proper clock\n", __func__);
     35 		free(host);
     36 		return -ENODEV;
     37 	}
     38 	host->max_clk = max_clk;
     39 
     40 	add_sdhci(host, 0, min_clk);
     41 
     42 	return 0;
     43 }
     44 
     45 #else
     46 
     47 DECLARE_GLOBAL_DATA_PTR;
     48 
     49 struct atmel_sdhci_plat {
     50 	struct mmc_config cfg;
     51 	struct mmc mmc;
     52 };
     53 
     54 static int atmel_sdhci_probe(struct udevice *dev)
     55 {
     56 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
     57 	struct atmel_sdhci_plat *plat = dev_get_platdata(dev);
     58 	struct sdhci_host *host = dev_get_priv(dev);
     59 	u32 max_clk;
     60 	struct clk clk;
     61 	int ret;
     62 
     63 	ret = clk_get_by_index(dev, 0, &clk);
     64 	if (ret)
     65 		return ret;
     66 
     67 	ret = clk_enable(&clk);
     68 	if (ret)
     69 		return ret;
     70 
     71 	host->name = dev->name;
     72 	host->ioaddr = (void *)devfdt_get_addr(dev);
     73 
     74 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
     75 	host->bus_width	= fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
     76 					 "bus-width", 4);
     77 
     78 	ret = clk_get_by_index(dev, 1, &clk);
     79 	if (ret)
     80 		return ret;
     81 
     82 	ret = clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
     83 	if (ret)
     84 		return ret;
     85 
     86 	max_clk = clk_get_rate(&clk);
     87 	if (!max_clk)
     88 		return -EINVAL;
     89 
     90 	host->max_clk = max_clk;
     91 
     92 	ret = sdhci_setup_cfg(&plat->cfg, host, 0, ATMEL_SDHC_MIN_FREQ);
     93 	if (ret)
     94 		return ret;
     95 
     96 	host->mmc = &plat->mmc;
     97 	host->mmc->dev = dev;
     98 	host->mmc->priv = host;
     99 	upriv->mmc = host->mmc;
    100 
    101 	clk_free(&clk);
    102 
    103 	return sdhci_probe(dev);
    104 }
    105 
    106 static int atmel_sdhci_bind(struct udevice *dev)
    107 {
    108 	struct atmel_sdhci_plat *plat = dev_get_platdata(dev);
    109 
    110 	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
    111 }
    112 
    113 static const struct udevice_id atmel_sdhci_ids[] = {
    114 	{ .compatible = "atmel,sama5d2-sdhci" },
    115 	{ }
    116 };
    117 
    118 U_BOOT_DRIVER(atmel_sdhci_drv) = {
    119 	.name		= "atmel_sdhci",
    120 	.id		= UCLASS_MMC,
    121 	.of_match	= atmel_sdhci_ids,
    122 	.ops		= &sdhci_ops,
    123 	.bind		= atmel_sdhci_bind,
    124 	.probe		= atmel_sdhci_probe,
    125 	.priv_auto_alloc_size = sizeof(struct sdhci_host),
    126 	.platdata_auto_alloc_size = sizeof(struct atmel_sdhci_plat),
    127 };
    128 #endif
    129