]> git.sur5r.net Git - u-boot/blob - drivers/mmc/nds32_mmc.c
Merge git://git.denx.de/u-boot-sunxi
[u-boot] / drivers / mmc / nds32_mmc.c
1 /*
2  * Andestech ATFSDC010 SD/MMC driver
3  *
4  * (C) Copyright 2017
5  * Rick Chen, NDS32 Software Engineering, rick@andestech.com
6
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <clk.h>
12 #include <dm.h>
13 #include <dt-structs.h>
14 #include <errno.h>
15 #include <mapmem.h>
16 #include <mmc.h>
17 #include <pwrseq.h>
18 #include <syscon.h>
19 #include <linux/err.h>
20 #include <faraday/ftsdc010.h>
21 #include "ftsdc010_mci.h"
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 #if CONFIG_IS_ENABLED(OF_PLATDATA)
26 struct nds_mmc {
27         fdt32_t         bus_width;
28         bool            cap_mmc_highspeed;
29         bool            cap_sd_highspeed;
30         fdt32_t         clock_freq_min_max[2];
31         struct phandle_2_cell   clocks[4];
32         fdt32_t         fifo_depth;
33         fdt32_t         reg[2];
34 };
35 #endif
36
37 struct nds_mmc_plat {
38 #if CONFIG_IS_ENABLED(OF_PLATDATA)
39         struct nds_mmc dtplat;
40 #endif
41         struct mmc_config cfg;
42         struct mmc mmc;
43 };
44
45 struct ftsdc_priv {
46         struct clk clk;
47         struct ftsdc010_chip chip;
48         int fifo_depth;
49         bool fifo_mode;
50         u32 minmax[2];
51 };
52
53 static int nds32_mmc_ofdata_to_platdata(struct udevice *dev)
54 {
55 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
56         struct ftsdc_priv *priv = dev_get_priv(dev);
57         struct ftsdc010_chip *chip = &priv->chip;
58         chip->name = dev->name;
59         chip->ioaddr = (void *)devfdt_get_addr(dev);
60         chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
61                                         "bus-width", 4);
62         chip->priv = dev;
63         priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
64                                     "fifo-depth", 0);
65         priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
66                                           "fifo-mode");
67         if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
68                          "clock-freq-min-max", priv->minmax, 2)) {
69                 int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
70                                   "max-frequency", -EINVAL);
71                 if (val < 0)
72                         return val;
73
74                 priv->minmax[0] = 400000;  /* 400 kHz */
75                 priv->minmax[1] = val;
76         } else {
77                 debug("%s: 'clock-freq-min-max' property was deprecated.\n",
78                 __func__);
79         }
80 #endif
81         chip->sclk = priv->minmax[1];
82         chip->regs = chip->ioaddr;
83         return 0;
84 }
85
86 static int nds32_mmc_probe(struct udevice *dev)
87 {
88         struct nds_mmc_plat *plat = dev_get_platdata(dev);
89         struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
90         struct ftsdc_priv *priv = dev_get_priv(dev);
91         struct ftsdc010_chip *chip = &priv->chip;
92         struct udevice *pwr_dev __maybe_unused;
93 #if CONFIG_IS_ENABLED(OF_PLATDATA)
94         int ret;
95         struct nds_mmc *dtplat = &plat->dtplat;
96         chip->name = dev->name;
97         chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
98         chip->buswidth = dtplat->bus_width;
99         chip->priv = dev;
100         chip->dev_index = 1;
101         memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
102         ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
103         if (ret < 0)
104                 return ret;
105 #endif
106         ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps,
107                         priv->minmax[1] , priv->minmax[0]);
108         chip->mmc = &plat->mmc;
109         chip->mmc->priv = &priv->chip;
110         chip->mmc->dev = dev;
111         upriv->mmc = chip->mmc;
112         return ftsdc010_probe(dev);
113 }
114
115 static int nds32_mmc_bind(struct udevice *dev)
116 {
117         struct nds_mmc_plat *plat = dev_get_platdata(dev);
118         return ftsdc010_bind(dev, &plat->mmc, &plat->cfg);
119 }
120
121 static const struct udevice_id nds32_mmc_ids[] = {
122         { .compatible = "andestech,atsdc010" },
123         { }
124 };
125
126 U_BOOT_DRIVER(nds32_mmc_drv) = {
127         .name           = "nds32_mmc",
128         .id             = UCLASS_MMC,
129         .of_match       = nds32_mmc_ids,
130         .ofdata_to_platdata = nds32_mmc_ofdata_to_platdata,
131         .ops            = &dm_ftsdc010_ops,
132         .bind           = nds32_mmc_bind,
133         .probe          = nds32_mmc_probe,
134         .priv_auto_alloc_size = sizeof(struct ftsdc_priv),
135         .platdata_auto_alloc_size = sizeof(struct nds_mmc_plat),
136 };