1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * sdhci-dove.c Support for SDHCI on Marvell's Dove SoC |
4 | * |
5 | * Author: Saeed Bishara <saeed@marvell.com> |
6 | * Mike Rapoport <mike@compulab.co.il> |
7 | * Based on sdhci-cns3xxx.c |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/err.h> |
12 | #include <linux/io.h> |
13 | #include <linux/mmc/host.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | |
17 | #include "sdhci-pltfm.h" |
18 | |
19 | static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) |
20 | { |
21 | u16 ret; |
22 | |
23 | switch (reg) { |
24 | case SDHCI_HOST_VERSION: |
25 | case SDHCI_SLOT_INT_STATUS: |
26 | /* those registers don't exist */ |
27 | return 0; |
28 | default: |
29 | ret = readw(addr: host->ioaddr + reg); |
30 | } |
31 | return ret; |
32 | } |
33 | |
34 | static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) |
35 | { |
36 | u32 ret; |
37 | |
38 | ret = readl(addr: host->ioaddr + reg); |
39 | |
40 | switch (reg) { |
41 | case SDHCI_CAPABILITIES: |
42 | /* Mask the support for 3.0V */ |
43 | ret &= ~SDHCI_CAN_VDD_300; |
44 | break; |
45 | } |
46 | return ret; |
47 | } |
48 | |
49 | static const struct sdhci_ops sdhci_dove_ops = { |
50 | .read_w = sdhci_dove_readw, |
51 | .read_l = sdhci_dove_readl, |
52 | .set_clock = sdhci_set_clock, |
53 | .set_bus_width = sdhci_set_bus_width, |
54 | .reset = sdhci_reset, |
55 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
56 | }; |
57 | |
58 | static const struct sdhci_pltfm_data sdhci_dove_pdata = { |
59 | .ops = &sdhci_dove_ops, |
60 | .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | |
61 | SDHCI_QUIRK_NO_BUSY_IRQ | |
62 | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | |
63 | SDHCI_QUIRK_FORCE_DMA | |
64 | SDHCI_QUIRK_NO_HISPD_BIT, |
65 | }; |
66 | |
67 | static int sdhci_dove_probe(struct platform_device *pdev) |
68 | { |
69 | struct sdhci_host *host; |
70 | struct sdhci_pltfm_host *pltfm_host; |
71 | int ret; |
72 | |
73 | host = sdhci_pltfm_init(pdev, pdata: &sdhci_dove_pdata, priv_size: 0); |
74 | if (IS_ERR(ptr: host)) |
75 | return PTR_ERR(ptr: host); |
76 | |
77 | pltfm_host = sdhci_priv(host); |
78 | pltfm_host->clk = devm_clk_get_enabled(dev: &pdev->dev, NULL); |
79 | |
80 | ret = mmc_of_parse(host: host->mmc); |
81 | if (ret) |
82 | goto err_sdhci_add; |
83 | |
84 | ret = sdhci_add_host(host); |
85 | if (ret) |
86 | goto err_sdhci_add; |
87 | |
88 | return 0; |
89 | |
90 | err_sdhci_add: |
91 | sdhci_pltfm_free(pdev); |
92 | return ret; |
93 | } |
94 | |
95 | static const struct of_device_id sdhci_dove_of_match_table[] = { |
96 | { .compatible = "marvell,dove-sdhci" , }, |
97 | {} |
98 | }; |
99 | MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table); |
100 | |
101 | static struct platform_driver sdhci_dove_driver = { |
102 | .driver = { |
103 | .name = "sdhci-dove" , |
104 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
105 | .pm = &sdhci_pltfm_pmops, |
106 | .of_match_table = sdhci_dove_of_match_table, |
107 | }, |
108 | .probe = sdhci_dove_probe, |
109 | .remove_new = sdhci_pltfm_remove, |
110 | }; |
111 | |
112 | module_platform_driver(sdhci_dove_driver); |
113 | |
114 | MODULE_DESCRIPTION("SDHCI driver for Dove" ); |
115 | MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, " |
116 | "Mike Rapoport <mike@compulab.co.il>" ); |
117 | MODULE_LICENSE("GPL v2" ); |
118 | |