1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's 4 * 5 * Copyright (C) 2015 Broadcom Corporation 6 */ 7 8 #include <linux/io.h> 9 #include <linux/mmc/host.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 13 #include "sdhci-pltfm.h" 14 15 static const struct sdhci_ops sdhci_brcmstb_ops = { 16 .set_clock = sdhci_set_clock, 17 .set_bus_width = sdhci_set_bus_width, 18 .reset = sdhci_reset, 19 .set_uhs_signaling = sdhci_set_uhs_signaling, 20 }; 21 22 static const struct sdhci_pltfm_data sdhci_brcmstb_pdata = { 23 .ops = &sdhci_brcmstb_ops, 24 }; 25 26 static int sdhci_brcmstb_probe(struct platform_device *pdev) 27 { 28 struct sdhci_host *host; 29 struct sdhci_pltfm_host *pltfm_host; 30 struct clk *clk; 31 int res; 32 33 clk = devm_clk_get(&pdev->dev, NULL); 34 if (IS_ERR(clk)) { 35 dev_err(&pdev->dev, "Clock not found in Device Tree\n"); 36 clk = NULL; 37 } 38 res = clk_prepare_enable(clk); 39 if (res) 40 return res; 41 42 host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata, 0); 43 if (IS_ERR(host)) { 44 res = PTR_ERR(host); 45 goto err_clk; 46 } 47 48 sdhci_get_of_property(pdev); 49 res = mmc_of_parse(host->mmc); 50 if (res) 51 goto err; 52 53 /* 54 * Supply the existing CAPS, but clear the UHS modes. This 55 * will allow these modes to be specified by device tree 56 * properties through mmc_of_parse(). 57 */ 58 host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); 59 if (of_device_is_compatible(pdev->dev.of_node, "brcm,bcm7425-sdhci")) 60 host->caps &= ~SDHCI_CAN_64BIT; 61 host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); 62 host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | 63 SDHCI_SUPPORT_DDR50); 64 host->quirks |= SDHCI_QUIRK_MISSING_CAPS | 65 SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 66 67 res = sdhci_add_host(host); 68 if (res) 69 goto err; 70 71 pltfm_host = sdhci_priv(host); 72 pltfm_host->clk = clk; 73 return res; 74 75 err: 76 sdhci_pltfm_free(pdev); 77 err_clk: 78 clk_disable_unprepare(clk); 79 return res; 80 } 81 82 static const struct of_device_id sdhci_brcm_of_match[] = { 83 { .compatible = "brcm,bcm7425-sdhci" }, 84 { .compatible = "brcm,bcm7445-sdhci" }, 85 {}, 86 }; 87 MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match); 88 89 static struct platform_driver sdhci_brcmstb_driver = { 90 .driver = { 91 .name = "sdhci-brcmstb", 92 .pm = &sdhci_pltfm_pmops, 93 .of_match_table = of_match_ptr(sdhci_brcm_of_match), 94 }, 95 .probe = sdhci_brcmstb_probe, 96 .remove = sdhci_pltfm_unregister, 97 }; 98 99 module_platform_driver(sdhci_brcmstb_driver); 100 101 MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs"); 102 MODULE_AUTHOR("Broadcom"); 103 MODULE_LICENSE("GPL v2"); 104