Merge branch 'drm-core-next' of git://people.freedesktop.org/~airlied/linux
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / host / sdhci-tegra.c
1 /*
2  * Copyright (C) 2010 Google, Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <linux/err.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/clk.h>
20 #include <linux/io.h>
21 #include <linux/of.h>
22 #include <linux/of_device.h>
23 #include <linux/of_gpio.h>
24 #include <linux/gpio.h>
25 #include <linux/mmc/card.h>
26 #include <linux/mmc/host.h>
27
28 #include <asm/gpio.h>
29
30 #include <mach/gpio-tegra.h>
31 #include <mach/sdhci.h>
32
33 #include "sdhci-pltfm.h"
34
35 #define NVQUIRK_FORCE_SDHCI_SPEC_200    BIT(0)
36 #define NVQUIRK_ENABLE_BLOCK_GAP_DET    BIT(1)
37
38 struct sdhci_tegra_soc_data {
39         struct sdhci_pltfm_data *pdata;
40         u32 nvquirks;
41 };
42
43 struct sdhci_tegra {
44         const struct tegra_sdhci_platform_data *plat;
45         const struct sdhci_tegra_soc_data *soc_data;
46 };
47
48 static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
49 {
50         u32 val;
51
52         if (unlikely(reg == SDHCI_PRESENT_STATE)) {
53                 /* Use wp_gpio here instead? */
54                 val = readl(host->ioaddr + reg);
55                 return val | SDHCI_WRITE_PROTECT;
56         }
57
58         return readl(host->ioaddr + reg);
59 }
60
61 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
62 {
63         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
64         struct sdhci_tegra *tegra_host = pltfm_host->priv;
65         const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
66
67         if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
68                         (reg == SDHCI_HOST_VERSION))) {
69                 /* Erratum: Version register is invalid in HW. */
70                 return SDHCI_SPEC_200;
71         }
72
73         return readw(host->ioaddr + reg);
74 }
75
76 static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
77 {
78         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
79         struct sdhci_tegra *tegra_host = pltfm_host->priv;
80         const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
81
82         /* Seems like we're getting spurious timeout and crc errors, so
83          * disable signalling of them. In case of real errors software
84          * timers should take care of eventually detecting them.
85          */
86         if (unlikely(reg == SDHCI_SIGNAL_ENABLE))
87                 val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC);
88
89         writel(val, host->ioaddr + reg);
90
91         if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) &&
92                         (reg == SDHCI_INT_ENABLE))) {
93                 /* Erratum: Must enable block gap interrupt detection */
94                 u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
95                 if (val & SDHCI_INT_CARD_INT)
96                         gap_ctrl |= 0x8;
97                 else
98                         gap_ctrl &= ~0x8;
99                 writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
100         }
101 }
102
103 static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
104 {
105         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
106         struct sdhci_tegra *tegra_host = pltfm_host->priv;
107         const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
108
109         if (!gpio_is_valid(plat->wp_gpio))
110                 return -1;
111
112         return gpio_get_value(plat->wp_gpio);
113 }
114
115 static irqreturn_t carddetect_irq(int irq, void *data)
116 {
117         struct sdhci_host *sdhost = (struct sdhci_host *)data;
118
119         tasklet_schedule(&sdhost->card_tasklet);
120         return IRQ_HANDLED;
121 };
122
123 static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
124 {
125         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
126         struct sdhci_tegra *tegra_host = pltfm_host->priv;
127         const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
128         u32 ctrl;
129
130         ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
131         if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) {
132                 ctrl &= ~SDHCI_CTRL_4BITBUS;
133                 ctrl |= SDHCI_CTRL_8BITBUS;
134         } else {
135                 ctrl &= ~SDHCI_CTRL_8BITBUS;
136                 if (bus_width == MMC_BUS_WIDTH_4)
137                         ctrl |= SDHCI_CTRL_4BITBUS;
138                 else
139                         ctrl &= ~SDHCI_CTRL_4BITBUS;
140         }
141         sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
142         return 0;
143 }
144
145 static struct sdhci_ops tegra_sdhci_ops = {
146         .get_ro     = tegra_sdhci_get_ro,
147         .read_l     = tegra_sdhci_readl,
148         .read_w     = tegra_sdhci_readw,
149         .write_l    = tegra_sdhci_writel,
150         .platform_8bit_width = tegra_sdhci_8bit,
151 };
152
153 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
154 static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
155         .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
156                   SDHCI_QUIRK_SINGLE_POWER_WRITE |
157                   SDHCI_QUIRK_NO_HISPD_BIT |
158                   SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
159         .ops  = &tegra_sdhci_ops,
160 };
161
162 static struct sdhci_tegra_soc_data soc_data_tegra20 = {
163         .pdata = &sdhci_tegra20_pdata,
164         .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
165                     NVQUIRK_ENABLE_BLOCK_GAP_DET,
166 };
167 #endif
168
169 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
170 static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
171         .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
172                   SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
173                   SDHCI_QUIRK_SINGLE_POWER_WRITE |
174                   SDHCI_QUIRK_NO_HISPD_BIT |
175                   SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
176         .ops  = &tegra_sdhci_ops,
177 };
178
179 static struct sdhci_tegra_soc_data soc_data_tegra30 = {
180         .pdata = &sdhci_tegra30_pdata,
181 };
182 #endif
183
184 static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = {
185 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
186         { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
187 #endif
188 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
189         { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
190 #endif
191         {}
192 };
193 MODULE_DEVICE_TABLE(of, sdhci_dt_ids);
194
195 static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
196                                                 struct platform_device *pdev)
197 {
198         struct tegra_sdhci_platform_data *plat;
199         struct device_node *np = pdev->dev.of_node;
200
201         if (!np)
202                 return NULL;
203
204         plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
205         if (!plat) {
206                 dev_err(&pdev->dev, "Can't allocate platform data\n");
207                 return NULL;
208         }
209
210         plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
211         plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
212         plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
213         if (of_find_property(np, "support-8bit", NULL))
214                 plat->is_8bit = 1;
215
216         return plat;
217 }
218
219 static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
220 {
221         const struct of_device_id *match;
222         const struct sdhci_tegra_soc_data *soc_data;
223         struct sdhci_host *host;
224         struct sdhci_pltfm_host *pltfm_host;
225         struct tegra_sdhci_platform_data *plat;
226         struct sdhci_tegra *tegra_host;
227         struct clk *clk;
228         int rc;
229
230         match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
231         if (match)
232                 soc_data = match->data;
233         else
234                 soc_data = &soc_data_tegra20;
235
236         host = sdhci_pltfm_init(pdev, soc_data->pdata);
237         if (IS_ERR(host))
238                 return PTR_ERR(host);
239
240         pltfm_host = sdhci_priv(host);
241
242         plat = pdev->dev.platform_data;
243
244         if (plat == NULL)
245                 plat = sdhci_tegra_dt_parse_pdata(pdev);
246
247         if (plat == NULL) {
248                 dev_err(mmc_dev(host->mmc), "missing platform data\n");
249                 rc = -ENXIO;
250                 goto err_no_plat;
251         }
252
253         tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL);
254         if (!tegra_host) {
255                 dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
256                 rc = -ENOMEM;
257                 goto err_no_plat;
258         }
259
260         tegra_host->plat = plat;
261         tegra_host->soc_data = soc_data;
262
263         pltfm_host->priv = tegra_host;
264
265         if (gpio_is_valid(plat->power_gpio)) {
266                 rc = gpio_request(plat->power_gpio, "sdhci_power");
267                 if (rc) {
268                         dev_err(mmc_dev(host->mmc),
269                                 "failed to allocate power gpio\n");
270                         goto err_power_req;
271                 }
272                 gpio_direction_output(plat->power_gpio, 1);
273         }
274
275         if (gpio_is_valid(plat->cd_gpio)) {
276                 rc = gpio_request(plat->cd_gpio, "sdhci_cd");
277                 if (rc) {
278                         dev_err(mmc_dev(host->mmc),
279                                 "failed to allocate cd gpio\n");
280                         goto err_cd_req;
281                 }
282                 gpio_direction_input(plat->cd_gpio);
283
284                 rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
285                                  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
286                                  mmc_hostname(host->mmc), host);
287
288                 if (rc) {
289                         dev_err(mmc_dev(host->mmc), "request irq error\n");
290                         goto err_cd_irq_req;
291                 }
292
293         }
294
295         if (gpio_is_valid(plat->wp_gpio)) {
296                 rc = gpio_request(plat->wp_gpio, "sdhci_wp");
297                 if (rc) {
298                         dev_err(mmc_dev(host->mmc),
299                                 "failed to allocate wp gpio\n");
300                         goto err_wp_req;
301                 }
302                 gpio_direction_input(plat->wp_gpio);
303         }
304
305         clk = clk_get(mmc_dev(host->mmc), NULL);
306         if (IS_ERR(clk)) {
307                 dev_err(mmc_dev(host->mmc), "clk err\n");
308                 rc = PTR_ERR(clk);
309                 goto err_clk_get;
310         }
311         clk_enable(clk);
312         pltfm_host->clk = clk;
313
314         host->mmc->pm_caps = plat->pm_flags;
315
316         if (plat->is_8bit)
317                 host->mmc->caps |= MMC_CAP_8_BIT_DATA;
318
319         rc = sdhci_add_host(host);
320         if (rc)
321                 goto err_add_host;
322
323         return 0;
324
325 err_add_host:
326         clk_disable(pltfm_host->clk);
327         clk_put(pltfm_host->clk);
328 err_clk_get:
329         if (gpio_is_valid(plat->wp_gpio))
330                 gpio_free(plat->wp_gpio);
331 err_wp_req:
332         if (gpio_is_valid(plat->cd_gpio))
333                 free_irq(gpio_to_irq(plat->cd_gpio), host);
334 err_cd_irq_req:
335         if (gpio_is_valid(plat->cd_gpio))
336                 gpio_free(plat->cd_gpio);
337 err_cd_req:
338         if (gpio_is_valid(plat->power_gpio))
339                 gpio_free(plat->power_gpio);
340 err_power_req:
341 err_no_plat:
342         sdhci_pltfm_free(pdev);
343         return rc;
344 }
345
346 static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
347 {
348         struct sdhci_host *host = platform_get_drvdata(pdev);
349         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
350         struct sdhci_tegra *tegra_host = pltfm_host->priv;
351         const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
352         int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
353
354         sdhci_remove_host(host, dead);
355
356         if (gpio_is_valid(plat->wp_gpio))
357                 gpio_free(plat->wp_gpio);
358
359         if (gpio_is_valid(plat->cd_gpio)) {
360                 free_irq(gpio_to_irq(plat->cd_gpio), host);
361                 gpio_free(plat->cd_gpio);
362         }
363
364         if (gpio_is_valid(plat->power_gpio))
365                 gpio_free(plat->power_gpio);
366
367         clk_disable(pltfm_host->clk);
368         clk_put(pltfm_host->clk);
369
370         sdhci_pltfm_free(pdev);
371
372         return 0;
373 }
374
375 static struct platform_driver sdhci_tegra_driver = {
376         .driver         = {
377                 .name   = "sdhci-tegra",
378                 .owner  = THIS_MODULE,
379                 .of_match_table = sdhci_tegra_dt_match,
380                 .pm     = SDHCI_PLTFM_PMOPS,
381         },
382         .probe          = sdhci_tegra_probe,
383         .remove         = __devexit_p(sdhci_tegra_remove),
384 };
385
386 module_platform_driver(sdhci_tegra_driver);
387
388 MODULE_DESCRIPTION("SDHCI driver for Tegra");
389 MODULE_AUTHOR("Google, Inc.");
390 MODULE_LICENSE("GPL v2");