summaryrefslogtreecommitdiff
path: root/components/drivers/sdio/sdhci/sdhci-platform.c
blob: d6cf4ed2a351122e4e039b0f96d68871c82d6538 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * Copyright (c) 2006-2024 RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author        Notes
 * 2024-08-16     zhujiale     first version
 */
#include "sdhci-platform.h"

static const struct rt_sdhci_ops sdhci_pltfm_ops = {
    .set_clock         = rt_sdhci_set_clock,
    .set_bus_width     = rt_sdhci_set_bus_width,
    .reset             = rt_sdhci_reset,
    .set_uhs_signaling = rt_sdhci_set_uhs,
};

void rt_sdhci_get_property(struct rt_platform_device *pdev)
{
    struct rt_device        *dev        = &pdev->parent;
    struct rt_sdhci_host       *host       = pdev->priv;
    struct rt_sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    rt_uint32_t              bus_width;

    if (rt_dm_dev_prop_read_bool(dev, "sdhci,auto-cmd12"))
        host->quirks |= RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;

    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))
        host->quirks |= RT_SDHCI_QUIRK_FORCE_1_BIT_DATA;

    if (rt_dm_dev_prop_read_bool(dev, "broken-cd"))
        host->quirks |= RT_SDHCI_QUIRK_BROKEN_CARD_DETECTION;

    if (rt_dm_dev_prop_read_bool(dev, "no-1-8-v"))
        host->quirks2 |= RT_SDHCI_QUIRK2_NO_1_8_V;

    rt_dm_dev_prop_read_u32(dev, "clock-frequency", &pltfm_host->clock);

    if (rt_dm_dev_prop_read_bool(dev, "keep-power-in-suspend"))
        host->mmc->pm_caps |= MMC_PM_KEEP_POWER;

    if (rt_dm_dev_prop_read_bool(dev, "wakeup-source") || rt_dm_dev_prop_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
        host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}

struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device     *pdev,
                                    const struct rt_sdhci_pltfm_data *pdata,
                                    size_t                         priv_size)
{
    struct rt_sdhci_host      *host;
    struct rt_device       *dev = &pdev->parent;
    void                   *ioaddr;
    int                     irq;

    ioaddr = rt_dm_dev_iomap(dev, 0);
    if (!ioaddr)
    {
        return RT_NULL;
    }

    irq = rt_dm_dev_get_irq(dev, 0);
    if (irq < 0)
    {
        return RT_NULL;
    }
    host = rt_sdhci_alloc_host(dev,sizeof(struct rt_sdhci_pltfm_host) + priv_size);
    if (!host)
    {
        return RT_NULL;
    }
    host->irq     = irq;
    host->ioaddr  = ioaddr;
    host->hw_name = rt_dm_dev_get_name(dev);

    if (pdata && pdata->ops)
        host->ops = pdata->ops;
    else
        host->ops = &sdhci_pltfm_ops;
    if (pdata)
    {
        host->quirks  = pdata->quirks;
        host->quirks2 = pdata->quirks2;
    }

    pdev->priv = host;

    return host;
}

int rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device     *pdev,
                                  const struct rt_sdhci_pltfm_data *pdata,
                                  size_t                         priv_size)
{
    struct rt_sdhci_host *host;
    int                ret = 0;

    host = rt_sdhci_pltfm_init(pdev, pdata, priv_size);
    if (!host)
        return -RT_ERROR;

    rt_sdhci_get_property(pdev);

    ret = rt_sdhci_init_host(host);
    if (ret)
        rt_sdhci_pltfm_free(pdev);

    return ret;
}

void rt_sdhci_pltfm_free(struct rt_platform_device *pdev)
{
    struct rt_sdhci_host *host = pdev->priv;

    rt_sdhci_free_host(host);
}

void rt_sdhci_pltfm_remove(struct rt_platform_device *pdev)
{
    struct rt_sdhci_host *host = pdev->priv;
    int dead = (readl(host->ioaddr + RT_SDHCI_INT_STATUS) == 0xffffffff);

    rt_sdhci_uninit_host(host, dead);
    rt_sdhci_pltfm_free(pdev);
}