bb5f8ea4 |
1 | /* |
2 | * Atmel SDMMC controller driver. |
3 | * |
4 | * Copyright (C) 2015 Atmel, |
5 | * 2015 Ludovic Desroches <ludovic.desroches@atmel.com> |
6 | * |
7 | * This software is licensed under the terms of the GNU General Public |
8 | * License version 2, as published by the Free Software Foundation, and |
9 | * may be copied, distributed, and modified under those terms. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | */ |
16 | |
17 | #include <linux/clk.h> |
18 | #include <linux/err.h> |
19 | #include <linux/io.h> |
20 | #include <linux/mmc/host.h> |
21 | #include <linux/module.h> |
22 | #include <linux/of.h> |
23 | #include <linux/of_device.h> |
24 | |
25 | #include "sdhci-pltfm.h" |
26 | |
27 | #define SDMMC_CACR 0x230 |
28 | #define SDMMC_CACR_CAPWREN BIT(0) |
29 | #define SDMMC_CACR_KEY (0x46 << 8) |
30 | |
31 | struct sdhci_at91_priv { |
32 | struct clk *hclock; |
33 | struct clk *gck; |
34 | struct clk *mainck; |
35 | }; |
36 | |
37 | static const struct sdhci_ops sdhci_at91_sama5d2_ops = { |
38 | .set_clock = sdhci_set_clock, |
39 | .set_bus_width = sdhci_set_bus_width, |
40 | .reset = sdhci_reset, |
41 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
42 | }; |
43 | |
44 | static const struct sdhci_pltfm_data soc_data_sama5d2 = { |
45 | .ops = &sdhci_at91_sama5d2_ops, |
88c6eb0e |
46 | .quirks2 = SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST, |
bb5f8ea4 |
47 | }; |
48 | |
49 | static const struct of_device_id sdhci_at91_dt_match[] = { |
50 | { .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 }, |
51 | {} |
52 | }; |
53 | |
54 | static int sdhci_at91_probe(struct platform_device *pdev) |
55 | { |
56 | const struct of_device_id *match; |
57 | const struct sdhci_pltfm_data *soc_data; |
58 | struct sdhci_host *host; |
59 | struct sdhci_pltfm_host *pltfm_host; |
60 | struct sdhci_at91_priv *priv; |
61 | unsigned int caps0, caps1; |
62 | unsigned int clk_base, clk_mul; |
63 | unsigned int gck_rate, real_gck_rate; |
64 | int ret; |
65 | |
66 | match = of_match_device(sdhci_at91_dt_match, &pdev->dev); |
67 | if (!match) |
68 | return -EINVAL; |
69 | soc_data = match->data; |
70 | |
71 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
72 | if (!priv) { |
73 | dev_err(&pdev->dev, "unable to allocate private data\n"); |
74 | return -ENOMEM; |
75 | } |
76 | |
77 | priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); |
78 | if (IS_ERR(priv->mainck)) { |
79 | dev_err(&pdev->dev, "failed to get baseclk\n"); |
80 | return PTR_ERR(priv->mainck); |
81 | } |
82 | |
83 | priv->hclock = devm_clk_get(&pdev->dev, "hclock"); |
84 | if (IS_ERR(priv->hclock)) { |
85 | dev_err(&pdev->dev, "failed to get hclock\n"); |
86 | return PTR_ERR(priv->hclock); |
87 | } |
88 | |
89 | priv->gck = devm_clk_get(&pdev->dev, "multclk"); |
90 | if (IS_ERR(priv->gck)) { |
91 | dev_err(&pdev->dev, "failed to get multclk\n"); |
92 | return PTR_ERR(priv->gck); |
93 | } |
94 | |
95 | host = sdhci_pltfm_init(pdev, soc_data, 0); |
96 | if (IS_ERR(host)) |
97 | return PTR_ERR(host); |
98 | |
99 | /* |
100 | * The mult clock is provided by as a generated clock by the PMC |
101 | * controller. In order to set the rate of gck, we have to get the |
102 | * base clock rate and the clock mult from capabilities. |
103 | */ |
104 | clk_prepare_enable(priv->hclock); |
105 | caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES); |
106 | caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1); |
107 | clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; |
108 | clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; |
109 | gck_rate = clk_base * 1000000 * (clk_mul + 1); |
110 | ret = clk_set_rate(priv->gck, gck_rate); |
111 | if (ret < 0) { |
112 | dev_err(&pdev->dev, "failed to set gck"); |
113 | goto hclock_disable_unprepare; |
114 | return -EINVAL; |
115 | } |
116 | /* |
117 | * We need to check if we have the requested rate for gck because in |
118 | * some cases this rate could be not supported. If it happens, the rate |
119 | * is the closest one gck can provide. We have to update the value |
120 | * of clk mul. |
121 | */ |
122 | real_gck_rate = clk_get_rate(priv->gck); |
123 | if (real_gck_rate != gck_rate) { |
124 | clk_mul = real_gck_rate / (clk_base * 1000000) - 1; |
125 | caps1 &= (~SDHCI_CLOCK_MUL_MASK); |
126 | caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK); |
127 | /* Set capabilities in r/w mode. */ |
128 | writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR); |
129 | writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1); |
130 | /* Set capabilities in ro mode. */ |
131 | writel(0, host->ioaddr + SDMMC_CACR); |
132 | dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n", |
133 | clk_mul, real_gck_rate); |
134 | } |
135 | |
136 | clk_prepare_enable(priv->mainck); |
137 | clk_prepare_enable(priv->gck); |
138 | |
139 | pltfm_host = sdhci_priv(host); |
140 | pltfm_host->priv = priv; |
141 | |
142 | ret = mmc_of_parse(host->mmc); |
143 | if (ret) |
144 | goto clocks_disable_unprepare; |
145 | |
146 | sdhci_get_of_property(pdev); |
147 | |
148 | ret = sdhci_add_host(host); |
149 | if (ret) |
150 | goto clocks_disable_unprepare; |
151 | |
152 | return 0; |
153 | |
154 | clocks_disable_unprepare: |
155 | clk_disable_unprepare(priv->gck); |
156 | clk_disable_unprepare(priv->mainck); |
157 | hclock_disable_unprepare: |
158 | clk_disable_unprepare(priv->hclock); |
159 | sdhci_pltfm_free(pdev); |
160 | return ret; |
161 | } |
162 | |
163 | static int sdhci_at91_remove(struct platform_device *pdev) |
164 | { |
165 | struct sdhci_host *host = platform_get_drvdata(pdev); |
166 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
167 | struct sdhci_at91_priv *priv = pltfm_host->priv; |
168 | |
169 | sdhci_pltfm_unregister(pdev); |
170 | |
171 | clk_disable_unprepare(priv->gck); |
172 | clk_disable_unprepare(priv->hclock); |
173 | clk_disable_unprepare(priv->mainck); |
174 | |
175 | return 0; |
176 | } |
177 | |
178 | static struct platform_driver sdhci_at91_driver = { |
179 | .driver = { |
180 | .name = "sdhci-at91", |
bb5f8ea4 |
181 | .of_match_table = sdhci_at91_dt_match, |
182 | .pm = SDHCI_PLTFM_PMOPS, |
183 | }, |
184 | .probe = sdhci_at91_probe, |
185 | .remove = sdhci_at91_remove, |
186 | }; |
187 | |
188 | module_platform_driver(sdhci_at91_driver); |
189 | |
190 | MODULE_DESCRIPTION("SDHCI driver for at91"); |
191 | MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@atmel.com>"); |
192 | MODULE_LICENSE("GPL v2"); |