~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise-security

« back to all changes in this revision

Viewing changes to drivers/mmc/host/sdhci-tegra.c

  • Committer: Package Import Robot
  • Author(s): Paolo Pisati, Paolo Pisati
  • Date: 2011-12-06 15:56:07 UTC
  • Revision ID: package-import@ubuntu.com-20111206155607-pcf44kv5fmhk564f
Tags: 3.2.0-1401.1
[ Paolo Pisati ]

* Rebased on top of Ubuntu-3.2.0-3.8
* Tilt-tracking @ ef2487af4bb15bdd0689631774b5a5e3a59f74e2
* Delete debian.ti-omap4/control, it shoudln't be tracked
* Fix architecture spelling (s/armel/armhf/)
* [Config] Update configs following 3.2 import
* [Config] Fix compilation: disable CODA and ARCH_OMAP3
* [Config] Fix compilation: disable Ethernet Faraday
* Update series to precise

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 */
14
14
 
15
15
#include <linux/err.h>
 
16
#include <linux/module.h>
16
17
#include <linux/init.h>
17
18
#include <linux/platform_device.h>
18
19
#include <linux/clk.h>
19
20
#include <linux/io.h>
 
21
#include <linux/of.h>
 
22
#include <linux/of_gpio.h>
20
23
#include <linux/gpio.h>
21
24
#include <linux/mmc/card.h>
22
25
#include <linux/mmc/host.h>
23
 
 
24
 
#include <mach/gpio.h>
 
26
#include <linux/module.h>
 
27
 
 
28
#include <asm/gpio.h>
 
29
 
 
30
#include <mach/gpio-tegra.h>
25
31
#include <mach/sdhci.h>
26
32
 
27
 
#include "sdhci.h"
28
33
#include "sdhci-pltfm.h"
29
34
 
30
35
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
74
79
 
75
80
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
76
81
{
77
 
        struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc));
78
 
        struct tegra_sdhci_platform_data *plat;
79
 
 
80
 
        plat = pdev->dev.platform_data;
 
82
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
 
83
        struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
81
84
 
82
85
        if (!gpio_is_valid(plat->wp_gpio))
83
86
                return -1;
95
98
 
96
99
static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
97
100
{
98
 
        struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
99
 
        struct tegra_sdhci_platform_data *plat;
 
101
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 
102
        struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
100
103
        u32 ctrl;
101
104
 
102
 
        plat = pdev->dev.platform_data;
103
 
 
104
105
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
105
106
        if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) {
106
107
                ctrl &= ~SDHCI_CTRL_4BITBUS;
116
117
        return 0;
117
118
}
118
119
 
119
 
 
120
 
static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
121
 
                                  struct sdhci_pltfm_data *pdata)
122
 
{
123
 
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
124
 
        struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
125
 
        struct tegra_sdhci_platform_data *plat;
 
120
static struct sdhci_ops tegra_sdhci_ops = {
 
121
        .get_ro     = tegra_sdhci_get_ro,
 
122
        .read_l     = tegra_sdhci_readl,
 
123
        .read_w     = tegra_sdhci_readw,
 
124
        .write_l    = tegra_sdhci_writel,
 
125
        .platform_8bit_width = tegra_sdhci_8bit,
 
126
};
 
127
 
 
128
static struct sdhci_pltfm_data sdhci_tegra_pdata = {
 
129
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
 
130
                  SDHCI_QUIRK_SINGLE_POWER_WRITE |
 
131
                  SDHCI_QUIRK_NO_HISPD_BIT |
 
132
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
 
133
        .ops  = &tegra_sdhci_ops,
 
134
};
 
135
 
 
136
static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = {
 
137
        { .compatible = "nvidia,tegra20-sdhci", },
 
138
        {}
 
139
};
 
140
MODULE_DEVICE_TABLE(of, sdhci_dt_ids);
 
141
 
 
142
static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
 
143
                                                struct platform_device *pdev)
 
