root/drivers/mmc/host/sdricoh_cs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sdricoh_readl
  2. sdricoh_writel
  3. sdricoh_readw
  4. sdricoh_writew
  5. sdricoh_readb
  6. sdricoh_query_status
  7. sdricoh_mmc_cmd
  8. sdricoh_reset
  9. sdricoh_blockio
  10. sdricoh_request
  11. sdricoh_set_ios
  12. sdricoh_get_ro
  13. sdricoh_init_mmc
  14. sdricoh_pcmcia_probe
  15. sdricoh_pcmcia_detach
  16. sdricoh_pcmcia_suspend
  17. sdricoh_pcmcia_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be
   4  *     found on some Ricoh RL5c476 II cardbus bridge
   5  *
   6  *  Copyright (C) 2006 - 2008 Sascha Sommer <saschasommer@freenet.de>
   7  */
   8 
   9 /*
  10 #define DEBUG
  11 #define VERBOSE_DEBUG
  12 */
  13 #include <linux/delay.h>
  14 #include <linux/highmem.h>
  15 #include <linux/module.h>
  16 #include <linux/pci.h>
  17 #include <linux/ioport.h>
  18 #include <linux/scatterlist.h>
  19 
  20 #include <pcmcia/cistpl.h>
  21 #include <pcmcia/ds.h>
  22 #include <linux/io.h>
  23 
  24 #include <linux/mmc/host.h>
  25 
  26 #define DRIVER_NAME "sdricoh_cs"
  27 
  28 static unsigned int switchlocked;
  29 
  30 /* i/o region */
  31 #define SDRICOH_PCI_REGION 0
  32 #define SDRICOH_PCI_REGION_SIZE 0x1000
  33 
  34 /* registers */
  35 #define R104_VERSION     0x104
  36 #define R200_CMD         0x200
  37 #define R204_CMD_ARG     0x204
  38 #define R208_DATAIO      0x208
  39 #define R20C_RESP        0x20c
  40 #define R21C_STATUS      0x21c
  41 #define R2E0_INIT        0x2e0
  42 #define R2E4_STATUS_RESP 0x2e4
  43 #define R2F0_RESET       0x2f0
  44 #define R224_MODE        0x224
  45 #define R226_BLOCKSIZE   0x226
  46 #define R228_POWER       0x228
  47 #define R230_DATA        0x230
  48 
  49 /* flags for the R21C_STATUS register */
  50 #define STATUS_CMD_FINISHED      0x00000001
  51 #define STATUS_TRANSFER_FINISHED 0x00000004
  52 #define STATUS_CARD_INSERTED     0x00000020
  53 #define STATUS_CARD_LOCKED       0x00000080
  54 #define STATUS_CMD_TIMEOUT       0x00400000
  55 #define STATUS_READY_TO_READ     0x01000000
  56 #define STATUS_READY_TO_WRITE    0x02000000
  57 #define STATUS_BUSY              0x40000000
  58 
  59 /* timeouts */
  60 #define INIT_TIMEOUT      100
  61 #define CMD_TIMEOUT       100000
  62 #define TRANSFER_TIMEOUT  100000
  63 #define BUSY_TIMEOUT      32767
  64 
  65 /* list of supported pcmcia devices */
  66 static const struct pcmcia_device_id pcmcia_ids[] = {
  67         /* vendor and device strings followed by their crc32 hashes */
  68         PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed,
  69                                 0xc3901202),
  70         PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay Controller", 0xd9f522ed,
  71                                 0xace80909),
  72         PCMCIA_DEVICE_NULL,
  73 };
  74 
  75 MODULE_DEVICE_TABLE(pcmcia, pcmcia_ids);
  76 
  77 /* mmc privdata */
  78 struct sdricoh_host {
  79         struct device *dev;
  80         struct mmc_host *mmc;   /* MMC structure */
  81         unsigned char __iomem *iobase;
  82         struct pci_dev *pci_dev;
  83         int app_cmd;
  84 };
  85 
  86 /***************** register i/o helper functions *****************************/
  87 
  88 static inline unsigned int sdricoh_readl(struct sdricoh_host *host,
  89                                          unsigned int reg)
  90 {
  91         unsigned int value = readl(host->iobase + reg);
  92         dev_vdbg(host->dev, "rl %x 0x%x\n", reg, value);
  93         return value;
  94 }
  95 
  96 static inline void sdricoh_writel(struct sdricoh_host *host, unsigned int reg,
  97                                   unsigned int value)
  98 {
  99         writel(value, host->iobase + reg);
 100         dev_vdbg(host->dev, "wl %x 0x%x\n", reg, value);
 101 
 102 }
 103 
 104 static inline unsigned int sdricoh_readw(struct sdricoh_host *host,
 105                                          unsigned int reg)
 106 {
 107         unsigned int value = readw(host->iobase + reg);
 108         dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value);
 109         return value;
 110 }
 111 
 112 static inline void sdricoh_writew(struct sdricoh_host *host, unsigned int reg,
 113                                          unsigned short value)
 114 {
 115         writew(value, host->iobase + reg);
 116         dev_vdbg(host->dev, "ww %x 0x%x\n", reg, value);
 117 }
 118 
 119 static inline unsigned int sdricoh_readb(struct sdricoh_host *host,
 120                                          unsigned int reg)
 121 {
 122         unsigned int value = readb(host->iobase + reg);
 123         dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value);
 124         return value;
 125 }
 126 
 127 static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted,
 128                                 unsigned int timeout){
 129         unsigned int loop;
 130         unsigned int status = 0;
 131         struct device *dev = host->dev;
 132         for (loop = 0; loop < timeout; loop++) {
 133                 status = sdricoh_readl(host, R21C_STATUS);
 134                 sdricoh_writel(host, R2E4_STATUS_RESP, status);
 135                 if (status & wanted)
 136                         break;
 137         }
 138 
 139         if (loop == timeout) {
 140                 dev_err(dev, "query_status: timeout waiting for %x\n", wanted);
 141                 return -ETIMEDOUT;
 142         }
 143 
 144         /* do not do this check in the loop as some commands fail otherwise */
 145         if (status & 0x7F0000) {
 146                 dev_err(dev, "waiting for status bit %x failed\n", wanted);
 147                 return -EINVAL;
 148         }
 149         return 0;
 150 
 151 }
 152 
 153 static int sdricoh_mmc_cmd(struct sdricoh_host *host, unsigned char opcode,
 154                            unsigned int arg)
 155 {
 156         unsigned int status;
 157         int result = 0;
 158         unsigned int loop = 0;
 159         /* reset status reg? */
 160         sdricoh_writel(host, R21C_STATUS, 0x18);
 161         /* fill parameters */
 162         sdricoh_writel(host, R204_CMD_ARG, arg);
 163         sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode);
 164         /* wait for command completion */
 165         if (opcode) {
 166                 for (loop = 0; loop < CMD_TIMEOUT; loop++) {
 167                         status = sdricoh_readl(host, R21C_STATUS);
 168                         sdricoh_writel(host, R2E4_STATUS_RESP, status);
 169                         if (status  & STATUS_CMD_FINISHED)
 170                                 break;
 171                 }
 172                 /* don't check for timeout in the loop it is not always
 173                    reset correctly
 174                 */
 175                 if (loop == CMD_TIMEOUT || status & STATUS_CMD_TIMEOUT)
 176                         result = -ETIMEDOUT;
 177 
 178         }
 179 
 180         return result;
 181 
 182 }
 183 
 184 static int sdricoh_reset(struct sdricoh_host *host)
 185 {
 186         dev_dbg(host->dev, "reset\n");
 187         sdricoh_writel(host, R2F0_RESET, 0x10001);
 188         sdricoh_writel(host, R2E0_INIT, 0x10000);
 189         if (sdricoh_readl(host, R2E0_INIT) != 0x10000)
 190                 return -EIO;
 191         sdricoh_writel(host, R2E0_INIT, 0x10007);
 192 
 193         sdricoh_writel(host, R224_MODE, 0x2000000);
 194         sdricoh_writel(host, R228_POWER, 0xe0);
 195 
 196 
 197         /* status register ? */
 198         sdricoh_writel(host, R21C_STATUS, 0x18);
 199 
 200         return 0;
 201 }
 202 
 203 static int sdricoh_blockio(struct sdricoh_host *host, int read,
 204                                 u8 *buf, int len)
 205 {
 206         int size;
 207         u32 data = 0;
 208         /* wait until the data is available */
 209         if (read) {
 210                 if (sdricoh_query_status(host, STATUS_READY_TO_READ,
 211                                                 TRANSFER_TIMEOUT))
 212                         return -ETIMEDOUT;
 213                 sdricoh_writel(host, R21C_STATUS, 0x18);
 214                 /* read data */
 215                 while (len) {
 216                         data = sdricoh_readl(host, R230_DATA);
 217                         size = min(len, 4);
 218                         len -= size;
 219                         while (size) {
 220                                 *buf = data & 0xFF;
 221                                 buf++;
 222                                 data >>= 8;
 223                                 size--;
 224                         }
 225                 }
 226         } else {
 227                 if (sdricoh_query_status(host, STATUS_READY_TO_WRITE,
 228                                                 TRANSFER_TIMEOUT))
 229                         return -ETIMEDOUT;
 230                 sdricoh_writel(host, R21C_STATUS, 0x18);
 231                 /* write data */
 232                 while (len) {
 233                         size = min(len, 4);
 234                         len -= size;
 235                         while (size) {
 236                                 data >>= 8;
 237                                 data |= (u32)*buf << 24;
 238                                 buf++;
 239                                 size--;
 240                         }
 241                         sdricoh_writel(host, R230_DATA, data);
 242                 }
 243         }
 244 
 245         return 0;
 246 }
 247 
 248 static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq)
 249 {
 250         struct sdricoh_host *host = mmc_priv(mmc);
 251         struct mmc_command *cmd = mrq->cmd;
 252         struct mmc_data *data = cmd->data;
 253         struct device *dev = host->dev;
 254         unsigned char opcode = cmd->opcode;
 255         int i;
 256 
 257         dev_dbg(dev, "=============================\n");
 258         dev_dbg(dev, "sdricoh_request opcode=%i\n", opcode);
 259 
 260         sdricoh_writel(host, R21C_STATUS, 0x18);
 261 
 262         /* MMC_APP_CMDs need some special handling */
 263         if (host->app_cmd) {
 264                 opcode |= 64;
 265                 host->app_cmd = 0;
 266         } else if (opcode == 55)
 267                 host->app_cmd = 1;
 268 
 269         /* read/write commands seem to require this */
 270         if (data) {
 271                 sdricoh_writew(host, R226_BLOCKSIZE, data->blksz);
 272                 sdricoh_writel(host, R208_DATAIO, 0);
 273         }
 274 
 275         cmd->error = sdricoh_mmc_cmd(host, opcode, cmd->arg);
 276 
 277         /* read response buffer */
 278         if (cmd->flags & MMC_RSP_PRESENT) {
 279                 if (cmd->flags & MMC_RSP_136) {
 280                         /* CRC is stripped so we need to do some shifting. */
 281                         for (i = 0; i < 4; i++) {
 282                                 cmd->resp[i] =
 283                                     sdricoh_readl(host,
 284                                                   R20C_RESP + (3 - i) * 4) << 8;
 285                                 if (i != 3)
 286                                         cmd->resp[i] |=
 287                                             sdricoh_readb(host, R20C_RESP +
 288                                                           (3 - i) * 4 - 1);
 289                         }
 290                 } else
 291                         cmd->resp[0] = sdricoh_readl(host, R20C_RESP);
 292         }
 293 
 294         /* transfer data */
 295         if (data && cmd->error == 0) {
 296                 dev_dbg(dev, "transfer: blksz %i blocks %i sg_len %i "
 297                         "sg length %i\n", data->blksz, data->blocks,
 298                         data->sg_len, data->sg->length);
 299 
 300                 /* enter data reading mode */
 301                 sdricoh_writel(host, R21C_STATUS, 0x837f031e);
 302                 for (i = 0; i < data->blocks; i++) {
 303                         size_t len = data->blksz;
 304                         u8 *buf;
 305                         struct page *page;
 306                         int result;
 307                         page = sg_page(data->sg);
 308 
 309                         buf = kmap(page) + data->sg->offset + (len * i);
 310                         result =
 311                                 sdricoh_blockio(host,
 312                                         data->flags & MMC_DATA_READ, buf, len);
 313                         kunmap(page);
 314                         flush_dcache_page(page);
 315                         if (result) {
 316                                 dev_err(dev, "sdricoh_request: cmd %i "
 317                                         "block transfer failed\n", cmd->opcode);
 318                                 cmd->error = result;
 319                                 break;
 320                         } else
 321                                 data->bytes_xfered += len;
 322                 }
 323 
 324                 sdricoh_writel(host, R208_DATAIO, 1);
 325 
 326                 if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED,
 327                                         TRANSFER_TIMEOUT)) {
 328                         dev_err(dev, "sdricoh_request: transfer end error\n");
 329                         cmd->error = -EINVAL;
 330                 }
 331         }
 332         /* FIXME check busy flag */
 333 
 334         mmc_request_done(mmc, mrq);
 335         dev_dbg(dev, "=============================\n");
 336 }
 337 
 338 static void sdricoh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 339 {
 340         struct sdricoh_host *host = mmc_priv(mmc);
 341         dev_dbg(host->dev, "set_ios\n");
 342 
 343         if (ios->power_mode == MMC_POWER_ON) {
 344                 sdricoh_writel(host, R228_POWER, 0xc0e0);
 345 
 346                 if (ios->bus_width == MMC_BUS_WIDTH_4) {
 347                         sdricoh_writel(host, R224_MODE, 0x2000300);
 348                         sdricoh_writel(host, R228_POWER, 0x40e0);
 349                 } else {
 350                         sdricoh_writel(host, R224_MODE, 0x2000340);
 351                 }
 352 
 353         } else if (ios->power_mode == MMC_POWER_UP) {
 354                 sdricoh_writel(host, R224_MODE, 0x2000320);
 355                 sdricoh_writel(host, R228_POWER, 0xe0);
 356         }
 357 }
 358 
 359 static int sdricoh_get_ro(struct mmc_host *mmc)
 360 {
 361         struct sdricoh_host *host = mmc_priv(mmc);
 362         unsigned int status;
 363 
 364         status = sdricoh_readl(host, R21C_STATUS);
 365         sdricoh_writel(host, R2E4_STATUS_RESP, status);
 366 
 367         /* some notebooks seem to have the locked flag switched */
 368         if (switchlocked)
 369                 return !(status & STATUS_CARD_LOCKED);
 370 
 371         return (status & STATUS_CARD_LOCKED);
 372 }
 373 
 374 static const struct mmc_host_ops sdricoh_ops = {
 375         .request = sdricoh_request,
 376         .set_ios = sdricoh_set_ios,
 377         .get_ro = sdricoh_get_ro,
 378 };
 379 
 380 /* initialize the control and register it to the mmc framework */
 381 static int sdricoh_init_mmc(struct pci_dev *pci_dev,
 382                             struct pcmcia_device *pcmcia_dev)
 383 {
 384         int result;
 385         void __iomem *iobase;
 386         struct mmc_host *mmc;
 387         struct sdricoh_host *host;
 388         struct device *dev = &pcmcia_dev->dev;
 389         /* map iomem */
 390         if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) !=
 391             SDRICOH_PCI_REGION_SIZE) {
 392                 dev_dbg(dev, "unexpected pci resource len\n");
 393                 return -ENODEV;
 394         }
 395         iobase =
 396             pci_iomap(pci_dev, SDRICOH_PCI_REGION, SDRICOH_PCI_REGION_SIZE);
 397         if (!iobase) {
 398                 dev_err(dev, "unable to map iobase\n");
 399                 return -ENODEV;
 400         }
 401         /* check version? */
 402         if (readl(iobase + R104_VERSION) != 0x4000) {
 403                 dev_dbg(dev, "no supported mmc controller found\n");
 404                 result = -ENODEV;
 405                 goto unmap_io;
 406         }
 407         /* allocate privdata */
 408         mmc = pcmcia_dev->priv =
 409             mmc_alloc_host(sizeof(struct sdricoh_host), &pcmcia_dev->dev);
 410         if (!mmc) {
 411                 dev_err(dev, "mmc_alloc_host failed\n");
 412                 result = -ENOMEM;
 413                 goto unmap_io;
 414         }
 415         host = mmc_priv(mmc);
 416 
 417         host->iobase = iobase;
 418         host->dev = dev;
 419         host->pci_dev = pci_dev;
 420 
 421         mmc->ops = &sdricoh_ops;
 422 
 423         /* FIXME: frequency and voltage handling is done by the controller
 424          */
 425         mmc->f_min = 450000;
 426         mmc->f_max = 24000000;
 427         mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 428         mmc->caps |= MMC_CAP_4_BIT_DATA;
 429 
 430         mmc->max_seg_size = 1024 * 512;
 431         mmc->max_blk_size = 512;
 432 
 433         /* reset the controller */
 434         if (sdricoh_reset(host)) {
 435                 dev_dbg(dev, "could not reset\n");
 436                 result = -EIO;
 437                 goto free_host;
 438         }
 439 
 440         result = mmc_add_host(mmc);
 441 
 442         if (!result) {
 443                 dev_dbg(dev, "mmc host registered\n");
 444                 return 0;
 445         }
 446 free_host:
 447         mmc_free_host(mmc);
 448 unmap_io:
 449         pci_iounmap(pci_dev, iobase);
 450         return result;
 451 }
 452 
 453 /* search for supported mmc controllers */
 454 static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev)
 455 {
 456         struct pci_dev *pci_dev = NULL;
 457 
 458         dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device"
 459                 " %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]);
 460 
 461         /* search pci cardbus bridge that contains the mmc controller */
 462         /* the io region is already claimed by yenta_socket... */
 463         while ((pci_dev =
 464                 pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476,
 465                                pci_dev))) {
 466                 /* try to init the device */
 467                 if (!sdricoh_init_mmc(pci_dev, pcmcia_dev)) {
 468                         dev_info(&pcmcia_dev->dev, "MMC controller found\n");
 469                         return 0;
 470                 }
 471 
 472         }
 473         dev_err(&pcmcia_dev->dev, "No MMC controller was found.\n");
 474         return -ENODEV;
 475 }
 476 
 477 static void sdricoh_pcmcia_detach(struct pcmcia_device *link)
 478 {
 479         struct mmc_host *mmc = link->priv;
 480 
 481         dev_dbg(&link->dev, "detach\n");
 482 
 483         /* remove mmc host */
 484         if (mmc) {
 485                 struct sdricoh_host *host = mmc_priv(mmc);
 486                 mmc_remove_host(mmc);
 487                 pci_iounmap(host->pci_dev, host->iobase);
 488                 pci_dev_put(host->pci_dev);
 489                 mmc_free_host(mmc);
 490         }
 491         pcmcia_disable_device(link);
 492 
 493 }
 494 
 495 #ifdef CONFIG_PM
 496 static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
 497 {
 498         dev_dbg(&link->dev, "suspend\n");
 499         return 0;
 500 }
 501 
 502 static int sdricoh_pcmcia_resume(struct pcmcia_device *link)
 503 {
 504         struct mmc_host *mmc = link->priv;
 505         dev_dbg(&link->dev, "resume\n");
 506         sdricoh_reset(mmc_priv(mmc));
 507         return 0;
 508 }
 509 #else
 510 #define sdricoh_pcmcia_suspend NULL
 511 #define sdricoh_pcmcia_resume NULL
 512 #endif
 513 
 514 static struct pcmcia_driver sdricoh_driver = {
 515         .name = DRIVER_NAME,
 516         .probe = sdricoh_pcmcia_probe,
 517         .remove = sdricoh_pcmcia_detach,
 518         .id_table = pcmcia_ids,
 519         .suspend = sdricoh_pcmcia_suspend,
 520         .resume = sdricoh_pcmcia_resume,
 521 };
 522 module_pcmcia_driver(sdricoh_driver);
 523 
 524 module_param(switchlocked, uint, 0444);
 525 
 526 MODULE_AUTHOR("Sascha Sommer <saschasommer@freenet.de>");
 527 MODULE_DESCRIPTION("Ricoh PCMCIA Secure Digital Interface driver");
 528 MODULE_LICENSE("GPL");
 529 
 530 MODULE_PARM_DESC(switchlocked, "Switch the cards locked status."
 531                 "Use this when unlocked cards are shown readonly (default 0)");

/* [<][>][^][v][top][bottom][index][help] */