1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * NPCM SDHC MMC host controller driver. |
4 | * |
5 | * Copyright (c) 2023 Nuvoton Technology corporation. |
6 | */ |
7 | |
8 | #include <linux/clk.h> |
9 | #include <linux/err.h> |
10 | #include <linux/io.h> |
11 | #include <linux/mmc/host.h> |
12 | #include <linux/mmc/mmc.h> |
13 | #include <linux/mod_devicetable.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | |
17 | #include "sdhci-pltfm.h" |
18 | |
19 | static const struct sdhci_pltfm_data npcm7xx_sdhci_pdata = { |
20 | .quirks = SDHCI_QUIRK_DELAY_AFTER_POWER, |
21 | .quirks2 = SDHCI_QUIRK2_STOP_WITH_TC | |
22 | SDHCI_QUIRK2_NO_1_8_V, |
23 | }; |
24 | |
25 | static const struct sdhci_pltfm_data npcm8xx_sdhci_pdata = { |
26 | .quirks = SDHCI_QUIRK_DELAY_AFTER_POWER, |
27 | .quirks2 = SDHCI_QUIRK2_STOP_WITH_TC, |
28 | }; |
29 | |
30 | static int npcm_sdhci_probe(struct platform_device *pdev) |
31 | { |
32 | const struct sdhci_pltfm_data *data; |
33 | struct sdhci_pltfm_host *pltfm_host; |
34 | struct device *dev = &pdev->dev; |
35 | struct sdhci_host *host; |
36 | u32 caps; |
37 | int ret; |
38 | |
39 | data = of_device_get_match_data(dev); |
40 | if (!data) |
41 | return -EINVAL; |
42 | |
43 | host = sdhci_pltfm_init(pdev, pdata: data, priv_size: 0); |
44 | if (IS_ERR(ptr: host)) |
45 | return PTR_ERR(ptr: host); |
46 | |
47 | pltfm_host = sdhci_priv(host); |
48 | |
49 | pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL); |
50 | if (IS_ERR(ptr: pltfm_host->clk)) { |
51 | ret = PTR_ERR(ptr: pltfm_host->clk); |
52 | goto err_sdhci; |
53 | } |
54 | |
55 | caps = sdhci_readl(host, SDHCI_CAPABILITIES); |
56 | if (caps & SDHCI_CAN_DO_8BIT) |
57 | host->mmc->caps |= MMC_CAP_8_BIT_DATA; |
58 | |
59 | ret = mmc_of_parse(host: host->mmc); |
60 | if (ret) |
61 | goto err_sdhci; |
62 | |
63 | ret = sdhci_add_host(host); |
64 | if (ret) |
65 | goto err_sdhci; |
66 | |
67 | return 0; |
68 | |
69 | err_sdhci: |
70 | sdhci_pltfm_free(pdev); |
71 | return ret; |
72 | } |
73 | |
74 | static const struct of_device_id npcm_sdhci_of_match[] = { |
75 | { .compatible = "nuvoton,npcm750-sdhci" , .data = &npcm7xx_sdhci_pdata }, |
76 | { .compatible = "nuvoton,npcm845-sdhci" , .data = &npcm8xx_sdhci_pdata }, |
77 | { } |
78 | }; |
79 | MODULE_DEVICE_TABLE(of, npcm_sdhci_of_match); |
80 | |
81 | static struct platform_driver npcm_sdhci_driver = { |
82 | .driver = { |
83 | .name = "npcm-sdhci" , |
84 | .of_match_table = npcm_sdhci_of_match, |
85 | .pm = &sdhci_pltfm_pmops, |
86 | }, |
87 | .probe = npcm_sdhci_probe, |
88 | .remove_new = sdhci_pltfm_remove, |
89 | }; |
90 | module_platform_driver(npcm_sdhci_driver); |
91 | |
92 | MODULE_DESCRIPTION("NPCM Secure Digital Host Controller Interface driver" ); |
93 | MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>" ); |
94 | MODULE_LICENSE("GPL" ); |
95 | |