144
{
 
145
        struct tegra_sdhci_platform_data *plat;
 
146
        struct device_node *np = pdev->dev.of_node;
 
147
 
 
148
        if (!np)
 
149
                return NULL;
 
150
 
 
151
        plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
 
152
        if (!plat) {
 
153
                dev_err(&pdev->dev, "Can't allocate platform data\n");
 
154
                return NULL;
 
155
        }
 
156
 
 
157
        plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
 
158
        plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
 
159
        plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
 
160
        if (of_find_property(np, "support-8bit", NULL))
 
161
                plat->is_8bit = 1;
 
162
 
 
163
        return plat;
 
164
}
 
165
 
 
166
static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 
167
{
 
168
        struct sdhci_pltfm_host *pltfm_host;
 
169
        struct tegra_sdhci_platform_data *plat;
 
170
        struct sdhci_host *host;
126
171
        struct clk *clk;
127
172
        int rc;
128
173
 
 
174
        host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
 
175
        if (IS_ERR(host))
 
176
                return PTR_ERR(host);
 
177
 
 
178
        pltfm_host = sdhci_priv(host);
 
179
 
129
180
        plat = pdev->dev.platform_data;
 
181
 
 
182
        if (plat == NULL)
 
183
                plat = sdhci_tegra_dt_parse_pdata(pdev);
 
184
 
130
185
        if (plat == NULL) {
131
186
                dev_err(mmc_dev(host->mmc), "missing platform data\n");
132
 
                return -ENXIO;
 
187
                rc = -ENXIO;
 
188
                goto err_no_plat;
133
189
        }
134
190
 
 
191
        pltfm_host->priv = plat;
 
192
 
135
193
        if (gpio_is_valid(plat->power_gpio)) {
136
194
                rc = gpio_request(plat->power_gpio, "sdhci_power");
137
195
                if (rc) {
138
196
                        dev_err(mmc_dev(host->mmc),
139
197
                                "failed to allocate power gpio\n");
140
 
                        goto out;
 
198
                        goto err_power_req;
141
199
                }
142
200
                tegra_gpio_enable(plat->power_gpio);
143
201
                gpio_direction_output(plat->power_gpio, 1);
148
206
                if (rc) {
149
207
                        dev_err(mmc_dev(host->mmc),
150
208
                                "failed to allocate cd gpio\n");
151
 
                        goto out_power;
 
209
                        goto err_cd_req;
152
210
                }
153
211
                tegra_gpio_enable(plat->cd_gpio);
154
212
                gpio_direction_input(plat->cd_gpio);
159
217
 
160
218
                if (rc) {
161
219
                        dev_err(mmc_dev(host->mmc), "request irq error\n");
162
 
                        goto out_cd;
 
220
                        goto err_cd_irq_req;
163
221
                }
164
222
 
165
223
        }
169
227
                if (rc) {
170
228
                        dev_err(mmc_dev(host->mmc),
171
229
                                "failed to allocate wp gpio\n");
172
 
                        goto out_irq;
 
230
                        goto err_wp_req;
173
231
                }
174
232
                tegra_gpio_enable(plat->wp_gpio);
175
233
                gpio_direction_input(plat->wp_gpio);
179
237
        if (IS_ERR(clk)) {
180
238
                dev_err(mmc_dev(host->mmc), "clk err\n");
181
239
                rc = PTR_ERR(clk);
182
 
                goto out_wp;
 
240
                goto err_clk_get;
183
241
        }
184
242
        clk_enable(clk);
185
243
        pltfm_host->clk = clk;
189
247
        if (plat->is_8bit)
190
248
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
191
249
 
 
250
        rc = sdhci_add_host(host);
 
251
        if (rc)
 
252
                goto err_add_host;
 
253
 
192
254
        return 0;
193
255
 
194
 
out_wp:
 
256
err_add_host:
 
257
        clk_disable(pltfm_host->clk);
 
258
        clk_put(pltfm_host->clk);
 
259
err_clk_get:
195
260
        if (gpio_is_valid(plat->wp_gpio)) {
196
261
                tegra_gpio_disable(plat->wp_gpio);
197
262
                gpio_free(plat->wp_gpio);
198
263
        }
199
 
 
200
 
out_irq:
 
264
err_wp_req:
201
265
        if (gpio_is_valid(plat->cd_gpio))
202
266
                free_irq(gpio_to_irq(plat->cd_gpio), host);
203
 
out_cd:
 
267
err_cd_irq_req:
204
268
        if (gpio_is_valid(plat->cd_gpio)) {
205
269
                tegra_gpio_disable(plat->cd_gpio);
206
270
                gpio_free(plat->cd_gpio);
207
271
        }
208
 
 
209
 
out_power:
 
272
err_cd_req:
210
273
        if (gpio_is_valid(plat->power_gpio)) {
211
274
                tegra_gpio_disable(plat->power_gpio);
212
275
                gpio_free(plat->power_gpio);
213
276
        }
214
 
 
215
 
out:
 
277
err_power_req:
 
278
err_no_plat:
 
279
        sdhci_pltfm_free(pdev);
216
280
        return rc;
217
281
}
218
282
 
