1 | /* |
2 | * MOXA ART MMC host driver. |
3 | * |
4 | * Copyright (C) 2014 Jonas Jensen |
5 | * |
6 | * Jonas Jensen <jonas.jensen@gmail.com> |
7 | * |
8 | * Based on code from |
9 | * Moxa Technologies Co., Ltd. <www.moxa.com> |
10 | * |
11 | * This file is licensed under the terms of the GNU General Public |
12 | * License version 2. This program is licensed "as is" without any |
13 | * warranty of any kind, whether express or implied. |
14 | */ |
15 | |
16 | #include <linux/module.h> |
17 | #include <linux/init.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/errno.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/blkdev.h> |
23 | #include <linux/dma-mapping.h> |
24 | #include <linux/dmaengine.h> |
25 | #include <linux/mmc/host.h> |
26 | #include <linux/mmc/sd.h> |
27 | #include <linux/sched.h> |
28 | #include <linux/io.h> |
29 | #include <linux/of_address.h> |
30 | #include <linux/of_irq.h> |
31 | #include <linux/clk.h> |
32 | #include <linux/bitops.h> |
33 | #include <linux/of_dma.h> |
34 | #include <linux/spinlock.h> |
35 | |
36 | #define REG_COMMAND 0 |
37 | #define REG_ARGUMENT 4 |
38 | #define REG_RESPONSE0 8 |
39 | #define REG_RESPONSE1 12 |
40 | #define REG_RESPONSE2 16 |
41 | #define REG_RESPONSE3 20 |
42 | #define REG_RESPONSE_COMMAND 24 |
43 | #define REG_DATA_CONTROL 28 |
44 | #define REG_DATA_TIMER 32 |
45 | #define REG_DATA_LENGTH 36 |
46 | #define REG_STATUS 40 |
47 | #define REG_CLEAR 44 |
48 | #define REG_INTERRUPT_MASK 48 |
49 | #define REG_POWER_CONTROL 52 |
50 | #define REG_CLOCK_CONTROL 56 |
51 | #define REG_BUS_WIDTH 60 |
52 | #define REG_DATA_WINDOW 64 |
53 | #define REG_FEATURE 68 |
54 | #define REG_REVISION 72 |
55 | |
56 | /* REG_COMMAND */ |
57 | #define CMD_SDC_RESET BIT(10) |
58 | #define CMD_EN BIT(9) |
59 | #define CMD_APP_CMD BIT(8) |
60 | #define CMD_LONG_RSP BIT(7) |
61 | #define CMD_NEED_RSP BIT(6) |
62 | #define CMD_IDX_MASK 0x3f |
63 | |
64 | /* REG_RESPONSE_COMMAND */ |
65 | #define RSP_CMD_APP BIT(6) |
66 | #define RSP_CMD_IDX_MASK 0x3f |
67 | |
68 | /* REG_DATA_CONTROL */ |
69 | #define DCR_DATA_FIFO_RESET BIT(8) |
70 | #define DCR_DATA_THRES BIT(7) |
71 | #define DCR_DATA_EN BIT(6) |
72 | #define DCR_DMA_EN BIT(5) |
73 | #define DCR_DATA_WRITE BIT(4) |
74 | #define DCR_BLK_SIZE 0x0f |
75 | |
76 | /* REG_DATA_LENGTH */ |
77 | #define DATA_LEN_MASK 0xffffff |
78 | |
79 | /* REG_STATUS */ |
80 | #define WRITE_PROT BIT(12) |
81 | #define CARD_DETECT BIT(11) |
82 | /* 1-10 below can be sent to either registers, interrupt or clear. */ |
83 | #define CARD_CHANGE BIT(10) |
84 | #define FIFO_ORUN BIT(9) |
85 | #define FIFO_URUN BIT(8) |
86 | #define DATA_END BIT(7) |
87 | #define CMD_SENT BIT(6) |
88 | #define DATA_CRC_OK BIT(5) |
89 | #define RSP_CRC_OK BIT(4) |
90 | #define DATA_TIMEOUT BIT(3) |
91 | #define RSP_TIMEOUT BIT(2) |
92 | #define DATA_CRC_FAIL BIT(1) |
93 | #define RSP_CRC_FAIL BIT(0) |
94 | |
95 | #define MASK_RSP (RSP_TIMEOUT | RSP_CRC_FAIL | \ |
96 | RSP_CRC_OK | CARD_DETECT | CMD_SENT) |
97 | |
98 | #define MASK_DATA (DATA_CRC_OK | DATA_END | \ |
99 | DATA_CRC_FAIL | DATA_TIMEOUT) |
100 | |
101 | #define MASK_INTR_PIO (FIFO_URUN | FIFO_ORUN | CARD_CHANGE) |
102 | |
103 | /* REG_POWER_CONTROL */ |
104 | #define SD_POWER_ON BIT(4) |
105 | #define SD_POWER_MASK 0x0f |
106 | |
107 | /* REG_CLOCK_CONTROL */ |
108 | #define CLK_HISPD BIT(9) |
109 | #define CLK_OFF BIT(8) |
110 | #define CLK_SD BIT(7) |
111 | #define CLK_DIV_MASK 0x7f |
112 | |
113 | /* REG_BUS_WIDTH */ |
114 | #define BUS_WIDTH_4_SUPPORT BIT(3) |
115 | #define BUS_WIDTH_4 BIT(2) |
116 | #define BUS_WIDTH_1 BIT(0) |
117 | |
118 | #define MMC_VDD_360 23 |
119 | #define MIN_POWER (MMC_VDD_360 - SD_POWER_MASK) |
120 | #define MAX_RETRIES 500000 |
121 | |
122 | struct moxart_host { |
123 | spinlock_t lock; |
124 | |
125 | void __iomem *base; |
126 | |
127 | phys_addr_t reg_phys; |
128 | |
129 | struct dma_chan *dma_chan_tx; |
130 | struct dma_chan *dma_chan_rx; |
131 | struct dma_async_tx_descriptor *tx_desc; |
132 | struct mmc_host *mmc; |
133 | struct mmc_request *mrq; |
134 | struct scatterlist *cur_sg; |
135 | struct completion dma_complete; |
136 | struct completion pio_complete; |
137 | |
138 | u32 num_sg; |
139 | u32 data_remain; |
140 | u32 data_len; |
141 | u32 fifo_width; |
142 | u32 timeout; |
143 | u32 rate; |
144 | |
145 | long sysclk; |
146 | |
147 | bool have_dma; |
148 | bool is_removed; |
149 | }; |
150 | |
151 | static inline void moxart_init_sg(struct moxart_host *host, |
152 | struct mmc_data *data) |
153 | { |
154 | host->cur_sg = data->sg; |
155 | host->num_sg = data->sg_len; |
156 | host->data_remain = host->cur_sg->length; |
157 | |
158 | if (host->data_remain > host->data_len) |
159 | host->data_remain = host->data_len; |
160 | } |
161 | |
162 | static inline int moxart_next_sg(struct moxart_host *host) |
163 | { |
164 | int remain; |
165 | struct mmc_data *data = host->mrq->cmd->data; |
166 | |
167 | host->cur_sg++; |
168 | host->num_sg--; |
169 | |
170 | if (host->num_sg > 0) { |
171 | host->data_remain = host->cur_sg->length; |
172 | remain = host->data_len - data->bytes_xfered; |
173 | if (remain > 0 && remain < host->data_remain) |
174 | host->data_remain = remain; |
175 | } |
176 | |
177 | return host->num_sg; |
178 | } |
179 | |
180 | static int moxart_wait_for_status(struct moxart_host *host, |
181 | u32 mask, u32 *status) |
182 | { |
183 | int ret = -ETIMEDOUT; |
184 | u32 i; |
185 | |
186 | for (i = 0; i < MAX_RETRIES; i++) { |
187 | *status = readl(addr: host->base + REG_STATUS); |
188 | if (!(*status & mask)) { |
189 | udelay(5); |
190 | continue; |
191 | } |
192 | writel(val: *status & mask, addr: host->base + REG_CLEAR); |
193 | ret = 0; |
194 | break; |
195 | } |
196 | |
197 | if (ret) |
198 | dev_err(mmc_dev(host->mmc), "timed out waiting for status\n" ); |
199 | |
200 | return ret; |
201 | } |
202 | |
203 | |
204 | static void moxart_send_command(struct moxart_host *host, |
205 | struct mmc_command *cmd) |
206 | { |
207 | u32 status, cmdctrl; |
208 | |
209 | writel(RSP_TIMEOUT | RSP_CRC_OK | |
210 | RSP_CRC_FAIL | CMD_SENT, addr: host->base + REG_CLEAR); |
211 | writel(val: cmd->arg, addr: host->base + REG_ARGUMENT); |
212 | |
213 | cmdctrl = cmd->opcode & CMD_IDX_MASK; |
214 | if (cmdctrl == SD_APP_SET_BUS_WIDTH || cmdctrl == SD_APP_OP_COND || |
215 | cmdctrl == SD_APP_SEND_SCR || cmdctrl == SD_APP_SD_STATUS || |
216 | cmdctrl == SD_APP_SEND_NUM_WR_BLKS) |
217 | cmdctrl |= CMD_APP_CMD; |
218 | |
219 | if (cmd->flags & MMC_RSP_PRESENT) |
220 | cmdctrl |= CMD_NEED_RSP; |
221 | |
222 | if (cmd->flags & MMC_RSP_136) |
223 | cmdctrl |= CMD_LONG_RSP; |
224 | |
225 | writel(val: cmdctrl | CMD_EN, addr: host->base + REG_COMMAND); |
226 | |
227 | if (moxart_wait_for_status(host, MASK_RSP, status: &status) == -ETIMEDOUT) |
228 | cmd->error = -ETIMEDOUT; |
229 | |
230 | if (status & RSP_TIMEOUT) { |
231 | cmd->error = -ETIMEDOUT; |
232 | return; |
233 | } |
234 | if (status & RSP_CRC_FAIL) { |
235 | cmd->error = -EIO; |
236 | return; |
237 | } |
238 | if (status & RSP_CRC_OK) { |
239 | if (cmd->flags & MMC_RSP_136) { |
240 | cmd->resp[3] = readl(addr: host->base + REG_RESPONSE0); |
241 | cmd->resp[2] = readl(addr: host->base + REG_RESPONSE1); |
242 | cmd->resp[1] = readl(addr: host->base + REG_RESPONSE2); |
243 | cmd->resp[0] = readl(addr: host->base + REG_RESPONSE3); |
244 | } else { |
245 | cmd->resp[0] = readl(addr: host->base + REG_RESPONSE0); |
246 | } |
247 | } |
248 | } |
249 | |
250 | static void moxart_dma_complete(void *param) |
251 | { |
252 | struct moxart_host *host = param; |
253 | |
254 | complete(&host->dma_complete); |
255 | } |
256 | |
257 | static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host) |
258 | { |
259 | u32 len, dir_slave; |
260 | struct dma_async_tx_descriptor *desc = NULL; |
261 | struct dma_chan *dma_chan; |
262 | |
263 | if (host->data_len == data->bytes_xfered) |
264 | return; |
265 | |
266 | if (data->flags & MMC_DATA_WRITE) { |
267 | dma_chan = host->dma_chan_tx; |
268 | dir_slave = DMA_MEM_TO_DEV; |
269 | } else { |
270 | dma_chan = host->dma_chan_rx; |
271 | dir_slave = DMA_DEV_TO_MEM; |
272 | } |
273 | |
274 | len = dma_map_sg(dma_chan->device->dev, data->sg, |
275 | data->sg_len, mmc_get_dma_dir(data)); |
276 | |
277 | if (len > 0) { |
278 | desc = dmaengine_prep_slave_sg(chan: dma_chan, sgl: data->sg, |
279 | sg_len: len, dir: dir_slave, |
280 | flags: DMA_PREP_INTERRUPT | |
281 | DMA_CTRL_ACK); |
282 | } else { |
283 | dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n" ); |
284 | } |
285 | |
286 | if (desc) { |
287 | host->tx_desc = desc; |
288 | desc->callback = moxart_dma_complete; |
289 | desc->callback_param = host; |
290 | dmaengine_submit(desc); |
291 | dma_async_issue_pending(chan: dma_chan); |
292 | } |
293 | |
294 | data->bytes_xfered += host->data_remain; |
295 | |
296 | wait_for_completion_interruptible_timeout(x: &host->dma_complete, |
297 | timeout: host->timeout); |
298 | |
299 | dma_unmap_sg(dma_chan->device->dev, |
300 | data->sg, data->sg_len, |
301 | mmc_get_dma_dir(data)); |
302 | } |
303 | |
304 | |
305 | static void moxart_transfer_pio(struct moxart_host *host) |
306 | { |
307 | struct mmc_data *data = host->mrq->cmd->data; |
308 | u32 *sgp, len = 0, remain, status; |
309 | |
310 | if (host->data_len == data->bytes_xfered) |
311 | return; |
312 | |
313 | sgp = sg_virt(sg: host->cur_sg); |
314 | remain = host->data_remain; |
315 | |
316 | if (data->flags & MMC_DATA_WRITE) { |
317 | while (remain > 0) { |
318 | if (moxart_wait_for_status(host, FIFO_URUN, status: &status) |
319 | == -ETIMEDOUT) { |
320 | data->error = -ETIMEDOUT; |
321 | complete(&host->pio_complete); |
322 | return; |
323 | } |
324 | for (len = 0; len < remain && len < host->fifo_width;) { |
325 | iowrite32(*sgp, host->base + REG_DATA_WINDOW); |
326 | sgp++; |
327 | len += 4; |
328 | } |
329 | remain -= len; |
330 | } |
331 | |
332 | } else { |
333 | while (remain > 0) { |
334 | if (moxart_wait_for_status(host, FIFO_ORUN, status: &status) |
335 | == -ETIMEDOUT) { |
336 | data->error = -ETIMEDOUT; |
337 | complete(&host->pio_complete); |
338 | return; |
339 | } |
340 | for (len = 0; len < remain && len < host->fifo_width;) { |
341 | *sgp = ioread32(host->base + REG_DATA_WINDOW); |
342 | sgp++; |
343 | len += 4; |
344 | } |
345 | remain -= len; |
346 | } |
347 | } |
348 | |
349 | data->bytes_xfered += host->data_remain - remain; |
350 | host->data_remain = remain; |
351 | |
352 | if (host->data_len != data->bytes_xfered) |
353 | moxart_next_sg(host); |
354 | else |
355 | complete(&host->pio_complete); |
356 | } |
357 | |
358 | static void moxart_prepare_data(struct moxart_host *host) |
359 | { |
360 | struct mmc_data *data = host->mrq->cmd->data; |
361 | u32 datactrl; |
362 | int blksz_bits; |
363 | |
364 | if (!data) |
365 | return; |
366 | |
367 | host->data_len = data->blocks * data->blksz; |
368 | blksz_bits = ffs(data->blksz) - 1; |
369 | BUG_ON(1 << blksz_bits != data->blksz); |
370 | |
371 | moxart_init_sg(host, data); |
372 | |
373 | datactrl = DCR_DATA_EN | (blksz_bits & DCR_BLK_SIZE); |
374 | |
375 | if (data->flags & MMC_DATA_WRITE) |
376 | datactrl |= DCR_DATA_WRITE; |
377 | |
378 | if ((host->data_len > host->fifo_width) && host->have_dma) |
379 | datactrl |= DCR_DMA_EN; |
380 | |
381 | writel(DCR_DATA_FIFO_RESET, addr: host->base + REG_DATA_CONTROL); |
382 | writel(MASK_DATA | FIFO_URUN | FIFO_ORUN, addr: host->base + REG_CLEAR); |
383 | writel(val: host->rate, addr: host->base + REG_DATA_TIMER); |
384 | writel(val: host->data_len, addr: host->base + REG_DATA_LENGTH); |
385 | writel(val: datactrl, addr: host->base + REG_DATA_CONTROL); |
386 | } |
387 | |
388 | static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq) |
389 | { |
390 | struct moxart_host *host = mmc_priv(host: mmc); |
391 | unsigned long flags; |
392 | u32 status; |
393 | |
394 | spin_lock_irqsave(&host->lock, flags); |
395 | |
396 | init_completion(x: &host->dma_complete); |
397 | init_completion(x: &host->pio_complete); |
398 | |
399 | host->mrq = mrq; |
400 | |
401 | if (readl(addr: host->base + REG_STATUS) & CARD_DETECT) { |
402 | mrq->cmd->error = -ETIMEDOUT; |
403 | goto request_done; |
404 | } |
405 | |
406 | moxart_prepare_data(host); |
407 | moxart_send_command(host, cmd: host->mrq->cmd); |
408 | |
409 | if (mrq->cmd->data) { |
410 | if ((host->data_len > host->fifo_width) && host->have_dma) { |
411 | |
412 | writel(CARD_CHANGE, addr: host->base + REG_INTERRUPT_MASK); |
413 | |
414 | spin_unlock_irqrestore(lock: &host->lock, flags); |
415 | |
416 | moxart_transfer_dma(data: mrq->cmd->data, host); |
417 | |
418 | spin_lock_irqsave(&host->lock, flags); |
419 | } else { |
420 | |
421 | writel(MASK_INTR_PIO, addr: host->base + REG_INTERRUPT_MASK); |
422 | |
423 | spin_unlock_irqrestore(lock: &host->lock, flags); |
424 | |
425 | /* PIO transfers start from interrupt. */ |
426 | wait_for_completion_interruptible_timeout(x: &host->pio_complete, |
427 | timeout: host->timeout); |
428 | |
429 | spin_lock_irqsave(&host->lock, flags); |
430 | } |
431 | |
432 | if (host->is_removed) { |
433 | dev_err(mmc_dev(host->mmc), "card removed\n" ); |
434 | mrq->cmd->error = -ETIMEDOUT; |
435 | goto request_done; |
436 | } |
437 | |
438 | if (moxart_wait_for_status(host, MASK_DATA, status: &status) |
439 | == -ETIMEDOUT) { |
440 | mrq->cmd->data->error = -ETIMEDOUT; |
441 | goto request_done; |
442 | } |
443 | |
444 | if (status & DATA_CRC_FAIL) |
445 | mrq->cmd->data->error = -ETIMEDOUT; |
446 | |
447 | if (mrq->cmd->data->stop) |
448 | moxart_send_command(host, cmd: mrq->cmd->data->stop); |
449 | } |
450 | |
451 | request_done: |
452 | spin_unlock_irqrestore(lock: &host->lock, flags); |
453 | mmc_request_done(host->mmc, mrq); |
454 | } |
455 | |
456 | static irqreturn_t moxart_irq(int irq, void *devid) |
457 | { |
458 | struct moxart_host *host = (struct moxart_host *)devid; |
459 | u32 status; |
460 | |
461 | spin_lock(lock: &host->lock); |
462 | |
463 | status = readl(addr: host->base + REG_STATUS); |
464 | if (status & CARD_CHANGE) { |
465 | host->is_removed = status & CARD_DETECT; |
466 | if (host->is_removed && host->have_dma) { |
467 | dmaengine_terminate_all(chan: host->dma_chan_tx); |
468 | dmaengine_terminate_all(chan: host->dma_chan_rx); |
469 | } |
470 | host->mrq = NULL; |
471 | writel(MASK_INTR_PIO, addr: host->base + REG_CLEAR); |
472 | writel(CARD_CHANGE, addr: host->base + REG_INTERRUPT_MASK); |
473 | mmc_detect_change(host->mmc, delay: 0); |
474 | } |
475 | if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq) |
476 | moxart_transfer_pio(host); |
477 | |
478 | spin_unlock(lock: &host->lock); |
479 | |
480 | return IRQ_HANDLED; |
481 | } |
482 | |
483 | static void moxart_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
484 | { |
485 | struct moxart_host *host = mmc_priv(host: mmc); |
486 | unsigned long flags; |
487 | u8 power, div; |
488 | u32 ctrl; |
489 | |
490 | spin_lock_irqsave(&host->lock, flags); |
491 | |
492 | if (ios->clock) { |
493 | for (div = 0; div < CLK_DIV_MASK; ++div) { |
494 | if (ios->clock >= host->sysclk / (2 * (div + 1))) |
495 | break; |
496 | } |
497 | ctrl = CLK_SD | div; |
498 | host->rate = host->sysclk / (2 * (div + 1)); |
499 | if (host->rate > host->sysclk) |
500 | ctrl |= CLK_HISPD; |
501 | writel(val: ctrl, addr: host->base + REG_CLOCK_CONTROL); |
502 | } |
503 | |
504 | if (ios->power_mode == MMC_POWER_OFF) { |
505 | writel(readl(addr: host->base + REG_POWER_CONTROL) & ~SD_POWER_ON, |
506 | addr: host->base + REG_POWER_CONTROL); |
507 | } else { |
508 | if (ios->vdd < MIN_POWER) |
509 | power = 0; |
510 | else |
511 | power = ios->vdd - MIN_POWER; |
512 | |
513 | writel(SD_POWER_ON | (u32) power, |
514 | addr: host->base + REG_POWER_CONTROL); |
515 | } |
516 | |
517 | switch (ios->bus_width) { |
518 | case MMC_BUS_WIDTH_4: |
519 | writel(BUS_WIDTH_4, addr: host->base + REG_BUS_WIDTH); |
520 | break; |
521 | default: |
522 | writel(BUS_WIDTH_1, addr: host->base + REG_BUS_WIDTH); |
523 | break; |
524 | } |
525 | |
526 | spin_unlock_irqrestore(lock: &host->lock, flags); |
527 | } |
528 | |
529 | |
530 | static int moxart_get_ro(struct mmc_host *mmc) |
531 | { |
532 | struct moxart_host *host = mmc_priv(host: mmc); |
533 | |
534 | return !!(readl(addr: host->base + REG_STATUS) & WRITE_PROT); |
535 | } |
536 | |
537 | static const struct mmc_host_ops moxart_ops = { |
538 | .request = moxart_request, |
539 | .set_ios = moxart_set_ios, |
540 | .get_ro = moxart_get_ro, |
541 | }; |
542 | |
543 | static int moxart_probe(struct platform_device *pdev) |
544 | { |
545 | struct device *dev = &pdev->dev; |
546 | struct device_node *node = dev->of_node; |
547 | struct resource res_mmc; |
548 | struct mmc_host *mmc; |
549 | struct moxart_host *host = NULL; |
550 | struct dma_slave_config cfg; |
551 | struct clk *clk; |
552 | void __iomem *reg_mmc; |
553 | int irq, ret; |
554 | u32 i; |
555 | |
556 | mmc = mmc_alloc_host(extra: sizeof(struct moxart_host), dev); |
557 | if (!mmc) { |
558 | dev_err(dev, "mmc_alloc_host failed\n" ); |
559 | ret = -ENOMEM; |
560 | goto out_mmc; |
561 | } |
562 | |
563 | ret = of_address_to_resource(dev: node, index: 0, r: &res_mmc); |
564 | if (ret) { |
565 | dev_err(dev, "of_address_to_resource failed\n" ); |
566 | goto out_mmc; |
567 | } |
568 | |
569 | irq = irq_of_parse_and_map(node, index: 0); |
570 | if (irq <= 0) { |
571 | dev_err(dev, "irq_of_parse_and_map failed\n" ); |
572 | ret = -EINVAL; |
573 | goto out_mmc; |
574 | } |
575 | |
576 | clk = devm_clk_get(dev, NULL); |
577 | if (IS_ERR(ptr: clk)) { |
578 | ret = PTR_ERR(ptr: clk); |
579 | goto out_mmc; |
580 | } |
581 | |
582 | reg_mmc = devm_ioremap_resource(dev, res: &res_mmc); |
583 | if (IS_ERR(ptr: reg_mmc)) { |
584 | ret = PTR_ERR(ptr: reg_mmc); |
585 | goto out_mmc; |
586 | } |
587 | |
588 | ret = mmc_of_parse(host: mmc); |
589 | if (ret) |
590 | goto out_mmc; |
591 | |
592 | host = mmc_priv(host: mmc); |
593 | host->mmc = mmc; |
594 | host->base = reg_mmc; |
595 | host->reg_phys = res_mmc.start; |
596 | host->timeout = msecs_to_jiffies(m: 1000); |
597 | host->sysclk = clk_get_rate(clk); |
598 | host->fifo_width = readl(addr: host->base + REG_FEATURE) << 2; |
599 | host->dma_chan_tx = dma_request_chan(dev, name: "tx" ); |
600 | host->dma_chan_rx = dma_request_chan(dev, name: "rx" ); |
601 | |
602 | spin_lock_init(&host->lock); |
603 | |
604 | mmc->ops = &moxart_ops; |
605 | mmc->f_max = DIV_ROUND_CLOSEST(host->sysclk, 2); |
606 | mmc->f_min = DIV_ROUND_CLOSEST(host->sysclk, CLK_DIV_MASK * 2); |
607 | mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */ |
608 | mmc->max_blk_size = 2048; /* Max. block length in REG_DATA_CONTROL */ |
609 | mmc->max_req_size = DATA_LEN_MASK; /* bits 0-23 in REG_DATA_LENGTH */ |
610 | mmc->max_blk_count = mmc->max_req_size / 512; |
611 | |
612 | if (IS_ERR(ptr: host->dma_chan_tx) || IS_ERR(ptr: host->dma_chan_rx)) { |
613 | if (PTR_ERR(ptr: host->dma_chan_tx) == -EPROBE_DEFER || |
614 | PTR_ERR(ptr: host->dma_chan_rx) == -EPROBE_DEFER) { |
615 | ret = -EPROBE_DEFER; |
616 | goto out; |
617 | } |
618 | if (!IS_ERR(ptr: host->dma_chan_tx)) { |
619 | dma_release_channel(chan: host->dma_chan_tx); |
620 | host->dma_chan_tx = NULL; |
621 | } |
622 | if (!IS_ERR(ptr: host->dma_chan_rx)) { |
623 | dma_release_channel(chan: host->dma_chan_rx); |
624 | host->dma_chan_rx = NULL; |
625 | } |
626 | dev_dbg(dev, "PIO mode transfer enabled\n" ); |
627 | host->have_dma = false; |
628 | |
629 | mmc->max_seg_size = mmc->max_req_size; |
630 | } else { |
631 | dev_dbg(dev, "DMA channels found (%p,%p)\n" , |
632 | host->dma_chan_tx, host->dma_chan_rx); |
633 | host->have_dma = true; |
634 | |
635 | memset(&cfg, 0, sizeof(cfg)); |
636 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
637 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
638 | |
639 | cfg.direction = DMA_MEM_TO_DEV; |
640 | cfg.src_addr = 0; |
641 | cfg.dst_addr = host->reg_phys + REG_DATA_WINDOW; |
642 | dmaengine_slave_config(chan: host->dma_chan_tx, config: &cfg); |
643 | |
644 | cfg.direction = DMA_DEV_TO_MEM; |
645 | cfg.src_addr = host->reg_phys + REG_DATA_WINDOW; |
646 | cfg.dst_addr = 0; |
647 | dmaengine_slave_config(chan: host->dma_chan_rx, config: &cfg); |
648 | |
649 | mmc->max_seg_size = min3(mmc->max_req_size, |
650 | dma_get_max_seg_size(host->dma_chan_rx->device->dev), |
651 | dma_get_max_seg_size(host->dma_chan_tx->device->dev)); |
652 | } |
653 | |
654 | if (readl(addr: host->base + REG_BUS_WIDTH) & BUS_WIDTH_4_SUPPORT) |
655 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
656 | |
657 | writel(val: 0, addr: host->base + REG_INTERRUPT_MASK); |
658 | |
659 | writel(CMD_SDC_RESET, addr: host->base + REG_COMMAND); |
660 | for (i = 0; i < MAX_RETRIES; i++) { |
661 | if (!(readl(addr: host->base + REG_COMMAND) & CMD_SDC_RESET)) |
662 | break; |
663 | udelay(5); |
664 | } |
665 | |
666 | ret = devm_request_irq(dev, irq, handler: moxart_irq, irqflags: 0, devname: "moxart-mmc" , dev_id: host); |
667 | if (ret) |
668 | goto out; |
669 | |
670 | dev_set_drvdata(dev, data: mmc); |
671 | ret = mmc_add_host(mmc); |
672 | if (ret) |
673 | goto out; |
674 | |
675 | dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n" , irq, host->fifo_width); |
676 | |
677 | return 0; |
678 | |
679 | out: |
680 | if (!IS_ERR_OR_NULL(ptr: host->dma_chan_tx)) |
681 | dma_release_channel(chan: host->dma_chan_tx); |
682 | if (!IS_ERR_OR_NULL(ptr: host->dma_chan_rx)) |
683 | dma_release_channel(chan: host->dma_chan_rx); |
684 | out_mmc: |
685 | if (mmc) |
686 | mmc_free_host(mmc); |
687 | return ret; |
688 | } |
689 | |
690 | static void moxart_remove(struct platform_device *pdev) |
691 | { |
692 | struct mmc_host *mmc = dev_get_drvdata(dev: &pdev->dev); |
693 | struct moxart_host *host = mmc_priv(host: mmc); |
694 | |
695 | if (!IS_ERR_OR_NULL(ptr: host->dma_chan_tx)) |
696 | dma_release_channel(chan: host->dma_chan_tx); |
697 | if (!IS_ERR_OR_NULL(ptr: host->dma_chan_rx)) |
698 | dma_release_channel(chan: host->dma_chan_rx); |
699 | mmc_remove_host(mmc); |
700 | |
701 | writel(val: 0, addr: host->base + REG_INTERRUPT_MASK); |
702 | writel(val: 0, addr: host->base + REG_POWER_CONTROL); |
703 | writel(readl(addr: host->base + REG_CLOCK_CONTROL) | CLK_OFF, |
704 | addr: host->base + REG_CLOCK_CONTROL); |
705 | mmc_free_host(mmc); |
706 | } |
707 | |
708 | static const struct of_device_id moxart_mmc_match[] = { |
709 | { .compatible = "moxa,moxart-mmc" }, |
710 | { .compatible = "faraday,ftsdc010" }, |
711 | { } |
712 | }; |
713 | MODULE_DEVICE_TABLE(of, moxart_mmc_match); |
714 | |
715 | static struct platform_driver moxart_mmc_driver = { |
716 | .probe = moxart_probe, |
717 | .remove_new = moxart_remove, |
718 | .driver = { |
719 | .name = "mmc-moxart" , |
720 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
721 | .of_match_table = moxart_mmc_match, |
722 | }, |
723 | }; |
724 | module_platform_driver(moxart_mmc_driver); |
725 | |
726 | MODULE_ALIAS("platform:mmc-moxart" ); |
727 | MODULE_DESCRIPTION("MOXA ART MMC driver" ); |
728 | MODULE_LICENSE("GPL v2" ); |
729 | MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>" ); |
730 | |