/* * 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 "dev_sdhci_dm.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) { rt_uint32_t bus_width; struct rt_device *dev = &pdev->parent; struct rt_sdhci_host *host = pdev->priv; struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); 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) && 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, rt_size_t priv_size) { int irq; void *ioaddr; struct rt_sdhci_host *host; struct rt_device *dev = &pdev->parent; 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; } rt_err_t rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev, const struct rt_sdhci_pltfm_data *pdata, rt_size_t priv_size) { rt_err_t ret = RT_EOK; struct rt_sdhci_host *host; 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); } rt_err_t rt_sdhci_pltfm_remove(struct rt_platform_device *pdev) { rt_bool_t dead; struct rt_sdhci_host *host = pdev->priv; dead = (HWREG32(host->ioaddr + RT_SDHCI_INT_STATUS) == 0xffffffff); rt_sdhci_uninit_host(host, dead); rt_sdhci_pltfm_free(pdev); return RT_EOK; } rt_uint32_t rt_sdhci_pltfm_clk_get_max_clock(struct rt_sdhci_host *host) { struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); return rt_clk_get_rate(pltfm_host->clk); }