219
 
static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
 
283
static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
220
284
{
 
285
        struct sdhci_host *host = platform_get_drvdata(pdev);
221
286
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
222
 
        struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
223
 
        struct tegra_sdhci_platform_data *plat;
 
287
        struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
 
288
        int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
224
289
 
225
 
        plat = pdev->dev.platform_data;
 
290
        sdhci_remove_host(host, dead);
226
291
 
227
292
        if (gpio_is_valid(plat->wp_gpio)) {
228
293
                tegra_gpio_disable(plat->wp_gpio);
242
307
 
243
308
        clk_disable(pltfm_host->clk);
244
309
        clk_put(pltfm_host->clk);
245
 
}
246
 
 
247
 
static struct sdhci_ops tegra_sdhci_ops = {
248
 
        .get_ro     = tegra_sdhci_get_ro,
249
 
        .read_l     = tegra_sdhci_readl,
250
 
        .read_w     = tegra_sdhci_readw,
251
 
        .write_l    = tegra_sdhci_writel,
252
 
        .platform_8bit_width = tegra_sdhci_8bit,
253
 
};
254
 
 
255
 
struct sdhci_pltfm_data sdhci_tegra_pdata = {
256
 
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
257
 
                  SDHCI_QUIRK_SINGLE_POWER_WRITE |
258
 
                  SDHCI_QUIRK_NO_HISPD_BIT |
259
 
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
260
 
        .ops  = &tegra_sdhci_ops,
261
 
        .init = tegra_sdhci_pltfm_init,
262
 
        .exit = tegra_sdhci_pltfm_exit,
263
 
};
 
310
 
 
311
        sdhci_pltfm_free(pdev);
 
312
 
 
313
        return 0;
 
314
}
 
315
 
 
316
static struct platform_driver sdhci_tegra_driver = {
 
317
        .driver         = {
 
318
                .name   = "sdhci-tegra",
 
319
                .owner  = THIS_MODULE,
 
320
                .of_match_table = sdhci_tegra_dt_match,
 
321
        },
 
322
        .probe          = sdhci_tegra_probe,
 
323
        .remove         = __devexit_p(sdhci_tegra_remove),
 
324
#ifdef CONFIG_PM
 
325
        .suspend        = sdhci_pltfm_suspend,
 
326
        .resume         = sdhci_pltfm_resume,
 
327
#endif
 
328
};
 
329
 
 
330
static int __init sdhci_tegra_init(void)
 
331
{
 
332
        return platform_driver_register(&sdhci_tegra_driver);
 
333
}
 
334
module_init(sdhci_tegra_init);
 
335
 
 
336
static void __exit sdhci_tegra_exit(void)
 
337
{
 
338
        platform_driver_unregister(&sdhci_tegra_driver);
 
339
}
 
340
module_exit(sdhci_tegra_exit);
 
341
 
 
342
MODULE_DESCRIPTION("SDHCI driver for Tegra");
 
343
MODULE_AUTHOR(" Google, Inc.");
 
344
MODULE_LICENSE("GPL v2");