126 lines
3.6 KiB
C
126 lines
3.6 KiB
C
/*
|
|
* 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);
|
|
}
|