aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2010-09-02 10:15:08 -0400
committerChris Ball <cjb@laptop.org>2010-10-23 09:11:11 -0400
commit53f3a9e26ed5a94bd3caf732e7635692cd3c4402 (patch)
tree4324614f7891ff66eea931f146fec64769b9bb1e /drivers/mmc/host
parenta36274e0184193e393fb82957925c3981a6b0477 (diff)
mmc: USB SD Host Controller (USHC) driver
Add a driver for USB SD Host Controller devices. These devices are Cypress Astoria chips with firmware compliant with issue 2 of CSR's USHC specification. [cjb: adapt to block layer deprecation of max_{hw,phys}_segs] Signed-off-by: David Vrabel <david.vrabel@csr.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/Kconfig14
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/ushc.c566
3 files changed, 581 insertions, 0 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 68d12794cfd9..8de7b9e8fc51 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -451,3 +451,17 @@ config MMC_JZ4740
451 SoCs. 451 SoCs.
452 If you have a board based on such a SoC and with a SD/MMC slot, 452 If you have a board based on such a SoC and with a SD/MMC slot,
453 say Y or M here. 453 say Y or M here.
454
455config MMC_USHC
456 tristate "USB SD Host Controller (USHC) support"
457 depends on USB
458 help
459 This selects support for USB SD Host Controllers based on
460 the Cypress Astoria chip with firmware compliant with CSR's
461 USB SD Host Controller specification (CS-118793-SP).
462
463 CSR boards with this device include: USB<>SDIO (M1985v2),
464 and Ultrasira.
465
466 Note: These controllers only support SDIO cards and do not
467 support MMC or SD memory cards.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 840bcb52d82f..f7fb7eb234b9 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
36obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o 36obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
37obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o 37obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
38obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o 38obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
39obj-$(CONFIG_MMC_USHC) += ushc.o
39 40
40obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o 41obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o
41sdhci-platform-y := sdhci-pltfm.o 42sdhci-platform-y := sdhci-pltfm.o
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
new file mode 100644
index 000000000000..b4ead4a13c98
--- /dev/null
+++ b/drivers/mmc/host/ushc.c
@@ -0,0 +1,566 @@
1/*
2 * USB SD Host Controller (USHC) controller driver.
3 *
4 * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * Notes:
12 * - Only version 2 devices are supported.
13 * - Version 2 devices only support SDIO cards/devices (R2 response is
14 * unsupported).
15 *
16 * References:
17 * [USHC] USB SD Host Controller specification (CS-118793-SP)
18 */
19#include <linux/module.h>
20#include <linux/usb.h>
21#include <linux/kernel.h>
22#include <linux/usb.h>
23#include <linux/slab.h>
24#include <linux/dma-mapping.h>
25#include <linux/mmc/host.h>
26
27enum ushc_request {
28 USHC_GET_CAPS = 0x00,
29 USHC_HOST_CTRL = 0x01,
30 USHC_PWR_CTRL = 0x02,
31 USHC_CLK_FREQ = 0x03,
32 USHC_EXEC_CMD = 0x04,
33 USHC_READ_RESP = 0x05,
34 USHC_RESET = 0x06,
35};
36
37enum ushc_request_type {
38 USHC_GET_CAPS_TYPE = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
39 USHC_HOST_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
40 USHC_PWR_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
41 USHC_CLK_FREQ_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
42 USHC_EXEC_CMD_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
43 USHC_READ_RESP_TYPE = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
44 USHC_RESET_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
45};
46
47#define USHC_GET_CAPS_VERSION_MASK 0xff
48#define USHC_GET_CAPS_3V3 (1 << 8)
49#define USHC_GET_CAPS_3V0 (1 << 9)
50#define USHC_GET_CAPS_1V8 (1 << 10)
51#define USHC_GET_CAPS_HIGH_SPD (1 << 16)
52
53#define USHC_HOST_CTRL_4BIT (1 << 1)
54#define USHC_HOST_CTRL_HIGH_SPD (1 << 0)
55
56#define USHC_PWR_CTRL_OFF 0x00
57#define USHC_PWR_CTRL_3V3 0x01
58#define USHC_PWR_CTRL_3V0 0x02
59#define USHC_PWR_CTRL_1V8 0x03
60
61#define USHC_READ_RESP_BUSY (1 << 4)
62#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3)
63#define USHC_READ_RESP_ERR_CRC (1 << 2)
64#define USHC_READ_RESP_ERR_DAT (1 << 1)
65#define USHC_READ_RESP_ERR_CMD (1 << 0)
66#define USHC_READ_RESP_ERR_MASK 0x0f
67
68struct ushc_cbw {
69 __u8 signature;
70 __u8 cmd_idx;
71 __le16 block_size;
72 __le32 arg;
73} __attribute__((packed));
74
75#define USHC_CBW_SIGNATURE 'C'
76
77struct ushc_csw {
78 __u8 signature;
79 __u8 status;
80 __le32 response;
81} __attribute__((packed));
82
83#define USHC_CSW_SIGNATURE 'S'
84
85struct ushc_int_data {
86 u8 status;
87 u8 reserved[3];
88};
89
90#define USHC_INT_STATUS_SDIO_INT (1 << 1)
91#define USHC_INT_STATUS_CARD_PRESENT (1 << 0)
92
93
94struct ushc_data {
95 struct usb_device *usb_dev;
96 struct mmc_host *mmc;
97
98 struct urb *int_urb;
99 struct ushc_int_data *int_data;
100
101 struct urb *cbw_urb;
102 struct ushc_cbw *cbw;
103
104 struct urb *data_urb;
105
106 struct urb *csw_urb;
107 struct ushc_csw *csw;
108
109 spinlock_t lock;
110 struct mmc_request *current_req;
111 u32 caps;
112 u16 host_ctrl;
113 unsigned long flags;
114 u8 last_status;
115 int clock_freq;
116};
117
118#define DISCONNECTED 0
119#define INT_EN 1
120#define IGNORE_NEXT_INT 2
121
122static void data_callback(struct urb *urb);
123
124static int ushc_hw_reset(struct ushc_data *ushc)
125{
126 return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
127 USHC_RESET, USHC_RESET_TYPE,
128 0, 0, NULL, 0, 100);
129}
130
131static int ushc_hw_get_caps(struct ushc_data *ushc)
132{
133 int ret;
134 int version;
135
136 ret = usb_control_msg(ushc->usb_dev, usb_rcvctrlpipe(ushc->usb_dev, 0),
137 USHC_GET_CAPS, USHC_GET_CAPS_TYPE,
138 0, 0, &ushc->caps, sizeof(ushc->caps), 100);
139 if (ret < 0)
140 return ret;
141
142 ushc->caps = le32_to_cpu(ushc->caps);
143
144 version = ushc->caps & USHC_GET_CAPS_VERSION_MASK;
145 if (version != 0x02) {
146 dev_err(&ushc->usb_dev->dev, "controller version %d is not supported\n", version);
147 return -EINVAL;
148 }
149
150 return 0;
151}
152
153static int ushc_hw_set_host_ctrl(struct ushc_data *ushc, u16 mask, u16 val)
154{
155 u16 host_ctrl;
156 int ret;
157
158 host_ctrl = (ushc->host_ctrl & ~mask) | val;
159 ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
160 USHC_HOST_CTRL, USHC_HOST_CTRL_TYPE,
161 host_ctrl, 0, NULL, 0, 100);
162 if (ret < 0)
163 return ret;
164 ushc->host_ctrl = host_ctrl;
165 return 0;
166}
167
168static void int_callback(struct urb *urb)
169{
170 struct ushc_data *ushc = urb->context;
171 u8 status, last_status;
172
173 if (urb->status < 0)
174 return;
175
176 status = ushc->int_data->status;
177 last_status = ushc->last_status;
178 ushc->last_status = status;
179
180 /*
181 * Ignore the card interrupt status on interrupt transfers that
182 * were submitted while card interrupts where disabled.
183 *
184 * This avoid occasional spurious interrupts when enabling
185 * interrupts immediately after clearing the source on the card.
186 */
187
188 if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags)
189 && test_bit(INT_EN, &ushc->flags)
190 && status & USHC_INT_STATUS_SDIO_INT) {
191 mmc_signal_sdio_irq(ushc->mmc);
192 }
193
194 if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT)
195 mmc_detect_change(ushc->mmc, msecs_to_jiffies(100));
196
197 if (!test_bit(INT_EN, &ushc->flags))
198 set_bit(IGNORE_NEXT_INT, &ushc->flags);
199 usb_submit_urb(ushc->int_urb, GFP_ATOMIC);
200}
201
202static void cbw_callback(struct urb *urb)
203{
204 struct ushc_data *ushc = urb->context;
205
206 if (urb->status != 0) {
207 usb_unlink_urb(ushc->data_urb);
208 usb_unlink_urb(ushc->csw_urb);
209 }
210}
211
212static void data_callback(struct urb *urb)
213{
214 struct ushc_data *ushc = urb->context;
215
216 if (urb->status != 0)
217 usb_unlink_urb(ushc->csw_urb);
218}
219
220static void csw_callback(struct urb *urb)
221{
222 struct ushc_data *ushc = urb->context;
223 struct mmc_request *req = ushc->current_req;
224 int status;
225
226 status = ushc->csw->status;
227
228 if (urb->status != 0) {
229 req->cmd->error = urb->status;
230 } else if (status & USHC_READ_RESP_ERR_CMD) {
231 if (status & USHC_READ_RESP_ERR_CRC)
232 req->cmd->error = -EIO;
233 else
234 req->cmd->error = -ETIMEDOUT;
235 }
236 if (req->data) {
237 if (status & USHC_READ_RESP_ERR_DAT) {
238 if (status & USHC_READ_RESP_ERR_CRC)
239 req->data->error = -EIO;
240 else
241 req->data->error = -ETIMEDOUT;
242 req->data->bytes_xfered = 0;
243 } else {
244 req->data->bytes_xfered = req->data->blksz * req->data->blocks;
245 }
246 }
247
248 req->cmd->resp[0] = le32_to_cpu(ushc->csw->response);
249
250 mmc_request_done(ushc->mmc, req);
251}
252
253static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
254{
255 struct ushc_data *ushc = mmc_priv(mmc);
256 int ret;
257 unsigned long flags;
258
259 spin_lock_irqsave(&ushc->lock, flags);
260
261 if (test_bit(DISCONNECTED, &ushc->flags)) {
262 ret = -ENODEV;
263 goto out;
264 }
265
266 /* Version 2 firmware doesn't support the R2 response format. */
267 if (req->cmd->flags & MMC_RSP_136) {
268 ret = -EINVAL;
269 goto out;
270 }
271
272 /* The Astoria's data FIFOs don't work with clock speeds < 5MHz so
273 limit commands with data to 6MHz or more. */
274 if (req->data && ushc->clock_freq < 6000000) {
275 ret = -EINVAL;
276 goto out;
277 }
278
279 ushc->current_req = req;
280
281 /* Start cmd with CBW. */
282 ushc->cbw->cmd_idx = cpu_to_le16(req->cmd->opcode);
283 if (req->data)
284 ushc->cbw->block_size = cpu_to_le16(req->data->blksz);
285 else
286 ushc->cbw->block_size = 0;
287 ushc->cbw->arg = cpu_to_le32(req->cmd->arg);
288
289 ret = usb_submit_urb(ushc->cbw_urb, GFP_ATOMIC);
290 if (ret < 0)
291 goto out;
292
293 /* Submit data (if any). */
294 if (req->data) {
295 struct mmc_data *data = req->data;
296 int pipe;
297
298 if (data->flags & MMC_DATA_READ)
299 pipe = usb_rcvbulkpipe(ushc->usb_dev, 6);
300 else
301 pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
302
303 usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
304 sg_virt(data->sg), data->sg->length,
305 data_callback, ushc);
306 ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
307 if (ret < 0)
308 goto out;
309 }
310
311 /* Submit CSW. */
312 ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC);
313 if (ret < 0)
314 goto out;
315
316out:
317 spin_unlock_irqrestore(&ushc->lock, flags);
318 if (ret < 0) {
319 usb_unlink_urb(ushc->cbw_urb);
320 usb_unlink_urb(ushc->data_urb);
321 req->cmd->error = ret;
322 mmc_request_done(mmc, req);
323 }
324}
325
326static int ushc_set_power(struct ushc_data *ushc, unsigned char power_mode)
327{
328 u16 voltage;
329
330 switch (power_mode) {
331 case MMC_POWER_OFF:
332 voltage = USHC_PWR_CTRL_OFF;
333 break;
334 case MMC_POWER_UP:
335 case MMC_POWER_ON:
336 voltage = USHC_PWR_CTRL_3V3;
337 break;
338 default:
339 return -EINVAL;
340 }
341
342 return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
343 USHC_PWR_CTRL, USHC_PWR_CTRL_TYPE,
344 voltage, 0, NULL, 0, 100);
345}
346
347static int ushc_set_bus_width(struct ushc_data *ushc, int bus_width)
348{
349 return ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_4BIT,
350 bus_width == 4 ? USHC_HOST_CTRL_4BIT : 0);
351}
352
353static int ushc_set_bus_freq(struct ushc_data *ushc, int clk, bool enable_hs)
354{
355 int ret;
356
357 /* Hardware can't detect interrupts while the clock is off. */
358 if (clk == 0)
359 clk = 400000;
360
361 ret = ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_HIGH_SPD,
362 enable_hs ? USHC_HOST_CTRL_HIGH_SPD : 0);
363 if (ret < 0)
364 return ret;
365
366 ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
367 USHC_CLK_FREQ, USHC_CLK_FREQ_TYPE,
368 clk & 0xffff, (clk >> 16) & 0xffff, NULL, 0, 100);
369 if (ret < 0)
370 return ret;
371
372 ushc->clock_freq = clk;
373 return 0;
374}
375
376static void ushc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
377{
378 struct ushc_data *ushc = mmc_priv(mmc);
379
380 ushc_set_power(ushc, ios->power_mode);
381 ushc_set_bus_width(ushc, 1 << ios->bus_width);
382 ushc_set_bus_freq(ushc, ios->clock, ios->timing == MMC_TIMING_SD_HS);
383}
384
385static int ushc_get_cd(struct mmc_host *mmc)
386{
387 struct ushc_data *ushc = mmc_priv(mmc);
388
389 return !!(ushc->last_status & USHC_INT_STATUS_CARD_PRESENT);
390}
391
392static void ushc_enable_sdio_irq(struct mmc_host *mmc, int enable)
393{
394 struct ushc_data *ushc = mmc_priv(mmc);
395
396 if (enable)
397 set_bit(INT_EN, &ushc->flags);
398 else
399 clear_bit(INT_EN, &ushc->flags);
400}
401
402static void ushc_clean_up(struct ushc_data *ushc)
403{
404 usb_free_urb(ushc->int_urb);
405 usb_free_urb(ushc->csw_urb);
406 usb_free_urb(ushc->data_urb);
407 usb_free_urb(ushc->cbw_urb);
408
409 kfree(ushc->int_data);
410 kfree(ushc->cbw);
411 kfree(ushc->csw);
412
413 mmc_free_host(ushc->mmc);
414}
415
416static const struct mmc_host_ops ushc_ops = {
417 .request = ushc_request,
418 .set_ios = ushc_set_ios,
419 .get_cd = ushc_get_cd,
420 .enable_sdio_irq = ushc_enable_sdio_irq,
421};
422
423static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id)
424{
425 struct usb_device *usb_dev = interface_to_usbdev(intf);
426 struct mmc_host *mmc;
427 struct ushc_data *ushc;
428 int ret = -ENOMEM;
429
430 mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
431 if (mmc == NULL)
432 return -ENOMEM;
433 ushc = mmc_priv(mmc);
434 usb_set_intfdata(intf, ushc);
435
436 ushc->usb_dev = usb_dev;
437 ushc->mmc = mmc;
438
439 spin_lock_init(&ushc->lock);
440
441 ret = ushc_hw_reset(ushc);
442 if (ret < 0)
443 goto err;
444
445 /* Read capabilities. */
446 ret = ushc_hw_get_caps(ushc);
447 if (ret < 0)
448 goto err;
449
450 mmc->ops = &ushc_ops;
451
452 mmc->f_min = 400000;
453 mmc->f_max = 50000000;
454 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
455 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
456 mmc->caps |= (ushc->caps & USHC_GET_CAPS_HIGH_SPD) ? MMC_CAP_SD_HIGHSPEED : 0;
457
458 mmc->max_seg_size = 512*511;
459 mmc->max_segs = 1;
460 mmc->max_req_size = 512*511;
461 mmc->max_blk_size = 512;
462 mmc->max_blk_count = 511;
463
464 ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
465 if (ushc->int_urb == NULL)
466 goto err;
467 ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
468 if (ushc->int_data == NULL)
469 goto err;
470 usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
471 usb_rcvintpipe(usb_dev,
472 intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
473 ushc->int_data, sizeof(struct ushc_int_data),
474 int_callback, ushc,
475 intf->cur_altsetting->endpoint[0].desc.bInterval);
476
477 ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
478 if (ushc->cbw_urb == NULL)
479 goto err;
480 ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
481 if (ushc->cbw == NULL)
482 goto err;
483 ushc->cbw->signature = USHC_CBW_SIGNATURE;
484
485 usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
486 ushc->cbw, sizeof(struct ushc_cbw),
487 cbw_callback, ushc);
488
489 ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
490 if (ushc->data_urb == NULL)
491 goto err;
492
493 ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
494 if (ushc->csw_urb == NULL)
495 goto err;
496 ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
497 if (ushc->csw == NULL)
498 goto err;
499 usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
500 ushc->csw, sizeof(struct ushc_csw),
501 csw_callback, ushc);
502
503 ret = mmc_add_host(ushc->mmc);
504 if (ret)
505 goto err;
506
507 ret = usb_submit_urb(ushc->int_urb, GFP_KERNEL);
508 if (ret < 0) {
509 mmc_remove_host(ushc->mmc);
510 goto err;
511 }
512
513 return 0;
514
515err:
516 ushc_clean_up(ushc);
517 return ret;
518}
519
520static void ushc_disconnect(struct usb_interface *intf)
521{
522 struct ushc_data *ushc = usb_get_intfdata(intf);
523
524 spin_lock_irq(&ushc->lock);
525 set_bit(DISCONNECTED, &ushc->flags);
526 spin_unlock_irq(&ushc->lock);
527
528 usb_kill_urb(ushc->int_urb);
529 usb_kill_urb(ushc->cbw_urb);
530 usb_kill_urb(ushc->data_urb);
531 usb_kill_urb(ushc->csw_urb);
532
533 mmc_remove_host(ushc->mmc);
534
535 ushc_clean_up(ushc);
536}
537
538static struct usb_device_id ushc_id_table[] = {
539 /* CSR USB SD Host Controller */
540 { USB_DEVICE(0x0a12, 0x5d10) },
541 { },
542};
543MODULE_DEVICE_TABLE(usb, ushc_id_table);
544
545static struct usb_driver ushc_driver = {
546 .name = "ushc",
547 .id_table = ushc_id_table,
548 .probe = ushc_probe,
549 .disconnect = ushc_disconnect,
550};
551
552static int __init ushc_init(void)
553{
554 return usb_register(&ushc_driver);
555}
556module_init(ushc_init);
557
558static void __exit ushc_exit(void)
559{
560 usb_deregister(&ushc_driver);
561}
562module_exit(ushc_exit);
563
564MODULE_DESCRIPTION("USB SD Host Controller driver");
565MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>");
566MODULE_LICENSE("GPL");