// SPDX-License-Identifier: GPL-2.0-or-later /* * sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be * found on some Ricoh RL5c476 II cardbus bridge * * Copyright (C) 2006 - 2008 Sascha Sommer <saschasommer@freenet.de>
*/
staticint sdricoh_query_status(struct sdricoh_host *host, unsignedint wanted)
{ int ret; unsignedint status = 0; struct device *dev = host->dev;
ret = read_poll_timeout(sdricoh_readl, status,
sdricoh_status_ok(host, status, wanted),
32, SDRICOH_DATA_TIMEOUT_US, false,
host, R21C_STATUS); if (ret) {
dev_err(dev, "query_status: timeout waiting for %x\n", wanted); return -ETIMEDOUT;
}
/* do not do this check in the loop as some commands fail otherwise */ if (status & 0x7F0000) {
dev_err(dev, "waiting for status bit %x failed\n", wanted); return -EINVAL;
} return 0;
/* status register ? */
sdricoh_writel(host, R21C_STATUS, 0x18);
return 0;
}
staticint sdricoh_blockio(struct sdricoh_host *host, int read,
u8 *buf, int len)
{ int size;
u32 data = 0; /* wait until the data is available */ if (read) { if (sdricoh_query_status(host, STATUS_READY_TO_READ)) return -ETIMEDOUT;
sdricoh_writel(host, R21C_STATUS, 0x18); /* read data */ while (len) {
data = sdricoh_readl(host, R230_DATA);
size = min(len, 4);
len -= size; while (size) {
*buf = data & 0xFF;
buf++;
data >>= 8;
size--;
}
}
} else { if (sdricoh_query_status(host, STATUS_READY_TO_WRITE)) return -ETIMEDOUT;
sdricoh_writel(host, R21C_STATUS, 0x18); /* write data */ while (len) {
size = min(len, 4);
len -= size; while (size) {
data >>= 8;
data |= (u32)*buf << 24;
buf++;
size--;
}
sdricoh_writel(host, R230_DATA, data);
}
}
/* read/write commands seem to require this */ if (data) {
sdricoh_writew(host, R226_BLOCKSIZE, data->blksz);
sdricoh_writel(host, R208_DATAIO, 0);
}
cmd->error = sdricoh_mmc_cmd(host, cmd);
/* read response buffer */ if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { /* CRC is stripped so we need to do some shifting. */ for (i = 0; i < 4; i++) {
cmd->resp[i] =
sdricoh_readl(host,
R20C_RESP + (3 - i) * 4) << 8; if (i != 3)
cmd->resp[i] |=
sdricoh_readb(host, R20C_RESP +
(3 - i) * 4 - 1);
}
} else
cmd->resp[0] = sdricoh_readl(host, R20C_RESP);
}
/* transfer data */ if (data && cmd->error == 0) {
dev_dbg(dev, "transfer: blksz %i blocks %i sg_len %i " "sg length %i\n", data->blksz, data->blocks,
data->sg_len, data->sg->length);
/* enter data reading mode */
sdricoh_writel(host, R21C_STATUS, 0x837f031e); for (i = 0; i < data->blocks; i++) {
size_t len = data->blksz;
u8 *buf; struct page *page; int result;
page = sg_page(data->sg);
if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED)) {
dev_err(dev, "sdricoh_request: transfer end error\n");
cmd->error = -EINVAL;
}
} /* FIXME check busy flag */
/* FIXME: frequency and voltage handling is done by the controller
*/
mmc->f_min = 450000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps |= MMC_CAP_4_BIT_DATA;
/* search pci cardbus bridge that contains the mmc controller */ /* the io region is already claimed by yenta_socket... */ while ((pci_dev =
pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476,
pci_dev))) { /* try to init the device */ if (!sdricoh_init_mmc(pci_dev, pcmcia_dev)) {
dev_info(&pcmcia_dev->dev, "MMC controller found\n"); return 0;
}
}
dev_err(&pcmcia_dev->dev, "No MMC controller was found.\n"); return -ENODEV;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.