Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memstick: add support for JMicron jmb38x MemoryStick host controller

Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Alex Dubov and committed by
Linus Torvalds
60fdd931 59367258

+960 -4
+1 -1
drivers/memstick/Kconfig
··· 8 8 Sony MemoryStick is a proprietary storage/extension card protocol. 9 9 10 10 If you want MemoryStick support, you should say Y here and also 11 - to the specific driver for your MMC interface. 11 + to the specific driver for your MemoryStick interface. 12 12 13 13 if MEMSTICK 14 14
+10
drivers/memstick/host/Kconfig
··· 20 20 To compile this driver as a module, choose M here: the 21 21 module will be called tifm_ms. 22 22 23 + config MEMSTICK_JMICRON_38X 24 + tristate "JMicron JMB38X MemoryStick interface support (EXPERIMENTAL)" 25 + depends on EXPERIMENTAL && PCI 26 + 27 + help 28 + Say Y here if you want to be able to access MemoryStick cards with 29 + the JMicron(R) JMB38X MemoryStick card reader. 30 + 31 + To compile this driver as a module, choose M here: the 32 + module will be called jmb38x_ms.
+3 -3
drivers/memstick/host/Makefile
··· 3 3 # 4 4 5 5 ifeq ($(CONFIG_MEMSTICK_DEBUG),y) 6 - EXTRA_CFLAGS += -DDEBUG 6 + EXTRA_CFLAGS += -DDEBUG 7 7 endif 8 8 9 - obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o 10 - 9 + obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o 10 + obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o
+945
drivers/memstick/host/jmb38x_ms.c
··· 1 + /* 2 + * jmb38x_ms.c - JMicron jmb38x MemoryStick card reader 3 + * 4 + * Copyright (C) 2008 Alex Dubov <oakad@yahoo.com> 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 version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + */ 11 + 12 + #include <linux/spinlock.h> 13 + #include <linux/interrupt.h> 14 + #include <linux/pci.h> 15 + #include <linux/delay.h> 16 + #include <linux/highmem.h> 17 + #include <linux/memstick.h> 18 + 19 + #define DRIVER_NAME "jmb38x_ms" 20 + 21 + static int no_dma; 22 + module_param(no_dma, bool, 0644); 23 + 24 + enum { 25 + DMA_ADDRESS = 0x00, 26 + BLOCK = 0x04, 27 + DMA_CONTROL = 0x08, 28 + TPC_P0 = 0x0c, 29 + TPC_P1 = 0x10, 30 + TPC = 0x14, 31 + HOST_CONTROL = 0x18, 32 + DATA = 0x1c, 33 + STATUS = 0x20, 34 + INT_STATUS = 0x24, 35 + INT_STATUS_ENABLE = 0x28, 36 + INT_SIGNAL_ENABLE = 0x2c, 37 + TIMER = 0x30, 38 + TIMER_CONTROL = 0x34, 39 + PAD_OUTPUT_ENABLE = 0x38, 40 + PAD_PU_PD = 0x3c, 41 + CLOCK_DELAY = 0x40, 42 + ADMA_ADDRESS = 0x44, 43 + CLOCK_CONTROL = 0x48, 44 + LED_CONTROL = 0x4c, 45 + VERSION = 0x50 46 + }; 47 + 48 + struct jmb38x_ms_host { 49 + struct jmb38x_ms *chip; 50 + void __iomem *addr; 51 + spinlock_t lock; 52 + int id; 53 + char host_id[DEVICE_ID_SIZE]; 54 + int irq; 55 + unsigned int block_pos; 56 + unsigned long timeout_jiffies; 57 + struct timer_list timer; 58 + struct memstick_request *req; 59 + unsigned char eject:1, 60 + use_dma:1; 61 + unsigned char cmd_flags; 62 + unsigned char io_pos; 63 + unsigned int io_word[2]; 64 + }; 65 + 66 + struct jmb38x_ms { 67 + struct pci_dev *pdev; 68 + int host_cnt; 69 + struct memstick_host *hosts[]; 70 + }; 71 + 72 + #define BLOCK_COUNT_MASK 0xffff0000 73 + #define BLOCK_SIZE_MASK 0x00000fff 74 + 75 + #define DMA_CONTROL_ENABLE 0x00000001 76 + 77 + #define TPC_DATA_SEL 0x00008000 78 + #define TPC_DIR 0x00004000 79 + #define TPC_WAIT_INT 0x00002000 80 + #define TPC_GET_INT 0x00000800 81 + #define TPC_CODE_SZ_MASK 0x00000700 82 + #define TPC_DATA_SZ_MASK 0x00000007 83 + 84 + #define HOST_CONTROL_RESET_REQ 0x00008000 85 + #define HOST_CONTROL_REI 0x00004000 86 + #define HOST_CONTROL_LED 0x00000400 87 + #define HOST_CONTROL_FAST_CLK 0x00000200 88 + #define HOST_CONTROL_RESET 0x00000100 89 + #define HOST_CONTROL_POWER_EN 0x00000080 90 + #define HOST_CONTROL_CLOCK_EN 0x00000040 91 + #define HOST_CONTROL_IF_SHIFT 4 92 + 93 + #define HOST_CONTROL_IF_SERIAL 0x0 94 + #define HOST_CONTROL_IF_PAR4 0x1 95 + #define HOST_CONTROL_IF_PAR8 0x3 96 + 97 + #define STATUS_HAS_MEDIA 0x00000400 98 + #define STATUS_FIFO_EMPTY 0x00000200 99 + #define STATUS_FIFO_FULL 0x00000100 100 + 101 + #define INT_STATUS_TPC_ERR 0x00080000 102 + #define INT_STATUS_CRC_ERR 0x00040000 103 + #define INT_STATUS_TIMER_TO 0x00020000 104 + #define INT_STATUS_HSK_TO 0x00010000 105 + #define INT_STATUS_ANY_ERR 0x00008000 106 + #define INT_STATUS_FIFO_WRDY 0x00000080 107 + #define INT_STATUS_FIFO_RRDY 0x00000040 108 + #define INT_STATUS_MEDIA_OUT 0x00000010 109 + #define INT_STATUS_MEDIA_IN 0x00000008 110 + #define INT_STATUS_DMA_BOUNDARY 0x00000004 111 + #define INT_STATUS_EOTRAN 0x00000002 112 + #define INT_STATUS_EOTPC 0x00000001 113 + 114 + #define INT_STATUS_ALL 0x000f801f 115 + 116 + #define PAD_OUTPUT_ENABLE_MS 0x0F3F 117 + 118 + #define PAD_PU_PD_OFF 0x7FFF0000 119 + #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 120 + #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 121 + 122 + enum { 123 + CMD_READY = 0x01, 124 + FIFO_READY = 0x02, 125 + REG_DATA = 0x04, 126 + AUTO_GET_INT = 0x08 127 + }; 128 + 129 + static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, 130 + unsigned char *buf, unsigned int length) 131 + { 132 + unsigned int off = 0; 133 + 134 + while (host->io_pos && length) { 135 + buf[off++] = host->io_word[0] & 0xff; 136 + host->io_word[0] >>= 8; 137 + length--; 138 + host->io_pos--; 139 + } 140 + 141 + if (!length) 142 + return off; 143 + 144 + while (!(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { 145 + if (length < 4) 146 + break; 147 + *(unsigned int *)(buf + off) = __raw_readl(host->addr + DATA); 148 + length -= 4; 149 + off += 4; 150 + } 151 + 152 + if (length 153 + && !(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { 154 + host->io_word[0] = readl(host->addr + DATA); 155 + for (host->io_pos = 4; host->io_pos; --host->io_pos) { 156 + buf[off++] = host->io_word[0] & 0xff; 157 + host->io_word[0] >>= 8; 158 + length--; 159 + if (!length) 160 + break; 161 + } 162 + } 163 + 164 + return off; 165 + } 166 + 167 + static unsigned int jmb38x_ms_read_reg_data(struct jmb38x_ms_host *host, 168 + unsigned char *buf, 169 + unsigned int length) 170 + { 171 + unsigned int off = 0; 172 + 173 + while (host->io_pos > 4 && length) { 174 + buf[off++] = host->io_word[0] & 0xff; 175 + host->io_word[0] >>= 8; 176 + length--; 177 + host->io_pos--; 178 + } 179 + 180 + if (!length) 181 + return off; 182 + 183 + while (host->io_pos && length) { 184 + buf[off++] = host->io_word[1] & 0xff; 185 + host->io_word[1] >>= 8; 186 + length--; 187 + host->io_pos--; 188 + } 189 + 190 + return off; 191 + } 192 + 193 + static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host, 194 + unsigned char *buf, 195 + unsigned int length) 196 + { 197 + unsigned int off = 0; 198 + 199 + if (host->io_pos) { 200 + while (host->io_pos < 4 && length) { 201 + host->io_word[0] |= buf[off++] << (host->io_pos * 8); 202 + host->io_pos++; 203 + length--; 204 + } 205 + } 206 + 207 + if (host->io_pos == 4 208 + && !(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { 209 + writel(host->io_word[0], host->addr + DATA); 210 + host->io_pos = 0; 211 + host->io_word[0] = 0; 212 + } else if (host->io_pos) { 213 + return off; 214 + } 215 + 216 + if (!length) 217 + return off; 218 + 219 + while (!(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { 220 + if (length < 4) 221 + break; 222 + 223 + __raw_writel(*(unsigned int *)(buf + off), 224 + host->addr + DATA); 225 + length -= 4; 226 + off += 4; 227 + } 228 + 229 + switch (length) { 230 + case 3: 231 + host->io_word[0] |= buf[off + 2] << 16; 232 + host->io_pos++; 233 + case 2: 234 + host->io_word[0] |= buf[off + 1] << 8; 235 + host->io_pos++; 236 + case 1: 237 + host->io_word[0] |= buf[off]; 238 + host->io_pos++; 239 + } 240 + 241 + off += host->io_pos; 242 + 243 + return off; 244 + } 245 + 246 + static unsigned int jmb38x_ms_write_reg_data(struct jmb38x_ms_host *host, 247 + unsigned char *buf, 248 + unsigned int length) 249 + { 250 + unsigned int off = 0; 251 + 252 + while (host->io_pos < 4 && length) { 253 + host->io_word[0] &= ~(0xff << (host->io_pos * 8)); 254 + host->io_word[0] |= buf[off++] << (host->io_pos * 8); 255 + host->io_pos++; 256 + length--; 257 + } 258 + 259 + if (!length) 260 + return off; 261 + 262 + while (host->io_pos < 8 && length) { 263 + host->io_word[1] &= ~(0xff << (host->io_pos * 8)); 264 + host->io_word[1] |= buf[off++] << (host->io_pos * 8); 265 + host->io_pos++; 266 + length--; 267 + } 268 + 269 + return off; 270 + } 271 + 272 + static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) 273 + { 274 + unsigned int length; 275 + unsigned int off; 276 + unsigned int t_size, p_off, p_cnt; 277 + unsigned char *buf; 278 + struct page *pg; 279 + unsigned long flags = 0; 280 + 281 + if (host->req->long_data) { 282 + length = host->req->sg.length - host->block_pos; 283 + off = host->req->sg.offset + host->block_pos; 284 + } else { 285 + length = host->req->data_len - host->block_pos; 286 + off = 0; 287 + } 288 + 289 + while (length) { 290 + if (host->req->long_data) { 291 + pg = nth_page(sg_page(&host->req->sg), 292 + off >> PAGE_SHIFT); 293 + p_off = offset_in_page(off); 294 + p_cnt = PAGE_SIZE - p_off; 295 + p_cnt = min(p_cnt, length); 296 + 297 + local_irq_save(flags); 298 + buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; 299 + } else { 300 + buf = host->req->data + host->block_pos; 301 + p_cnt = host->req->data_len - host->block_pos; 302 + } 303 + 304 + if (host->req->data_dir == WRITE) 305 + t_size = !(host->cmd_flags & REG_DATA) 306 + ? jmb38x_ms_write_data(host, buf, p_cnt) 307 + : jmb38x_ms_write_reg_data(host, buf, p_cnt); 308 + else 309 + t_size = !(host->cmd_flags & REG_DATA) 310 + ? jmb38x_ms_read_data(host, buf, p_cnt) 311 + : jmb38x_ms_read_reg_data(host, buf, p_cnt); 312 + 313 + if (host->req->long_data) { 314 + kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); 315 + local_irq_restore(flags); 316 + } 317 + 318 + if (!t_size) 319 + break; 320 + host->block_pos += t_size; 321 + length -= t_size; 322 + off += t_size; 323 + } 324 + 325 + if (!length && host->req->data_dir == WRITE) { 326 + if (host->cmd_flags & REG_DATA) { 327 + writel(host->io_word[0], host->addr + TPC_P0); 328 + writel(host->io_word[1], host->addr + TPC_P1); 329 + } else if (host->io_pos) { 330 + writel(host->io_word[0], host->addr + DATA); 331 + } 332 + } 333 + 334 + return length; 335 + } 336 + 337 + static int jmb38x_ms_issue_cmd(struct memstick_host *msh) 338 + { 339 + struct jmb38x_ms_host *host = memstick_priv(msh); 340 + unsigned char *data; 341 + unsigned int data_len, cmd, t_val; 342 + 343 + if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) { 344 + dev_dbg(msh->cdev.dev, "no media status\n"); 345 + host->req->error = -ETIME; 346 + return host->req->error; 347 + } 348 + 349 + dev_dbg(msh->cdev.dev, "control %08x\n", 350 + readl(host->addr + HOST_CONTROL)); 351 + dev_dbg(msh->cdev.dev, "status %08x\n", readl(host->addr + INT_STATUS)); 352 + dev_dbg(msh->cdev.dev, "hstatus %08x\n", readl(host->addr + STATUS)); 353 + 354 + host->cmd_flags = 0; 355 + host->block_pos = 0; 356 + host->io_pos = 0; 357 + host->io_word[0] = 0; 358 + host->io_word[1] = 0; 359 + 360 + cmd = host->req->tpc << 16; 361 + cmd |= TPC_DATA_SEL; 362 + 363 + if (host->req->data_dir == READ) 364 + cmd |= TPC_DIR; 365 + if (host->req->need_card_int) 366 + cmd |= TPC_WAIT_INT; 367 + if (host->req->get_int_reg) 368 + cmd |= TPC_GET_INT; 369 + 370 + data = host->req->data; 371 + 372 + host->use_dma = !no_dma; 373 + 374 + if (host->req->long_data) { 375 + data_len = host->req->sg.length; 376 + } else { 377 + data_len = host->req->data_len; 378 + host->use_dma = 0; 379 + } 380 + 381 + if (data_len <= 8) { 382 + cmd &= ~(TPC_DATA_SEL | 0xf); 383 + host->cmd_flags |= REG_DATA; 384 + cmd |= data_len & 0xf; 385 + host->use_dma = 0; 386 + } 387 + 388 + if (host->use_dma) { 389 + if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1, 390 + host->req->data_dir == READ 391 + ? PCI_DMA_FROMDEVICE 392 + : PCI_DMA_TODEVICE)) { 393 + host->req->error = -ENOMEM; 394 + return host->req->error; 395 + } 396 + data_len = sg_dma_len(&host->req->sg); 397 + writel(sg_dma_address(&host->req->sg), 398 + host->addr + DMA_ADDRESS); 399 + writel(((1 << 16) & BLOCK_COUNT_MASK) 400 + | (data_len & BLOCK_SIZE_MASK), 401 + host->addr + BLOCK); 402 + writel(DMA_CONTROL_ENABLE, host->addr + DMA_CONTROL); 403 + } else if (!(host->cmd_flags & REG_DATA)) { 404 + writel(((1 << 16) & BLOCK_COUNT_MASK) 405 + | (data_len & BLOCK_SIZE_MASK), 406 + host->addr + BLOCK); 407 + t_val = readl(host->addr + INT_STATUS_ENABLE); 408 + t_val |= host->req->data_dir == READ 409 + ? INT_STATUS_FIFO_RRDY 410 + : INT_STATUS_FIFO_WRDY; 411 + 412 + writel(t_val, host->addr + INT_STATUS_ENABLE); 413 + writel(t_val, host->addr + INT_SIGNAL_ENABLE); 414 + } else { 415 + cmd &= ~(TPC_DATA_SEL | 0xf); 416 + host->cmd_flags |= REG_DATA; 417 + cmd |= data_len & 0xf; 418 + 419 + if (host->req->data_dir == WRITE) { 420 + jmb38x_ms_transfer_data(host); 421 + writel(host->io_word[0], host->addr + TPC_P0); 422 + writel(host->io_word[1], host->addr + TPC_P1); 423 + } 424 + } 425 + 426 + mod_timer(&host->timer, jiffies + host->timeout_jiffies); 427 + writel(HOST_CONTROL_LED | readl(host->addr + HOST_CONTROL), 428 + host->addr + HOST_CONTROL); 429 + host->req->error = 0; 430 + 431 + writel(cmd, host->addr + TPC); 432 + dev_dbg(msh->cdev.dev, "executing TPC %08x, len %x\n", cmd, data_len); 433 + 434 + return 0; 435 + } 436 + 437 + static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last) 438 + { 439 + struct jmb38x_ms_host *host = memstick_priv(msh); 440 + unsigned int t_val = 0; 441 + int rc; 442 + 443 + del_timer(&host->timer); 444 + 445 + dev_dbg(msh->cdev.dev, "c control %08x\n", 446 + readl(host->addr + HOST_CONTROL)); 447 + dev_dbg(msh->cdev.dev, "c status %08x\n", 448 + readl(host->addr + INT_STATUS)); 449 + dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); 450 + 451 + if (host->req->get_int_reg) { 452 + t_val = readl(host->addr + TPC_P0); 453 + host->req->int_reg = (t_val & 0xff); 454 + } 455 + 456 + if (host->use_dma) { 457 + writel(0, host->addr + DMA_CONTROL); 458 + pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, 459 + host->req->data_dir == READ 460 + ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); 461 + } else { 462 + t_val = readl(host->addr + INT_STATUS_ENABLE); 463 + if (host->req->data_dir == READ) 464 + t_val &= ~INT_STATUS_FIFO_RRDY; 465 + else 466 + t_val &= ~INT_STATUS_FIFO_WRDY; 467 + 468 + writel(t_val, host->addr + INT_STATUS_ENABLE); 469 + writel(t_val, host->addr + INT_SIGNAL_ENABLE); 470 + } 471 + 472 + writel((~HOST_CONTROL_LED) & readl(host->addr + HOST_CONTROL), 473 + host->addr + HOST_CONTROL); 474 + 475 + if (!last) { 476 + do { 477 + rc = memstick_next_req(msh, &host->req); 478 + } while (!rc && jmb38x_ms_issue_cmd(msh)); 479 + } else { 480 + do { 481 + rc = memstick_next_req(msh, &host->req); 482 + if (!rc) 483 + host->req->error = -ETIME; 484 + } while (!rc); 485 + } 486 + } 487 + 488 + static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) 489 + { 490 + struct memstick_host *msh = dev_id; 491 + struct jmb38x_ms_host *host = memstick_priv(msh); 492 + unsigned int irq_status; 493 + 494 + spin_lock(&host->lock); 495 + irq_status = readl(host->addr + INT_STATUS); 496 + dev_dbg(&host->chip->pdev->dev, "irq_status = %08x\n", irq_status); 497 + if (irq_status == 0 || irq_status == (~0)) { 498 + spin_unlock(&host->lock); 499 + return IRQ_NONE; 500 + } 501 + 502 + if (host->req) { 503 + if (irq_status & INT_STATUS_ANY_ERR) { 504 + if (irq_status & INT_STATUS_CRC_ERR) 505 + host->req->error = -EILSEQ; 506 + else 507 + host->req->error = -ETIME; 508 + } else { 509 + if (host->use_dma) { 510 + if (irq_status & INT_STATUS_EOTRAN) 511 + host->cmd_flags |= FIFO_READY; 512 + } else { 513 + if (irq_status & (INT_STATUS_FIFO_RRDY 514 + | INT_STATUS_FIFO_WRDY)) 515 + jmb38x_ms_transfer_data(host); 516 + 517 + if (irq_status & INT_STATUS_EOTRAN) { 518 + jmb38x_ms_transfer_data(host); 519 + host->cmd_flags |= FIFO_READY; 520 + } 521 + } 522 + 523 + if (irq_status & INT_STATUS_EOTPC) { 524 + host->cmd_flags |= CMD_READY; 525 + if (host->cmd_flags & REG_DATA) { 526 + if (host->req->data_dir == READ) { 527 + host->io_word[0] 528 + = readl(host->addr 529 + + TPC_P0); 530 + host->io_word[1] 531 + = readl(host->addr 532 + + TPC_P1); 533 + host->io_pos = 8; 534 + 535 + jmb38x_ms_transfer_data(host); 536 + } 537 + host->cmd_flags |= FIFO_READY; 538 + } 539 + } 540 + } 541 + } 542 + 543 + if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) { 544 + dev_dbg(&host->chip->pdev->dev, "media changed\n"); 545 + memstick_detect_change(msh); 546 + } 547 + 548 + writel(irq_status, host->addr + INT_STATUS); 549 + 550 + if (host->req 551 + && (((host->cmd_flags & CMD_READY) 552 + && (host->cmd_flags & FIFO_READY)) 553 + || host->req->error)) 554 + jmb38x_ms_complete_cmd(msh, 0); 555 + 556 + spin_unlock(&host->lock); 557 + return IRQ_HANDLED; 558 + } 559 + 560 + static void jmb38x_ms_abort(unsigned long data) 561 + { 562 + struct memstick_host *msh = (struct memstick_host *)data; 563 + struct jmb38x_ms_host *host = memstick_priv(msh); 564 + unsigned long flags; 565 + 566 + dev_dbg(&host->chip->pdev->dev, "abort\n"); 567 + spin_lock_irqsave(&host->lock, flags); 568 + if (host->req) { 569 + host->req->error = -ETIME; 570 + jmb38x_ms_complete_cmd(msh, 0); 571 + } 572 + spin_unlock_irqrestore(&host->lock, flags); 573 + } 574 + 575 + static void jmb38x_ms_request(struct memstick_host *msh) 576 + { 577 + struct jmb38x_ms_host *host = memstick_priv(msh); 578 + unsigned long flags; 579 + int rc; 580 + 581 + spin_lock_irqsave(&host->lock, flags); 582 + if (host->req) { 583 + spin_unlock_irqrestore(&host->lock, flags); 584 + BUG(); 585 + return; 586 + } 587 + 588 + do { 589 + rc = memstick_next_req(msh, &host->req); 590 + } while (!rc && jmb38x_ms_issue_cmd(msh)); 591 + spin_unlock_irqrestore(&host->lock, flags); 592 + } 593 + 594 + static void jmb38x_ms_reset(struct jmb38x_ms_host *host) 595 + { 596 + unsigned int host_ctl = readl(host->addr + HOST_CONTROL); 597 + 598 + writel(host_ctl | HOST_CONTROL_RESET_REQ | HOST_CONTROL_RESET, 599 + host->addr + HOST_CONTROL); 600 + 601 + while (HOST_CONTROL_RESET_REQ 602 + & (host_ctl = readl(host->addr + HOST_CONTROL))) { 603 + ndelay(100); 604 + dev_dbg(&host->chip->pdev->dev, "reset\n"); 605 + } 606 + 607 + writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); 608 + writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); 609 + 610 + dev_dbg(&host->chip->pdev->dev, "reset\n"); 611 + } 612 + 613 + static void jmb38x_ms_set_param(struct memstick_host *msh, 614 + enum memstick_param param, 615 + int value) 616 + { 617 + struct jmb38x_ms_host *host = memstick_priv(msh); 618 + unsigned int host_ctl; 619 + unsigned long flags; 620 + 621 + spin_lock_irqsave(&host->lock, flags); 622 + 623 + switch (param) { 624 + case MEMSTICK_POWER: 625 + if (value == MEMSTICK_POWER_ON) { 626 + jmb38x_ms_reset(host); 627 + 628 + writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 629 + : PAD_PU_PD_ON_MS_SOCK0, 630 + host->addr + PAD_PU_PD); 631 + 632 + writel(PAD_OUTPUT_ENABLE_MS, 633 + host->addr + PAD_OUTPUT_ENABLE); 634 + 635 + host_ctl = readl(host->addr + HOST_CONTROL); 636 + host_ctl |= 7; 637 + writel(host_ctl | (HOST_CONTROL_POWER_EN 638 + | HOST_CONTROL_CLOCK_EN), 639 + host->addr + HOST_CONTROL); 640 + 641 + dev_dbg(&host->chip->pdev->dev, "power on\n"); 642 + } else if (value == MEMSTICK_POWER_OFF) { 643 + writel(readl(host->addr + HOST_CONTROL) 644 + & ~(HOST_CONTROL_POWER_EN 645 + | HOST_CONTROL_CLOCK_EN), 646 + host->addr + HOST_CONTROL); 647 + writel(0, host->addr + PAD_OUTPUT_ENABLE); 648 + writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); 649 + dev_dbg(&host->chip->pdev->dev, "power off\n"); 650 + } 651 + break; 652 + case MEMSTICK_INTERFACE: 653 + /* jmb38x_ms_reset(host); */ 654 + 655 + host_ctl = readl(host->addr + HOST_CONTROL); 656 + host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); 657 + /* host_ctl |= 7; */ 658 + 659 + if (value == MEMSTICK_SERIAL) { 660 + host_ctl &= ~HOST_CONTROL_FAST_CLK; 661 + host_ctl |= HOST_CONTROL_IF_SERIAL 662 + << HOST_CONTROL_IF_SHIFT; 663 + host_ctl |= HOST_CONTROL_REI; 664 + writel(0, host->addr + CLOCK_DELAY); 665 + } else if (value == MEMSTICK_PAR4) { 666 + host_ctl |= HOST_CONTROL_FAST_CLK; 667 + host_ctl |= HOST_CONTROL_IF_PAR4 668 + << HOST_CONTROL_IF_SHIFT; 669 + host_ctl &= ~HOST_CONTROL_REI; 670 + writel(4, host->addr + CLOCK_DELAY); 671 + } else if (value == MEMSTICK_PAR8) { 672 + host_ctl |= HOST_CONTROL_FAST_CLK; 673 + host_ctl |= HOST_CONTROL_IF_PAR8 674 + << HOST_CONTROL_IF_SHIFT; 675 + host_ctl &= ~HOST_CONTROL_REI; 676 + writel(4, host->addr + CLOCK_DELAY); 677 + } 678 + writel(host_ctl, host->addr + HOST_CONTROL); 679 + break; 680 + }; 681 + 682 + spin_unlock_irqrestore(&host->lock, flags); 683 + } 684 + 685 + #ifdef CONFIG_PM 686 + 687 + static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) 688 + { 689 + struct jmb38x_ms *jm = pci_get_drvdata(dev); 690 + int cnt; 691 + 692 + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { 693 + if (!jm->hosts[cnt]) 694 + break; 695 + memstick_suspend_host(jm->hosts[cnt]); 696 + } 697 + 698 + pci_save_state(dev); 699 + pci_enable_wake(dev, pci_choose_state(dev, state), 0); 700 + pci_disable_device(dev); 701 + pci_set_power_state(dev, pci_choose_state(dev, state)); 702 + return 0; 703 + } 704 + 705 + static int jmb38x_ms_resume(struct pci_dev *dev) 706 + { 707 + struct jmb38x_ms *jm = pci_get_drvdata(dev); 708 + int rc; 709 + 710 + pci_set_power_state(dev, PCI_D0); 711 + pci_restore_state(dev); 712 + rc = pci_enable_device(dev); 713 + if (rc) 714 + return rc; 715 + pci_set_master(dev); 716 + 717 + pci_read_config_dword(dev, 0xac, &rc); 718 + pci_write_config_dword(dev, 0xac, rc | 0x00470000); 719 + 720 + for (rc = 0; rc < jm->host_cnt; ++rc) { 721 + if (!jm->hosts[rc]) 722 + break; 723 + memstick_resume_host(jm->hosts[rc]); 724 + memstick_detect_change(jm->hosts[rc]); 725 + } 726 + 727 + return 0; 728 + } 729 + 730 + #else 731 + 732 + #define jmb38x_ms_suspend NULL 733 + #define jmb38x_ms_resume NULL 734 + 735 + #endif /* CONFIG_PM */ 736 + 737 + static int jmb38x_ms_count_slots(struct pci_dev *pdev) 738 + { 739 + int cnt, rc = 0; 740 + 741 + for (cnt = 0; cnt < PCI_ROM_RESOURCE; ++cnt) { 742 + if (!(IORESOURCE_MEM & pci_resource_flags(pdev, cnt))) 743 + break; 744 + 745 + if (256 != pci_resource_len(pdev, cnt)) 746 + break; 747 + 748 + ++rc; 749 + } 750 + return rc; 751 + } 752 + 753 + static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) 754 + { 755 + struct memstick_host *msh; 756 + struct jmb38x_ms_host *host; 757 + 758 + msh = memstick_alloc_host(sizeof(struct jmb38x_ms_host), 759 + &jm->pdev->dev); 760 + if (!msh) 761 + return NULL; 762 + 763 + host = memstick_priv(msh); 764 + host->chip = jm; 765 + host->addr = ioremap(pci_resource_start(jm->pdev, cnt), 766 + pci_resource_len(jm->pdev, cnt)); 767 + if (!host->addr) 768 + goto err_out_free; 769 + 770 + spin_lock_init(&host->lock); 771 + host->id = cnt; 772 + snprintf(host->host_id, DEVICE_ID_SIZE, DRIVER_NAME ":slot%d", 773 + host->id); 774 + host->irq = jm->pdev->irq; 775 + host->timeout_jiffies = msecs_to_jiffies(4000); 776 + msh->request = jmb38x_ms_request; 777 + msh->set_param = jmb38x_ms_set_param; 778 + /* 779 + msh->caps = MEMSTICK_CAP_AUTO_GET_INT | MEMSTICK_CAP_PAR4 780 + | MEMSTICK_CAP_PAR8; 781 + */ 782 + msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; 783 + 784 + setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh); 785 + 786 + if (!request_irq(host->irq, jmb38x_ms_isr, IRQF_SHARED, host->host_id, 787 + msh)) 788 + return msh; 789 + 790 + iounmap(host->addr); 791 + err_out_free: 792 + kfree(msh); 793 + return NULL; 794 + } 795 + 796 + static void jmb38x_ms_free_host(struct memstick_host *msh) 797 + { 798 + struct jmb38x_ms_host *host = memstick_priv(msh); 799 + 800 + free_irq(host->irq, msh); 801 + iounmap(host->addr); 802 + memstick_free_host(msh); 803 + } 804 + 805 + static int jmb38x_ms_probe(struct pci_dev *pdev, 806 + const struct pci_device_id *dev_id) 807 + { 808 + struct jmb38x_ms *jm; 809 + int pci_dev_busy = 0; 810 + int rc, cnt; 811 + 812 + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 813 + if (rc) 814 + return rc; 815 + 816 + rc = pci_enable_device(pdev); 817 + if (rc) 818 + return rc; 819 + 820 + pci_set_master(pdev); 821 + 822 + rc = pci_request_regions(pdev, DRIVER_NAME); 823 + if (rc) { 824 + pci_dev_busy = 1; 825 + goto err_out; 826 + } 827 + 828 + pci_read_config_dword(pdev, 0xac, &rc); 829 + pci_write_config_dword(pdev, 0xac, rc | 0x00470000); 830 + 831 + cnt = jmb38x_ms_count_slots(pdev); 832 + if (!cnt) { 833 + rc = -ENODEV; 834 + pci_dev_busy = 1; 835 + goto err_out; 836 + } 837 + 838 + jm = kzalloc(sizeof(struct jmb38x_ms) 839 + + cnt * sizeof(struct memstick_host *), GFP_KERNEL); 840 + if (!jm) { 841 + rc = -ENOMEM; 842 + goto err_out_int; 843 + } 844 + 845 + jm->pdev = pdev; 846 + jm->host_cnt = cnt; 847 + pci_set_drvdata(pdev, jm); 848 + 849 + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { 850 + jm->hosts[cnt] = jmb38x_ms_alloc_host(jm, cnt); 851 + if (!jm->hosts[cnt]) 852 + break; 853 + 854 + rc = memstick_add_host(jm->hosts[cnt]); 855 + 856 + if (rc) { 857 + jmb38x_ms_free_host(jm->hosts[cnt]); 858 + jm->hosts[cnt] = NULL; 859 + break; 860 + } 861 + } 862 + 863 + if (cnt) 864 + return 0; 865 + 866 + rc = -ENODEV; 867 + 868 + pci_set_drvdata(pdev, NULL); 869 + kfree(jm); 870 + err_out_int: 871 + pci_release_regions(pdev); 872 + err_out: 873 + if (!pci_dev_busy) 874 + pci_disable_device(pdev); 875 + return rc; 876 + } 877 + 878 + static void jmb38x_ms_remove(struct pci_dev *dev) 879 + { 880 + struct jmb38x_ms *jm = pci_get_drvdata(dev); 881 + struct jmb38x_ms_host *host; 882 + int cnt; 883 + unsigned long flags; 884 + 885 + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { 886 + if (!jm->hosts[cnt]) 887 + break; 888 + 889 + host = memstick_priv(jm->hosts[cnt]); 890 + 891 + writel(0, host->addr + INT_SIGNAL_ENABLE); 892 + writel(0, host->addr + INT_STATUS_ENABLE); 893 + mmiowb(); 894 + dev_dbg(&jm->pdev->dev, "interrupts off\n"); 895 + spin_lock_irqsave(&host->lock, flags); 896 + if (host->req) { 897 + host->req->error = -ETIME; 898 + jmb38x_ms_complete_cmd(jm->hosts[cnt], 1); 899 + } 900 + spin_unlock_irqrestore(&host->lock, flags); 901 + 902 + memstick_remove_host(jm->hosts[cnt]); 903 + dev_dbg(&jm->pdev->dev, "host removed\n"); 904 + 905 + jmb38x_ms_free_host(jm->hosts[cnt]); 906 + } 907 + 908 + pci_set_drvdata(dev, NULL); 909 + pci_release_regions(dev); 910 + pci_disable_device(dev); 911 + kfree(jm); 912 + } 913 + 914 + static struct pci_device_id jmb38x_ms_id_tbl [] = { 915 + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, 916 + PCI_ANY_ID, 0, 0, 0 }, 917 + { } 918 + }; 919 + 920 + static struct pci_driver jmb38x_ms_driver = { 921 + .name = DRIVER_NAME, 922 + .id_table = jmb38x_ms_id_tbl, 923 + .probe = jmb38x_ms_probe, 924 + .remove = jmb38x_ms_remove, 925 + .suspend = jmb38x_ms_suspend, 926 + .resume = jmb38x_ms_resume 927 + }; 928 + 929 + static int __init jmb38x_ms_init(void) 930 + { 931 + return pci_register_driver(&jmb38x_ms_driver); 932 + } 933 + 934 + static void __exit jmb38x_ms_exit(void) 935 + { 936 + pci_unregister_driver(&jmb38x_ms_driver); 937 + } 938 + 939 + MODULE_AUTHOR("Alex Dubov"); 940 + MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver"); 941 + MODULE_LICENSE("GPL"); 942 + MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl); 943 + 944 + module_init(jmb38x_ms_init); 945 + module_exit(jmb38x_ms_exit);
+1
include/linux/pci_ids.h
··· 2184 2184 #define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 2185 2185 #define PCI_DEVICE_ID_JMICRON_JMB368 0x2368 2186 2186 #define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 2187 + #define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 2187 2188 2188 2189 #define PCI_VENDOR_ID_KORENIX 0x1982 2189 2190 #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600