Lines Matching +full:mmc +full:- +full:host
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be
6 * Copyright (C) 2006 - 2008 Sascha Sommer <saschasommer@freenet.de>
25 #include <linux/mmc/host.h>
26 #include <linux/mmc/mmc.h>
77 /* mmc privdata */
80 struct mmc_host *mmc; /* MMC structure */ member
88 static inline unsigned int sdricoh_readl(struct sdricoh_host *host, in sdricoh_readl() argument
91 unsigned int value = readl(host->iobase + reg); in sdricoh_readl()
92 dev_vdbg(host->dev, "rl %x 0x%x\n", reg, value); in sdricoh_readl()
96 static inline void sdricoh_writel(struct sdricoh_host *host, unsigned int reg, in sdricoh_writel() argument
99 writel(value, host->iobase + reg); in sdricoh_writel()
100 dev_vdbg(host->dev, "wl %x 0x%x\n", reg, value); in sdricoh_writel()
104 static inline void sdricoh_writew(struct sdricoh_host *host, unsigned int reg, in sdricoh_writew() argument
107 writew(value, host->iobase + reg); in sdricoh_writew()
108 dev_vdbg(host->dev, "ww %x 0x%x\n", reg, value); in sdricoh_writew()
111 static inline unsigned int sdricoh_readb(struct sdricoh_host *host, in sdricoh_readb() argument
114 unsigned int value = readb(host->iobase + reg); in sdricoh_readb()
115 dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value); in sdricoh_readb()
119 static bool sdricoh_status_ok(struct sdricoh_host *host, unsigned int status, in sdricoh_status_ok() argument
122 sdricoh_writel(host, R2E4_STATUS_RESP, status); in sdricoh_status_ok()
126 static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted) in sdricoh_query_status() argument
130 struct device *dev = host->dev; in sdricoh_query_status()
133 sdricoh_status_ok(host, status, wanted), in sdricoh_query_status()
135 host, R21C_STATUS); in sdricoh_query_status()
138 return -ETIMEDOUT; in sdricoh_query_status()
144 return -EINVAL; in sdricoh_query_status()
150 static int sdricoh_mmc_cmd(struct sdricoh_host *host, struct mmc_command *cmd) in sdricoh_mmc_cmd() argument
154 unsigned char opcode = cmd->opcode; in sdricoh_mmc_cmd()
157 sdricoh_writel(host, R21C_STATUS, 0x18); in sdricoh_mmc_cmd()
160 if (host->app_cmd) { in sdricoh_mmc_cmd()
162 host->app_cmd = 0; in sdricoh_mmc_cmd()
164 host->app_cmd = 1; in sdricoh_mmc_cmd()
167 sdricoh_writel(host, R204_CMD_ARG, cmd->arg); in sdricoh_mmc_cmd()
168 sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode); in sdricoh_mmc_cmd()
174 timeout_us = cmd->busy_timeout ? cmd->busy_timeout * 1000 : in sdricoh_mmc_cmd()
178 sdricoh_status_ok(host, status, STATUS_CMD_FINISHED), in sdricoh_mmc_cmd()
180 host, R21C_STATUS); in sdricoh_mmc_cmd()
187 return -ETIMEDOUT; in sdricoh_mmc_cmd()
192 static int sdricoh_reset(struct sdricoh_host *host) in sdricoh_reset() argument
194 dev_dbg(host->dev, "reset\n"); in sdricoh_reset()
195 sdricoh_writel(host, R2F0_RESET, 0x10001); in sdricoh_reset()
196 sdricoh_writel(host, R2E0_INIT, 0x10000); in sdricoh_reset()
197 if (sdricoh_readl(host, R2E0_INIT) != 0x10000) in sdricoh_reset()
198 return -EIO; in sdricoh_reset()
199 sdricoh_writel(host, R2E0_INIT, 0x10007); in sdricoh_reset()
201 sdricoh_writel(host, R224_MODE, 0x2000000); in sdricoh_reset()
202 sdricoh_writel(host, R228_POWER, 0xe0); in sdricoh_reset()
206 sdricoh_writel(host, R21C_STATUS, 0x18); in sdricoh_reset()
211 static int sdricoh_blockio(struct sdricoh_host *host, int read, in sdricoh_blockio() argument
218 if (sdricoh_query_status(host, STATUS_READY_TO_READ)) in sdricoh_blockio()
219 return -ETIMEDOUT; in sdricoh_blockio()
220 sdricoh_writel(host, R21C_STATUS, 0x18); in sdricoh_blockio()
223 data = sdricoh_readl(host, R230_DATA); in sdricoh_blockio()
225 len -= size; in sdricoh_blockio()
230 size--; in sdricoh_blockio()
234 if (sdricoh_query_status(host, STATUS_READY_TO_WRITE)) in sdricoh_blockio()
235 return -ETIMEDOUT; in sdricoh_blockio()
236 sdricoh_writel(host, R21C_STATUS, 0x18); in sdricoh_blockio()
240 len -= size; in sdricoh_blockio()
245 size--; in sdricoh_blockio()
247 sdricoh_writel(host, R230_DATA, data); in sdricoh_blockio()
254 static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) in sdricoh_request() argument
256 struct sdricoh_host *host = mmc_priv(mmc); in sdricoh_request() local
257 struct mmc_command *cmd = mrq->cmd; in sdricoh_request()
258 struct mmc_data *data = cmd->data; in sdricoh_request()
259 struct device *dev = host->dev; in sdricoh_request()
263 dev_dbg(dev, "sdricoh_request opcode=%i\n", cmd->opcode); in sdricoh_request()
265 sdricoh_writel(host, R21C_STATUS, 0x18); in sdricoh_request()
269 sdricoh_writew(host, R226_BLOCKSIZE, data->blksz); in sdricoh_request()
270 sdricoh_writel(host, R208_DATAIO, 0); in sdricoh_request()
273 cmd->error = sdricoh_mmc_cmd(host, cmd); in sdricoh_request()
276 if (cmd->flags & MMC_RSP_PRESENT) { in sdricoh_request()
277 if (cmd->flags & MMC_RSP_136) { in sdricoh_request()
280 cmd->resp[i] = in sdricoh_request()
281 sdricoh_readl(host, in sdricoh_request()
282 R20C_RESP + (3 - i) * 4) << 8; in sdricoh_request()
284 cmd->resp[i] |= in sdricoh_request()
285 sdricoh_readb(host, R20C_RESP + in sdricoh_request()
286 (3 - i) * 4 - 1); in sdricoh_request()
289 cmd->resp[0] = sdricoh_readl(host, R20C_RESP); in sdricoh_request()
293 if (data && cmd->error == 0) { in sdricoh_request()
295 "sg length %i\n", data->blksz, data->blocks, in sdricoh_request()
296 data->sg_len, data->sg->length); in sdricoh_request()
299 sdricoh_writel(host, R21C_STATUS, 0x837f031e); in sdricoh_request()
300 for (i = 0; i < data->blocks; i++) { in sdricoh_request()
301 size_t len = data->blksz; in sdricoh_request()
305 page = sg_page(data->sg); in sdricoh_request()
307 buf = kmap(page) + data->sg->offset + (len * i); in sdricoh_request()
309 sdricoh_blockio(host, in sdricoh_request()
310 data->flags & MMC_DATA_READ, buf, len); in sdricoh_request()
315 "block transfer failed\n", cmd->opcode); in sdricoh_request()
316 cmd->error = result; in sdricoh_request()
319 data->bytes_xfered += len; in sdricoh_request()
322 sdricoh_writel(host, R208_DATAIO, 1); in sdricoh_request()
324 if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED)) { in sdricoh_request()
326 cmd->error = -EINVAL; in sdricoh_request()
331 mmc_request_done(mmc, mrq); in sdricoh_request()
335 static void sdricoh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) in sdricoh_set_ios() argument
337 struct sdricoh_host *host = mmc_priv(mmc); in sdricoh_set_ios() local
338 dev_dbg(host->dev, "set_ios\n"); in sdricoh_set_ios()
340 if (ios->power_mode == MMC_POWER_ON) { in sdricoh_set_ios()
341 sdricoh_writel(host, R228_POWER, 0xc0e0); in sdricoh_set_ios()
343 if (ios->bus_width == MMC_BUS_WIDTH_4) { in sdricoh_set_ios()
344 sdricoh_writel(host, R224_MODE, 0x2000300); in sdricoh_set_ios()
345 sdricoh_writel(host, R228_POWER, 0x40e0); in sdricoh_set_ios()
347 sdricoh_writel(host, R224_MODE, 0x2000340); in sdricoh_set_ios()
350 } else if (ios->power_mode == MMC_POWER_UP) { in sdricoh_set_ios()
351 sdricoh_writel(host, R224_MODE, 0x2000320); in sdricoh_set_ios()
352 sdricoh_writel(host, R228_POWER, 0xe0); in sdricoh_set_ios()
356 static int sdricoh_get_ro(struct mmc_host *mmc) in sdricoh_get_ro() argument
358 struct sdricoh_host *host = mmc_priv(mmc); in sdricoh_get_ro() local
361 status = sdricoh_readl(host, R21C_STATUS); in sdricoh_get_ro()
362 sdricoh_writel(host, R2E4_STATUS_RESP, status); in sdricoh_get_ro()
377 /* initialize the control and register it to the mmc framework */
383 struct mmc_host *mmc; in sdricoh_init_mmc() local
384 struct sdricoh_host *host; in sdricoh_init_mmc() local
385 struct device *dev = &pcmcia_dev->dev; in sdricoh_init_mmc()
390 return -ENODEV; in sdricoh_init_mmc()
396 return -ENODEV; in sdricoh_init_mmc()
400 dev_dbg(dev, "no supported mmc controller found\n"); in sdricoh_init_mmc()
401 result = -ENODEV; in sdricoh_init_mmc()
405 mmc = pcmcia_dev->priv = in sdricoh_init_mmc()
406 mmc_alloc_host(sizeof(struct sdricoh_host), &pcmcia_dev->dev); in sdricoh_init_mmc()
407 if (!mmc) { in sdricoh_init_mmc()
409 result = -ENOMEM; in sdricoh_init_mmc()
412 host = mmc_priv(mmc); in sdricoh_init_mmc()
414 host->iobase = iobase; in sdricoh_init_mmc()
415 host->dev = dev; in sdricoh_init_mmc()
416 host->pci_dev = pci_dev; in sdricoh_init_mmc()
418 mmc->ops = &sdricoh_ops; in sdricoh_init_mmc()
422 mmc->f_min = 450000; in sdricoh_init_mmc()
423 mmc->f_max = 24000000; in sdricoh_init_mmc()
424 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; in sdricoh_init_mmc()
425 mmc->caps |= MMC_CAP_4_BIT_DATA; in sdricoh_init_mmc()
427 mmc->max_seg_size = 1024 * 512; in sdricoh_init_mmc()
428 mmc->max_blk_size = 512; in sdricoh_init_mmc()
431 if (sdricoh_reset(host)) { in sdricoh_init_mmc()
433 result = -EIO; in sdricoh_init_mmc()
437 result = mmc_add_host(mmc); in sdricoh_init_mmc()
440 dev_dbg(dev, "mmc host registered\n"); in sdricoh_init_mmc()
444 mmc_free_host(mmc); in sdricoh_init_mmc()
450 /* search for supported mmc controllers */
455 dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device" in sdricoh_pcmcia_probe()
456 " %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]); in sdricoh_pcmcia_probe()
458 /* search pci cardbus bridge that contains the mmc controller */ in sdricoh_pcmcia_probe()
465 dev_info(&pcmcia_dev->dev, "MMC controller found\n"); in sdricoh_pcmcia_probe()
470 dev_err(&pcmcia_dev->dev, "No MMC controller was found.\n"); in sdricoh_pcmcia_probe()
471 return -ENODEV; in sdricoh_pcmcia_probe()
476 struct mmc_host *mmc = link->priv; in sdricoh_pcmcia_detach() local
478 dev_dbg(&link->dev, "detach\n"); in sdricoh_pcmcia_detach()
480 /* remove mmc host */ in sdricoh_pcmcia_detach()
481 if (mmc) { in sdricoh_pcmcia_detach()
482 struct sdricoh_host *host = mmc_priv(mmc); in sdricoh_pcmcia_detach() local
483 mmc_remove_host(mmc); in sdricoh_pcmcia_detach()
484 pci_iounmap(host->pci_dev, host->iobase); in sdricoh_pcmcia_detach()
485 pci_dev_put(host->pci_dev); in sdricoh_pcmcia_detach()
486 mmc_free_host(mmc); in sdricoh_pcmcia_detach()
495 dev_dbg(&link->dev, "suspend\n"); in sdricoh_pcmcia_suspend()
501 struct mmc_host *mmc = link->priv; in sdricoh_pcmcia_resume() local
502 dev_dbg(&link->dev, "resume\n"); in sdricoh_pcmcia_resume()
503 sdricoh_reset(mmc_priv(mmc)); in sdricoh_pcmcia_resume()