]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/mmc/atmel_sdhci.c
Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
[thirdparty/u-boot.git] / drivers / mmc / atmel_sdhci.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
a3b59b15
WY
2/*
3 * Copyright (C) 2015 Atmel Corporation
4 * Wenyou.Yang <wenyou.yang@atmel.com>
a3b59b15
WY
5 */
6
d678a59d 7#include <common.h>
a0d0d86f
WY
8#include <clk.h>
9#include <dm.h>
a3b59b15
WY
10#include <malloc.h>
11#include <sdhci.h>
12#include <asm/arch/clk.h>
401d1c4f 13#include <asm/global_data.h>
a3b59b15
WY
14
15#define ATMEL_SDHC_MIN_FREQ 400000
327713a6 16#define ATMEL_SDHC_GCK_RATE 240000000
a3b59b15 17
e83b6f99
ZL
18#define ATMEL_SDHC_MC1R 0x204
19#define ATMEL_SDHC_MC1R_FCD 0x80
20
a0d0d86f 21#ifndef CONFIG_DM_MMC
a3b59b15
WY
22int atmel_sdhci_init(void *regbase, u32 id)
23{
24 struct sdhci_host *host;
25 u32 max_clk, min_clk = ATMEL_SDHC_MIN_FREQ;
26
27 host = (struct sdhci_host *)calloc(1, sizeof(struct sdhci_host));
28 if (!host) {
29 printf("%s: sdhci_host calloc failed\n", __func__);
30 return -ENOMEM;
31 }
32
33 host->name = "atmel_sdhci";
34 host->ioaddr = regbase;
b3125088 35 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
a3b59b15
WY
36 max_clk = at91_get_periph_generated_clk(id);
37 if (!max_clk) {
38 printf("%s: Failed to get the proper clock\n", __func__);
39 free(host);
40 return -ENODEV;
41 }
6d0e34bf 42 host->max_clk = max_clk;
a3b59b15 43
6d0e34bf 44 add_sdhci(host, 0, min_clk);
a3b59b15
WY
45
46 return 0;
47}
a0d0d86f
WY
48
49#else
50
51DECLARE_GLOBAL_DATA_PTR;
52
53struct atmel_sdhci_plat {
54 struct mmc_config cfg;
55 struct mmc mmc;
56};
57
e83b6f99
ZL
58static void atmel_sdhci_config_fcd(struct sdhci_host *host)
59{
60 u8 mc1r;
61
62 /* If nonremovable, assume that the card is always present.
63 *
64 * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
65 */
66 if ((host->mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
67#if CONFIG_IS_ENABLED(DM_GPIO)
68 || dm_gpio_get_value(&host->cd_gpio) >= 0
69#endif
70 ) {
71 sdhci_readb(host, ATMEL_SDHC_MC1R);
72 mc1r |= ATMEL_SDHC_MC1R_FCD;
73 sdhci_writeb(host, mc1r, ATMEL_SDHC_MC1R);
74 }
75}
76
222a1f49
SM
77static int atmel_sdhci_deferred_probe(struct sdhci_host *host)
78{
79 struct udevice *dev = host->mmc->dev;
e83b6f99 80 int ret;
222a1f49 81
e83b6f99
ZL
82 ret = sdhci_probe(dev);
83 if (ret)
84 return ret;
85
86 atmel_sdhci_config_fcd(host);
87
88 return 0;
222a1f49
SM
89}
90
91static const struct sdhci_ops atmel_sdhci_ops = {
92 .deferred_probe = atmel_sdhci_deferred_probe,
93};
94
a0d0d86f
WY
95static int atmel_sdhci_probe(struct udevice *dev)
96{
97 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
c69cda25 98 struct atmel_sdhci_plat *plat = dev_get_plat(dev);
a0d0d86f
WY
99 struct sdhci_host *host = dev_get_priv(dev);
100 u32 max_clk;
a0d0d86f
WY
101 struct clk clk;
102 int ret;
103
339cb073 104 ret = clk_get_by_index(dev, 0, &clk);
a0d0d86f
WY
105 if (ret)
106 return ret;
107
108 ret = clk_enable(&clk);
109 if (ret)
110 return ret;
111
112 host->name = dev->name;
8613c8d8 113 host->ioaddr = dev_read_addr_ptr(dev);
a0d0d86f 114
b3125088 115 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
e160f7d4 116 host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
a0d0d86f
WY
117 "bus-width", 4);
118
339cb073 119 ret = clk_get_by_index(dev, 1, &clk);
a0d0d86f
WY
120 if (ret)
121 return ret;
122
2e00608c 123 clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
a0d0d86f
WY
124
125 max_clk = clk_get_rate(&clk);
126 if (!max_clk)
127 return -EINVAL;
128
81f16438 129 ret = clk_enable(&clk);
7eace38d
EH
130 /* return error only if the clock really has a clock enable func */
131 if (ret && ret != -ENOSYS)
81f16438
EH
132 return ret;
133
3710b464
EH
134 ret = mmc_of_parse(dev, &plat->cfg);
135 if (ret)
136 return ret;
137
6d0e34bf 138 host->max_clk = max_clk;
7835e873
PF
139 host->mmc = &plat->mmc;
140 host->mmc->dev = dev;
6d0e34bf
SH
141
142 ret = sdhci_setup_cfg(&plat->cfg, host, 0, ATMEL_SDHC_MIN_FREQ);
a0d0d86f
WY
143 if (ret)
144 return ret;
145
a0d0d86f 146 host->mmc->priv = host;
222a1f49 147 host->ops = &atmel_sdhci_ops;
a0d0d86f
WY
148 upriv->mmc = host->mmc;
149
e83b6f99
ZL
150 ret = sdhci_probe(dev);
151 if (ret)
152 return ret;
153
154 atmel_sdhci_config_fcd(host);
155
156 return 0;
a0d0d86f
WY
157}
158
159static int atmel_sdhci_bind(struct udevice *dev)
160{
c69cda25 161 struct atmel_sdhci_plat *plat = dev_get_plat(dev);
a0d0d86f 162
24f5aec3 163 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
a0d0d86f
WY
164}
165
166static const struct udevice_id atmel_sdhci_ids[] = {
167 { .compatible = "atmel,sama5d2-sdhci" },
f5663740 168 { .compatible = "microchip,sam9x60-sdhci" },
4cc08258 169 { .compatible = "microchip,sama7g5-sdhci" },
a0d0d86f
WY
170 { }
171};
172
173U_BOOT_DRIVER(atmel_sdhci_drv) = {
174 .name = "atmel_sdhci",
175 .id = UCLASS_MMC,
176 .of_match = atmel_sdhci_ids,
177 .ops = &sdhci_ops,
178 .bind = atmel_sdhci_bind,
179 .probe = atmel_sdhci_probe,
41575d8e 180 .priv_auto = sizeof(struct sdhci_host),
caa4daa2 181 .plat_auto = sizeof(struct atmel_sdhci_plat),
a0d0d86f
WY
182};
183#endif