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