11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2476bf3d6SAl Cooper /* 3476bf3d6SAl Cooper * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's 4476bf3d6SAl Cooper * 5476bf3d6SAl Cooper * Copyright (C) 2015 Broadcom Corporation 6476bf3d6SAl Cooper */ 7476bf3d6SAl Cooper 8476bf3d6SAl Cooper #include <linux/io.h> 9476bf3d6SAl Cooper #include <linux/mmc/host.h> 10476bf3d6SAl Cooper #include <linux/module.h> 11476bf3d6SAl Cooper #include <linux/of.h> 12476bf3d6SAl Cooper 13476bf3d6SAl Cooper #include "sdhci-pltfm.h" 14476bf3d6SAl Cooper 15476bf3d6SAl Cooper static const struct sdhci_ops sdhci_brcmstb_ops = { 16476bf3d6SAl Cooper .set_clock = sdhci_set_clock, 17476bf3d6SAl Cooper .set_bus_width = sdhci_set_bus_width, 18476bf3d6SAl Cooper .reset = sdhci_reset, 19476bf3d6SAl Cooper .set_uhs_signaling = sdhci_set_uhs_signaling, 20476bf3d6SAl Cooper }; 21476bf3d6SAl Cooper 2236719676SJulia Lawall static const struct sdhci_pltfm_data sdhci_brcmstb_pdata = { 23476bf3d6SAl Cooper .ops = &sdhci_brcmstb_ops, 24476bf3d6SAl Cooper }; 25476bf3d6SAl Cooper 26476bf3d6SAl Cooper static int sdhci_brcmstb_probe(struct platform_device *pdev) 27476bf3d6SAl Cooper { 28476bf3d6SAl Cooper struct sdhci_host *host; 29476bf3d6SAl Cooper struct sdhci_pltfm_host *pltfm_host; 30476bf3d6SAl Cooper struct clk *clk; 31476bf3d6SAl Cooper int res; 32476bf3d6SAl Cooper 33476bf3d6SAl Cooper clk = devm_clk_get(&pdev->dev, NULL); 34476bf3d6SAl Cooper if (IS_ERR(clk)) { 35476bf3d6SAl Cooper dev_err(&pdev->dev, "Clock not found in Device Tree\n"); 36476bf3d6SAl Cooper clk = NULL; 37476bf3d6SAl Cooper } 38476bf3d6SAl Cooper res = clk_prepare_enable(clk); 39476bf3d6SAl Cooper if (res) 40476bf3d6SAl Cooper return res; 41476bf3d6SAl Cooper 42476bf3d6SAl Cooper host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata, 0); 43476bf3d6SAl Cooper if (IS_ERR(host)) { 44476bf3d6SAl Cooper res = PTR_ERR(host); 45476bf3d6SAl Cooper goto err_clk; 46476bf3d6SAl Cooper } 47476bf3d6SAl Cooper 48476bf3d6SAl Cooper sdhci_get_of_property(pdev); 491e20186eSStefan Wahren res = mmc_of_parse(host->mmc); 501e20186eSStefan Wahren if (res) 511e20186eSStefan Wahren goto err; 52476bf3d6SAl Cooper 53476bf3d6SAl Cooper /* 54476bf3d6SAl Cooper * Supply the existing CAPS, but clear the UHS modes. This 55476bf3d6SAl Cooper * will allow these modes to be specified by device tree 56476bf3d6SAl Cooper * properties through mmc_of_parse(). 57476bf3d6SAl Cooper */ 58476bf3d6SAl Cooper host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); 596a3d8cedSJaedon Shin if (of_device_is_compatible(pdev->dev.of_node, "brcm,bcm7425-sdhci")) 606a3d8cedSJaedon Shin host->caps &= ~SDHCI_CAN_64BIT; 61476bf3d6SAl Cooper host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); 62476bf3d6SAl Cooper host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | 63476bf3d6SAl Cooper SDHCI_SUPPORT_DDR50); 64476bf3d6SAl Cooper host->quirks |= SDHCI_QUIRK_MISSING_CAPS | 65476bf3d6SAl Cooper SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 66476bf3d6SAl Cooper 67476bf3d6SAl Cooper res = sdhci_add_host(host); 68476bf3d6SAl Cooper if (res) 69476bf3d6SAl Cooper goto err; 70476bf3d6SAl Cooper 71476bf3d6SAl Cooper pltfm_host = sdhci_priv(host); 72476bf3d6SAl Cooper pltfm_host->clk = clk; 73476bf3d6SAl Cooper return res; 74476bf3d6SAl Cooper 75476bf3d6SAl Cooper err: 76476bf3d6SAl Cooper sdhci_pltfm_free(pdev); 77476bf3d6SAl Cooper err_clk: 78476bf3d6SAl Cooper clk_disable_unprepare(clk); 79476bf3d6SAl Cooper return res; 80476bf3d6SAl Cooper } 81476bf3d6SAl Cooper 82476bf3d6SAl Cooper static const struct of_device_id sdhci_brcm_of_match[] = { 83476bf3d6SAl Cooper { .compatible = "brcm,bcm7425-sdhci" }, 846a3d8cedSJaedon Shin { .compatible = "brcm,bcm7445-sdhci" }, 85476bf3d6SAl Cooper {}, 86476bf3d6SAl Cooper }; 87476bf3d6SAl Cooper MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match); 88476bf3d6SAl Cooper 89476bf3d6SAl Cooper static struct platform_driver sdhci_brcmstb_driver = { 90476bf3d6SAl Cooper .driver = { 91476bf3d6SAl Cooper .name = "sdhci-brcmstb", 921ab0d2d7SMasahiro Yamada .pm = &sdhci_pltfm_pmops, 93476bf3d6SAl Cooper .of_match_table = of_match_ptr(sdhci_brcm_of_match), 94476bf3d6SAl Cooper }, 95476bf3d6SAl Cooper .probe = sdhci_brcmstb_probe, 96476bf3d6SAl Cooper .remove = sdhci_pltfm_unregister, 97476bf3d6SAl Cooper }; 98476bf3d6SAl Cooper 99476bf3d6SAl Cooper module_platform_driver(sdhci_brcmstb_driver); 100476bf3d6SAl Cooper 101476bf3d6SAl Cooper MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs"); 102476bf3d6SAl Cooper MODULE_AUTHOR("Broadcom"); 103476bf3d6SAl Cooper MODULE_LICENSE("GPL v2"); 104