1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author        Notes
8  * 2024-08-16     zhujiale     first version
9  */
10 #include "sdhci-platform.h"
11 
12 static const struct rt_sdhci_ops sdhci_pltfm_ops = {
13     .set_clock         = rt_sdhci_set_clock,
14     .set_bus_width     = rt_sdhci_set_bus_width,
15     .reset             = rt_sdhci_reset,
16     .set_uhs_signaling = rt_sdhci_set_uhs,
17 };
18 
rt_sdhci_get_property(struct rt_platform_device * pdev)19 void rt_sdhci_get_property(struct rt_platform_device *pdev)
20 {
21     struct rt_device        *dev        = &pdev->parent;
22     struct rt_sdhci_host       *host       = pdev->priv;
23     struct rt_sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
24     rt_uint32_t              bus_width;
25 
26     if (rt_dm_dev_prop_read_bool(dev, "sdhci,auto-cmd12"))
27         host->quirks |= RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
28 
29     if (rt_dm_dev_prop_read_bool(dev, "sdhci,1-bit-only") || (rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) == 0 && bus_width == 1))
30         host->quirks |= RT_SDHCI_QUIRK_FORCE_1_BIT_DATA;
31 
32     if (rt_dm_dev_prop_read_bool(dev, "broken-cd"))
33         host->quirks |= RT_SDHCI_QUIRK_BROKEN_CARD_DETECTION;
34 
35     if (rt_dm_dev_prop_read_bool(dev, "no-1-8-v"))
36         host->quirks2 |= RT_SDHCI_QUIRK2_NO_1_8_V;
37 
38     rt_dm_dev_prop_read_u32(dev, "clock-frequency", &pltfm_host->clock);
39 
40     if (rt_dm_dev_prop_read_bool(dev, "keep-power-in-suspend"))
41         host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
42 
43     if (rt_dm_dev_prop_read_bool(dev, "wakeup-source") || rt_dm_dev_prop_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
44         host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
45 }
46 
rt_sdhci_pltfm_init(struct rt_platform_device * pdev,const struct rt_sdhci_pltfm_data * pdata,size_t priv_size)47 struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device     *pdev,
48                                     const struct rt_sdhci_pltfm_data *pdata,
49                                     size_t                         priv_size)
50 {
51     struct rt_sdhci_host      *host;
52     struct rt_device       *dev = &pdev->parent;
53     void                   *ioaddr;
54     int                     irq;
55 
56     ioaddr = rt_dm_dev_iomap(dev, 0);
57     if (!ioaddr)
58     {
59         return RT_NULL;
60     }
61 
62     irq = rt_dm_dev_get_irq(dev, 0);
63     if (irq < 0)
64     {
65         return RT_NULL;
66     }
67     host = rt_sdhci_alloc_host(dev,sizeof(struct rt_sdhci_pltfm_host) + priv_size);
68     if (!host)
69     {
70         return RT_NULL;
71     }
72     host->irq     = irq;
73     host->ioaddr  = ioaddr;
74     host->hw_name = rt_dm_dev_get_name(dev);
75 
76     if (pdata && pdata->ops)
77         host->ops = pdata->ops;
78     else
79         host->ops = &sdhci_pltfm_ops;
80     if (pdata)
81     {
82         host->quirks  = pdata->quirks;
83         host->quirks2 = pdata->quirks2;
84     }
85 
86     pdev->priv = host;
87 
88     return host;
89 }
90 
rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device * pdev,const struct rt_sdhci_pltfm_data * pdata,size_t priv_size)91 int rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device     *pdev,
92                                   const struct rt_sdhci_pltfm_data *pdata,
93                                   size_t                         priv_size)
94 {
95     struct rt_sdhci_host *host;
96     int                ret = 0;
97 
98     host = rt_sdhci_pltfm_init(pdev, pdata, priv_size);
99     if (!host)
100         return -RT_ERROR;
101 
102     rt_sdhci_get_property(pdev);
103 
104     ret = rt_sdhci_init_host(host);
105     if (ret)
106         rt_sdhci_pltfm_free(pdev);
107 
108     return ret;
109 }
110 
rt_sdhci_pltfm_free(struct rt_platform_device * pdev)111 void rt_sdhci_pltfm_free(struct rt_platform_device *pdev)
112 {
113     struct rt_sdhci_host *host = pdev->priv;
114 
115     rt_sdhci_free_host(host);
116 }
117 
rt_sdhci_pltfm_remove(struct rt_platform_device * pdev)118 void rt_sdhci_pltfm_remove(struct rt_platform_device *pdev)
119 {
120     struct rt_sdhci_host *host = pdev->priv;
121     int dead = (readl(host->ioaddr + RT_SDHCI_INT_STATUS) == 0xffffffff);
122 
123     rt_sdhci_uninit_host(host, dead);
124     rt_sdhci_pltfm_free(pdev);
125 }
126