From 67e054e919248fa1db93de727fb9ad49eb700642 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 22 Feb 2010 20:39:42 +0200 Subject: mtd: nand: Add driver for Ricoh xD/SmartMedia reader This adds a driver for Ricoh R5C852 xD card reader. This reader is a part of larger mulifunction chip and found at least in R5C832 Driver is complete, but bewere of the fact that some (probably only type M) xD cards are 'fake' which means that they have an on board CPU and expose emulated nand command set These cards don't even store the oob area on the flash, but generate it on the fly from something else. Thus they demand to have proper values written in the oob area, and therefore only useful with SmartMedia FTL. Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 1117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1117 insertions(+) create mode 100644 drivers/mtd/nand/r852.c (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c new file mode 100644 index 00000000000..9307a88e522 --- /dev/null +++ b/drivers/mtd/nand/r852.c @@ -0,0 +1,1117 @@ +/* + * Copyright © 2009 - Maxim Levitsky + * driver for Ricoh xD readers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sm_common.h" +#include "r852.h" + + +static int enable_dma = 1; +module_param(enable_dma, bool, S_IRUGO); +MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); + +static int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +/* read register */ +static inline uint8_t r852_read_reg(struct r852_device *dev, int address) +{ + uint8_t reg = readb(dev->mmio + address); + return reg; +} + +/* write register */ +static inline void r852_write_reg(struct r852_device *dev, + int address, uint8_t value) +{ + writeb(value, dev->mmio + address); + mmiowb(); +} + + +/* read dword sized register */ +static inline uint32_t r852_read_reg_dword(struct r852_device *dev, int address) +{ + uint32_t reg = le32_to_cpu(readl(dev->mmio + address)); + return reg; +} + +/* write dword sized register */ +static inline void r852_write_reg_dword(struct r852_device *dev, + int address, uint32_t value) +{ + writel(cpu_to_le32(value), dev->mmio + address); + mmiowb(); +} + +/* returns pointer to our private structure */ +static inline struct r852_device *r852_get_dev(struct mtd_info *mtd) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + return (struct r852_device *)chip->priv; +} + + +/* check if controller supports dma */ +static void r852_dma_test(struct r852_device *dev) +{ + dev->dma_usable = (r852_read_reg(dev, R852_DMA_CAP) & + (R852_DMA1 | R852_DMA2)) == (R852_DMA1 | R852_DMA2); + + if (!dev->dma_usable) + message("Non dma capable device detected, dma disabled"); + + if (!enable_dma) { + message("disabling dma on user request"); + dev->dma_usable = 0; + } +} + +/* + * Enable dma. Enables ether first or second stage of the DMA, + * Expects dev->dma_dir and dev->dma_state be set + */ +static void r852_dma_enable(struct r852_device *dev) +{ + uint8_t dma_reg, dma_irq_reg; + + /* Set up dma settings */ + dma_reg = r852_read_reg_dword(dev, R852_DMA_SETTINGS); + dma_reg &= ~(R852_DMA_READ | R852_DMA_INTERNAL | R852_DMA_MEMORY); + + if (dev->dma_dir) + dma_reg |= R852_DMA_READ; + + if (dev->dma_state == DMA_INTERNAL) + dma_reg |= R852_DMA_INTERNAL; + else { + dma_reg |= R852_DMA_MEMORY; + r852_write_reg_dword(dev, R852_DMA_ADDR, + cpu_to_le32(dev->phys_dma_addr)); + } + + r852_write_reg_dword(dev, R852_DMA_SETTINGS, dma_reg); + + /* Set dma irq */ + dma_irq_reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE); + r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, + dma_irq_reg | + R852_DMA_IRQ_INTERNAL | + R852_DMA_IRQ_ERROR | + R852_DMA_IRQ_MEMORY); +} + +/* + * Disable dma, called from the interrupt handler, which specifies + * success of the operation via 'error' argument + */ +static void r852_dma_done(struct r852_device *dev, int error) +{ + WARN_ON(dev->dma_stage == 0); + + r852_write_reg_dword(dev, R852_DMA_IRQ_STA, + r852_read_reg_dword(dev, R852_DMA_IRQ_STA)); + + r852_write_reg_dword(dev, R852_DMA_SETTINGS, 0); + r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, 0); + + dev->dma_error = error; + dev->dma_stage = 0; + + if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer) + pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN, + dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + complete(&dev->dma_done); +} + +/* + * Wait, till dma is done, which includes both phases of it + */ +static int r852_dma_wait(struct r852_device *dev) +{ + long timeout = wait_for_completion_timeout(&dev->dma_done, + msecs_to_jiffies(1000)); + if (!timeout) { + dbg("timeout waiting for DMA interrupt"); + return -ETIMEDOUT; + } + + return 0; +} + +/* + * Read/Write one page using dma. Only pages can be read (512 bytes) +*/ +static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) +{ + int bounce = 0; + unsigned long flags; + int error; + + dev->dma_error = 0; + + /* Set dma direction */ + dev->dma_dir = do_read; + dev->dma_stage = 1; + + dbg_verbose("doing dma %s ", do_read ? "read" : "write"); + + /* Set intial dma state: for reading first fill on board buffer, + from device, for writes first fill the buffer from memory*/ + dev->dma_state = do_read ? DMA_INTERNAL : DMA_MEMORY; + + /* if incoming buffer is not page aligned, we should do bounce */ + if ((unsigned long)buf & (R852_DMA_LEN-1)) + bounce = 1; + + if (!bounce) { + dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf, + R852_DMA_LEN, + (do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); + + if (dev->phys_dma_addr == DMA_ERROR_CODE) + bounce = 1; + } + + if (bounce) { + dbg_verbose("dma: using bounce buffer"); + dev->phys_dma_addr = dev->phys_bounce_buffer; + if (!do_read) + memcpy(dev->bounce_buffer, buf, R852_DMA_LEN); + } + + /* Enable DMA */ + spin_lock_irqsave(&dev->irqlock, flags); + r852_dma_enable(dev); + spin_unlock_irqrestore(&dev->irqlock, flags); + + /* Wait till complete */ + error = r852_dma_wait(dev); + + if (error) { + r852_dma_done(dev, error); + return; + } + + if (do_read && bounce) + memcpy((void *)buf, dev->bounce_buffer, R852_DMA_LEN); +} + +/* + * Program data lines of the nand chip to send data to it + */ +void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct r852_device *dev = r852_get_dev(mtd); + uint32_t reg; + + /* Don't allow any access to hardware if we suspect card removal */ + if (dev->card_unstable) + return; + + /* Special case for whole sector read */ + if (len == R852_DMA_LEN && dev->dma_usable) { + r852_do_dma(dev, (uint8_t *)buf, 0); + return; + } + + /* write DWORD chinks - faster */ + while (len) { + reg = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; + r852_write_reg_dword(dev, R852_DATALINE, reg); + buf += 4; + len -= 4; + + } + + /* write rest */ + while (len) + r852_write_reg(dev, R852_DATALINE, *buf++); +} + +/* + * Read data lines of the nand chip to retrieve data + */ +void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct r852_device *dev = r852_get_dev(mtd); + uint32_t reg; + + if (dev->card_unstable) { + /* since we can't signal error here, at least, return + predictable buffer */ + memset(buf, 0, len); + return; + } + + /* special case for whole sector read */ + if (len == R852_DMA_LEN && dev->dma_usable) { + r852_do_dma(dev, buf, 1); + return; + } + + /* read in dword sized chunks */ + while (len >= 4) { + + reg = r852_read_reg_dword(dev, R852_DATALINE); + *buf++ = reg & 0xFF; + *buf++ = (reg >> 8) & 0xFF; + *buf++ = (reg >> 16) & 0xFF; + *buf++ = (reg >> 24) & 0xFF; + len -= 4; + } + + /* read the reset by bytes */ + while (len--) + *buf++ = r852_read_reg(dev, R852_DATALINE); +} + +/* + * Read one byte from nand chip + */ +static uint8_t r852_read_byte(struct mtd_info *mtd) +{ + struct r852_device *dev = r852_get_dev(mtd); + + /* Same problem as in r852_read_buf.... */ + if (dev->card_unstable) + return 0; + + return r852_read_reg(dev, R852_DATALINE); +} + + +/* + * Readback the buffer to verify it + */ +int r852_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct r852_device *dev = r852_get_dev(mtd); + + /* We can't be sure about anything here... */ + if (dev->card_unstable) + return -1; + + /* This will never happen, unless you wired up a nand chip + with > 512 bytes page size to the reader */ + if (len > SM_SECTOR_SIZE) + return 0; + + r852_read_buf(mtd, dev->tmp_buffer, len); + return memcmp(buf, dev->tmp_buffer, len); +} + +/* + * Control several chip lines & send commands + */ +void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct r852_device *dev = r852_get_dev(mtd); + + if (dev->card_unstable) + return; + + if (ctrl & NAND_CTRL_CHANGE) { + + dev->ctlreg &= ~(R852_CTL_DATA | R852_CTL_COMMAND | + R852_CTL_ON | R852_CTL_CARDENABLE); + + if (ctrl & NAND_ALE) + dev->ctlreg |= R852_CTL_DATA; + + if (ctrl & NAND_CLE) + dev->ctlreg |= R852_CTL_COMMAND; + + if (ctrl & NAND_NCE) + dev->ctlreg |= (R852_CTL_CARDENABLE | R852_CTL_ON); + else + dev->ctlreg &= ~R852_CTL_WRITE; + + /* when write is stareted, enable write access */ + if (dat == NAND_CMD_ERASE1) + dev->ctlreg |= R852_CTL_WRITE; + + r852_write_reg(dev, R852_CTL, dev->ctlreg); + } + + /* HACK: NAND_CMD_SEQIN is called without NAND_CTRL_CHANGE, but we need + to set write mode */ + if (dat == NAND_CMD_SEQIN && (dev->ctlreg & R852_CTL_COMMAND)) { + dev->ctlreg |= R852_CTL_WRITE; + r852_write_reg(dev, R852_CTL, dev->ctlreg); + } + + if (dat != NAND_CMD_NONE) + r852_write_reg(dev, R852_DATALINE, dat); +} + +/* + * Wait till card is ready. + * based on nand_wait, but returns errors on DMA error + */ +int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct r852_device *dev = (struct r852_device *)chip->priv; + + unsigned long timeout; + int status; + + timeout = jiffies + (chip->state == FL_ERASING ? + msecs_to_jiffies(400) : msecs_to_jiffies(20)); + + while (time_before(jiffies, timeout)) + if (chip->dev_ready(mtd)) + break; + + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + status = (int)chip->read_byte(mtd); + + /* Unfortunelly, no way to send detailed error status... */ + if (dev->dma_error) { + status |= NAND_STATUS_FAIL; + dev->dma_error = 0; + } + return status; +} + +/* + * Check if card is ready + */ + +int r852_ready(struct mtd_info *mtd) +{ + struct r852_device *dev = r852_get_dev(mtd); + return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY); +} + + +/* + * Set ECC engine mode +*/ + +void r852_ecc_hwctl(struct mtd_info *mtd, int mode) +{ + struct r852_device *dev = r852_get_dev(mtd); + + if (dev->card_unstable) + return; + + switch (mode) { + case NAND_ECC_READ: + case NAND_ECC_WRITE: + /* enable ecc generation/check*/ + dev->ctlreg |= R852_CTL_ECC_ENABLE; + + /* flush ecc buffer */ + r852_write_reg(dev, R852_CTL, + dev->ctlreg | R852_CTL_ECC_ACCESS); + + r852_read_reg_dword(dev, R852_DATALINE); + r852_write_reg(dev, R852_CTL, dev->ctlreg); + return; + + case NAND_ECC_READSYN: + /* disable ecc generation */ + dev->ctlreg &= ~R852_CTL_ECC_ENABLE; + r852_write_reg(dev, R852_CTL, dev->ctlreg); + } +} + +/* + * Calculate ECC, only used for writes + */ + +int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, + uint8_t *ecc_code) +{ + struct r852_device *dev = r852_get_dev(mtd); + struct sm_oob *oob = (struct sm_oob *)ecc_code; + uint32_t ecc1, ecc2; + + if (dev->card_unstable) + return 0; + + dev->ctlreg &= ~R852_CTL_ECC_ENABLE; + r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS); + + ecc1 = r852_read_reg_dword(dev, R852_DATALINE); + ecc2 = r852_read_reg_dword(dev, R852_DATALINE); + + oob->ecc1[0] = (ecc1) & 0xFF; + oob->ecc1[1] = (ecc1 >> 8) & 0xFF; + oob->ecc1[2] = (ecc1 >> 16) & 0xFF; + + oob->ecc2[0] = (ecc2) & 0xFF; + oob->ecc2[1] = (ecc2 >> 8) & 0xFF; + oob->ecc2[2] = (ecc2 >> 16) & 0xFF; + + r852_write_reg(dev, R852_CTL, dev->ctlreg); + return 0; +} + +/* + * Correct the data using ECC, hw did almost everything for us + */ + +int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + uint16_t ecc_reg; + uint8_t ecc_status, err_byte; + int i, error = 0; + + struct r852_device *dev = r852_get_dev(mtd); + + if (dev->card_unstable) + return 0; + + r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS); + ecc_reg = r852_read_reg_dword(dev, R852_DATALINE); + r852_write_reg(dev, R852_CTL, dev->ctlreg); + + for (i = 0 ; i <= 1 ; i++) { + + ecc_status = (ecc_reg >> 8) & 0xFF; + + /* ecc uncorrectable error */ + if (ecc_status & R852_ECC_FAIL) { + dbg("ecc: unrecoverable error, in half %d", i); + error = -1; + goto exit; + } + + /* correctable error */ + if (ecc_status & R852_ECC_CORRECTABLE) { + + err_byte = ecc_reg & 0xFF; + dbg("ecc: recoverable error, " + "in half %d, byte %d, bit %d", i, + err_byte, ecc_status & R852_ECC_ERR_BIT_MSK); + + dat[err_byte] ^= + 1 << (ecc_status & R852_ECC_ERR_BIT_MSK); + error++; + } + + dat += 256; + ecc_reg >>= 16; + } +exit: + return error; +} + +/* + * This is copy of nand_read_oob_std + * nand_read_oob_syndrome assumes we can send column address - we can't + */ +static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return sndcmd; +} + +/* + * Start the nand engine + */ + +void r852_engine_enable(struct r852_device *dev) +{ + if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) { + r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON); + r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED); + } else { + r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED); + r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON); + } + msleep(300); + r852_write_reg(dev, R852_CTL, 0); +} + + +/* + * Stop the nand engine + */ + +void r852_engine_disable(struct r852_device *dev) +{ + r852_write_reg_dword(dev, R852_HW, 0); + r852_write_reg(dev, R852_CTL, R852_CTL_RESET); +} + +/* + * Test if card is present + */ + +void r852_card_update_present(struct r852_device *dev) +{ + unsigned long flags; + uint8_t reg; + + spin_lock_irqsave(&dev->irqlock, flags); + reg = r852_read_reg(dev, R852_CARD_STA); + dev->card_detected = !!(reg & R852_CARD_STA_PRESENT); + spin_unlock_irqrestore(&dev->irqlock, flags); +} + +/* + * Update card detection IRQ state according to current card state + * which is read in r852_card_update_present + */ +void r852_update_card_detect(struct r852_device *dev) +{ + int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE); + + card_detect_reg &= ~(R852_CARD_IRQ_REMOVE | R852_CARD_IRQ_INSERT); + card_detect_reg |= R852_CARD_IRQ_GENABLE; + + card_detect_reg |= dev->card_detected ? + R852_CARD_IRQ_REMOVE : R852_CARD_IRQ_INSERT; + + r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg); +} + +ssize_t r852_media_type_show(struct device *sys_dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev); + struct r852_device *dev = r852_get_dev(mtd); + char *data = dev->sm ? "smartmedia" : "xd"; + + strcpy(buf, data); + return strlen(data); +} + +DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL); + + +/* Detect properties of card in slot */ +void r852_update_media_status(struct r852_device *dev) +{ + uint8_t reg; + unsigned long flags; + int readonly; + + spin_lock_irqsave(&dev->irqlock, flags); + if (!dev->card_detected) { + message("card removed"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return ; + } + + readonly = r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_RO; + reg = r852_read_reg(dev, R852_DMA_CAP); + dev->sm = (reg & (R852_DMA1 | R852_DMA2)) && (reg & R852_SMBIT); + + message("detected %s %s card in slot", + dev->sm ? "SmartMedia" : "xD", + readonly ? "readonly" : "writeable"); + + dev->readonly = readonly; + spin_unlock_irqrestore(&dev->irqlock, flags); +} + +/* + * Register the nand device + * Called when the card is detected + */ +int r852_register_nand_device(struct r852_device *dev) +{ + dev->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); + + if (!dev->mtd) + goto error1; + + WARN_ON(dev->card_registred); + + dev->mtd->owner = THIS_MODULE; + dev->mtd->priv = dev->chip; + dev->mtd->dev.parent = &dev->pci_dev->dev; + + if (dev->readonly) + dev->chip->options |= NAND_ROM; + + r852_engine_enable(dev); + + if (sm_register_device(dev->mtd)) + goto error2; + + device_create_file(&dev->mtd->dev, &dev_attr_media_type); + dev->card_registred = 1; + return 0; +error2: + kfree(dev->mtd); +error1: + /* Force card redetect */ + dev->card_detected = 0; + return -1; +} + +/* + * Unregister the card + */ + +void r852_unregister_nand_device(struct r852_device *dev) +{ + if (!dev->card_registred) + return; + + device_remove_file(&dev->mtd->dev, &dev_attr_media_type); + nand_release(dev->mtd); + r852_engine_disable(dev); + dev->card_registred = 0; + kfree(dev->mtd); + dev->mtd = NULL; +} + +/* Card state updater */ +void r852_card_detect_work(struct work_struct *work) +{ + struct r852_device *dev = + container_of(work, struct r852_device, card_detect_work.work); + + r852_update_card_detect(dev); + dev->card_unstable = 0; + + /* false alarm */ + if (dev->card_detected == dev->card_registred) + goto exit; + + /* Read media properties */ + r852_update_media_status(dev); + + /* Register the card */ + if (dev->card_detected) + r852_register_nand_device(dev); + else + r852_unregister_nand_device(dev); +exit: + /* Update detection logic */ + r852_update_card_detect(dev); +} + +/* Ack + disable IRQ generation */ +static void r852_disable_irqs(struct r852_device *dev) +{ + uint8_t reg; + reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE); + r852_write_reg(dev, R852_CARD_IRQ_ENABLE, reg & ~R852_CARD_IRQ_MASK); + + reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE); + r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, + reg & ~R852_DMA_IRQ_MASK); + + r852_write_reg(dev, R852_CARD_IRQ_STA, R852_CARD_IRQ_MASK); + r852_write_reg_dword(dev, R852_DMA_IRQ_STA, R852_DMA_IRQ_MASK); +} + +/* Interrupt handler */ +static irqreturn_t r852_irq(int irq, void *data) +{ + struct r852_device *dev = (struct r852_device *)data; + + uint8_t card_status, dma_status; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* We can recieve shared interrupt while pci is suspended + in that case reads will return 0xFFFFFFFF.... */ + if (dev->insuspend) + goto out; + + /* handle card detection interrupts first */ + card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); + r852_write_reg(dev, R852_CARD_IRQ_STA, card_status); + + if (card_status & (R852_CARD_IRQ_INSERT|R852_CARD_IRQ_REMOVE)) { + + ret = IRQ_HANDLED; + dev->card_detected = !!(card_status & R852_CARD_IRQ_INSERT); + + /* we shouldn't recieve any interrupts if we wait for card + to settle */ + WARN_ON(dev->card_unstable); + + /* disable irqs while card is unstable */ + /* this will timeout DMA if active, but better that garbage */ + r852_disable_irqs(dev); + + if (dev->card_unstable) + goto out; + + /* let, card state to settle a bit, and then do the work */ + dev->card_unstable = 1; + queue_delayed_work(dev->card_workqueue, + &dev->card_detect_work, msecs_to_jiffies(100)); + goto out; + } + + + /* Handle dma interrupts */ + dma_status = r852_read_reg_dword(dev, R852_DMA_IRQ_STA); + r852_write_reg_dword(dev, R852_DMA_IRQ_STA, dma_status); + + if (dma_status & R852_DMA_IRQ_MASK) { + + ret = IRQ_HANDLED; + + if (dma_status & R852_DMA_IRQ_ERROR) { + dbg("recieved dma error IRQ"); + r852_dma_done(dev, -EIO); + goto out; + } + + /* recieved DMA interrupt out of nowhere? */ + WARN_ON_ONCE(dev->dma_stage == 0); + + if (dev->dma_stage == 0) + goto out; + + /* done device access */ + if (dev->dma_state == DMA_INTERNAL && + (dma_status & R852_DMA_IRQ_INTERNAL)) { + + dev->dma_state = DMA_MEMORY; + dev->dma_stage++; + } + + /* done memory DMA */ + if (dev->dma_state == DMA_MEMORY && + (dma_status & R852_DMA_IRQ_MEMORY)) { + dev->dma_state = DMA_INTERNAL; + dev->dma_stage++; + } + + /* Enable 2nd half of dma dance */ + if (dev->dma_stage == 2) + r852_dma_enable(dev); + + /* Operation done */ + if (dev->dma_stage == 3) + r852_dma_done(dev, 0); + goto out; + } + + /* Handle unknown interrupts */ + if (dma_status) + dbg("bad dma IRQ status = %x", dma_status); + + if (card_status & ~R852_CARD_STA_CD) + dbg("strange card status = %x", card_status); + +out: + spin_unlock_irqrestore(&dev->irqlock, flags); + return ret; +} + +int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + int error; + struct nand_chip *chip; + struct r852_device *dev; + + /* pci initialization */ + error = pci_enable_device(pci_dev); + + if (error) + goto error1; + + pci_set_master(pci_dev); + + error = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); + if (error) + goto error2; + + error = pci_request_regions(pci_dev, DRV_NAME); + + if (error) + goto error3; + + error = -ENOMEM; + + /* init nand chip, but register it only on card insert */ + chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); + + if (!chip) + goto error4; + + /* commands */ + chip->cmd_ctrl = r852_cmdctl; + chip->waitfunc = r852_wait; + chip->dev_ready = r852_ready; + + /* I/O */ + chip->read_byte = r852_read_byte; + chip->read_buf = r852_read_buf; + chip->write_buf = r852_write_buf; + chip->verify_buf = r852_verify_buf; + + /* ecc */ + chip->ecc.mode = NAND_ECC_HW_SYNDROME; + chip->ecc.size = R852_DMA_LEN; + chip->ecc.bytes = SM_OOB_SIZE; + chip->ecc.hwctl = r852_ecc_hwctl; + chip->ecc.calculate = r852_ecc_calculate; + chip->ecc.correct = r852_ecc_correct; + + /* TODO: hack */ + chip->ecc.read_oob = r852_read_oob; + + /* init our device structure */ + dev = kzalloc(sizeof(struct r852_device), GFP_KERNEL); + + if (!dev) + goto error5; + + chip->priv = dev; + dev->chip = chip; + dev->pci_dev = pci_dev; + pci_set_drvdata(pci_dev, dev); + + dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN, + &dev->phys_bounce_buffer); + + if (!dev->bounce_buffer) + goto error6; + + + error = -ENODEV; + dev->mmio = pci_ioremap_bar(pci_dev, 0); + + if (!dev->mmio) + goto error7; + + error = -ENOMEM; + dev->tmp_buffer = kzalloc(SM_SECTOR_SIZE, GFP_KERNEL); + + if (!dev->tmp_buffer) + goto error8; + + init_completion(&dev->dma_done); + + dev->card_workqueue = create_freezeable_workqueue(DRV_NAME); + + if (!dev->card_workqueue) + goto error9; + + INIT_DELAYED_WORK(&dev->card_detect_work, r852_card_detect_work); + + /* shutdown everything - precation */ + r852_engine_disable(dev); + r852_disable_irqs(dev); + + r852_dma_test(dev); + + /*register irq handler*/ + error = -ENODEV; + if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED, + DRV_NAME, dev)) + goto error10; + + dev->irq = pci_dev->irq; + spin_lock_init(&dev->irqlock); + + /* kick initial present test */ + dev->card_detected = 0; + r852_card_update_present(dev); + queue_delayed_work(dev->card_workqueue, + &dev->card_detect_work, 0); + + + printk(KERN_NOTICE DRV_NAME ": driver loaded succesfully\n"); + return 0; + +error10: + destroy_workqueue(dev->card_workqueue); +error9: + kfree(dev->tmp_buffer); +error8: + pci_iounmap(pci_dev, dev->mmio); +error7: + pci_free_consistent(pci_dev, R852_DMA_LEN, + dev->bounce_buffer, dev->phys_bounce_buffer); +error6: + kfree(dev); +error5: + kfree(chip); +error4: + pci_release_regions(pci_dev); +error3: +error2: + pci_disable_device(pci_dev); +error1: + return error; +} + +void r852_remove(struct pci_dev *pci_dev) +{ + struct r852_device *dev = pci_get_drvdata(pci_dev); + + /* Stop detect workqueue - + we are going to unregister the device anyway*/ + cancel_delayed_work_sync(&dev->card_detect_work); + destroy_workqueue(dev->card_workqueue); + + /* Unregister the device, this might make more IO */ + r852_unregister_nand_device(dev); + + /* Stop interrupts */ + r852_disable_irqs(dev); + synchronize_irq(dev->irq); + free_irq(dev->irq, dev); + + /* Cleanup */ + kfree(dev->tmp_buffer); + pci_iounmap(pci_dev, dev->mmio); + pci_free_consistent(pci_dev, R852_DMA_LEN, + dev->bounce_buffer, dev->phys_bounce_buffer); + + kfree(dev->chip); + kfree(dev); + + /* Shutdown the PCI device */ + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); +} + +void r852_shutdown(struct pci_dev *pci_dev) +{ + struct r852_device *dev = pci_get_drvdata(pci_dev); + + cancel_delayed_work_sync(&dev->card_detect_work); + r852_disable_irqs(dev); + synchronize_irq(dev->irq); + pci_disable_device(pci_dev); +} + +int r852_suspend(struct device *device) +{ + struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); + unsigned long flags; + + if (dev->ctlreg & R852_CTL_CARDENABLE) + return -EBUSY; + + /* First make sure the detect work is gone */ + cancel_delayed_work_sync(&dev->card_detect_work); + + /* Turn off the interrupts and stop the device */ + r852_disable_irqs(dev); + r852_engine_disable(dev); + + spin_lock_irqsave(&dev->irqlock, flags); + dev->insuspend = 1; + spin_unlock_irqrestore(&dev->irqlock, flags); + + /* At that point, even if interrupt handler is running, it will quit */ + /* So wait for this to happen explictly */ + synchronize_irq(dev->irq); + + /* If card was pulled off just during the suspend, which is very + unlikely, we will remove it on resume, it too late now + anyway... */ + dev->card_unstable = 0; + + pci_save_state(to_pci_dev(device)); + return pci_prepare_to_sleep(to_pci_dev(device)); +} + +int r852_resume(struct device *device) +{ + struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); + unsigned long flags; + + /* Turn on the hardware */ + pci_back_from_sleep(to_pci_dev(device)); + pci_restore_state(to_pci_dev(device)); + + r852_disable_irqs(dev); + r852_card_update_present(dev); + r852_engine_disable(dev); + + + /* Now its safe for IRQ to run */ + spin_lock_irqsave(&dev->irqlock, flags); + dev->insuspend = 0; + spin_unlock_irqrestore(&dev->irqlock, flags); + + + /* If card status changed, just do the work */ + if (dev->card_detected != dev->card_registred) { + dbg("card was %s during low power state", + dev->card_detected ? "added" : "removed"); + + queue_delayed_work(dev->card_workqueue, + &dev->card_detect_work, 1000); + return 0; + } + + /* Otherwise, initialize the card */ + if (dev->card_registred) { + r852_engine_enable(dev); + dev->chip->select_chip(dev->mtd, 0); + dev->chip->cmdfunc(dev->mtd, NAND_CMD_RESET, -1, -1); + dev->chip->select_chip(dev->mtd, -1); + } + + /* Program card detection IRQ */ + r852_update_card_detect(dev); + return 0; +} + +static const struct pci_device_id r852_pci_id_tbl[] = { + + { PCI_VDEVICE(RICOH, PCI_DEVICE_ID_RICOH_R5C852), }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); + +SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); + + +static struct pci_driver r852_pci_driver = { + .name = DRV_NAME, + .id_table = r852_pci_id_tbl, + .probe = r852_probe, + .remove = r852_remove, + .shutdown = r852_shutdown, + .driver.pm = &r852_pm_ops, +}; + +static __init int r852_module_init(void) +{ + return pci_register_driver(&r852_pci_driver); +} + +static void __exit r852_module_exit(void) +{ + pci_unregister_driver(&r852_pci_driver); +} + +module_init(r852_module_init); +module_exit(r852_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Maxim Levitsky "); +MODULE_DESCRIPTION("Ricoh 85xx xD/smartmedia card reader driver"); -- cgit v1.2.3-70-g09d2 From 133fa8c7d70d16b07db3a3d87ea18291db8f8ebf Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 26 Feb 2010 22:08:40 +0200 Subject: mtd: Few follow up cleanups for Smartmedia/xD support * Test results of few functions that were declared with __must_check * Fix bogus gcc warning about uinitialized variable 'ret' * Remove unused variable from mtdblock_remove_dev * Don't use deprecated DMA_32BIT_MASK Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/mtd_blkdevs.c | 6 ++++-- drivers/mtd/mtdblock.c | 1 - drivers/mtd/nand/r852.c | 6 ++++-- drivers/mtd/sm_ftl.c | 17 ++++++++++------- 4 files changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 9dd23d6acbb..e32c49cb400 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -380,9 +380,11 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) add_disk(gd); - if (new->disk_attributes) - sysfs_create_group(&disk_to_dev(gd)->kobj, + if (new->disk_attributes) { + ret = sysfs_create_group(&disk_to_dev(gd)->kobj, new->disk_attributes); + WARN_ON(ret); + } return 0; error4: module_put(tr->owner); diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 7ce30a239ad..e6edbec609f 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -354,7 +354,6 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) { - struct mtdblk_dev *mtdblk = container_of(dev, struct mtdblk_dev, mbd); del_mtd_blktrans_dev(dev); } diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 9307a88e522..7a616a926ee 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -654,7 +654,9 @@ int r852_register_nand_device(struct r852_device *dev) if (sm_register_device(dev->mtd)) goto error2; - device_create_file(&dev->mtd->dev, &dev_attr_media_type); + if (device_create_file(&dev->mtd->dev, &dev_attr_media_type)) + message("can't create media type sysfs attribute"); + dev->card_registred = 1; return 0; error2: @@ -838,7 +840,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) pci_set_master(pci_dev); - error = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); + error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); if (error) goto error2; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index a59ebb48cae..9fb56c76ae8 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -228,7 +228,7 @@ static int sm_read_sector(struct sm_ftl *ftl, struct mtd_info *mtd = ftl->trans->mtd; struct mtd_oob_ops ops; struct sm_oob tmp_oob; - int ret; + int ret = -EIO; int try = 0; /* FTL can contain -1 entries that are by default filled with bits */ @@ -753,6 +753,7 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) uint16_t block; int lba; int i = 0; + int len; dbg("initializing zone %d", zone_num); @@ -856,7 +857,9 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) i %= (kfifo_len(&zone->free_sectors) / 2); while (i--) { - kfifo_out(&zone->free_sectors, (unsigned char *)&block, 2); + len = kfifo_out(&zone->free_sectors, + (unsigned char *)&block, 2); + WARN_ON(len != 2); kfifo_in(&zone->free_sectors, (const unsigned char *)&block, 2); } return 0; @@ -947,17 +950,17 @@ restart: if (ftl->unstable) return -EIO; - /* No spare blocks */ - /* We could still continue by erasing the current block, + + /* If there are no spare blocks, */ + /* we could still continue by erasing/writing the current block, but for such worn out media it doesn't worth the trouble, and the dangers */ - - if (!kfifo_len(&zone->free_sectors)) { + if (kfifo_out(&zone->free_sectors, + (unsigned char *)&write_sector, 2) != 2) { dbg("no free sectors for write!"); return -EIO; } - kfifo_out(&zone->free_sectors, (unsigned char *)&write_sector, 2); if (sm_write_block(ftl, ftl->cache_data, zone_num, write_sector, ftl->cache_block, ftl->cache_data_invalid_bitmap)) -- cgit v1.2.3-70-g09d2 From d4080cb32ee3d2ed18aa69ffde6010524bd686cd Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 26 Feb 2010 23:10:32 +0200 Subject: mtd: r852 fix pci ID The PCI_DEVICE_ID_RICOH_R5C852 was missed in the edited commit, and on second thought I just open code it. This fixes compile error. Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 7a616a926ee..218a42dadff 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -1083,7 +1083,7 @@ int r852_resume(struct device *device) static const struct pci_device_id r852_pci_id_tbl[] = { - { PCI_VDEVICE(RICOH, PCI_DEVICE_ID_RICOH_R5C852), }, + { PCI_VDEVICE(RICOH, 0x0852), }, { }, }; -- cgit v1.2.3-70-g09d2 From fb45d3232c641bfee5000c8a81e2005903734702 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sat, 27 Feb 2010 02:04:02 +0200 Subject: mtd: r852: Few fixes for problems that occur when card is rapidly inserted/removed. First don't enable card detection logic to early. Second be very careful with DMA engine, to be sure it doesn't write to kernel memory driver doesn't own. Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 218a42dadff..cb271167b4a 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -96,14 +96,21 @@ static void r852_dma_enable(struct r852_device *dev) if (dev->dma_dir) dma_reg |= R852_DMA_READ; - if (dev->dma_state == DMA_INTERNAL) + if (dev->dma_state == DMA_INTERNAL) { dma_reg |= R852_DMA_INTERNAL; - else { + /* Precaution to make sure HW doesn't write */ + /* to random kernel memory */ + r852_write_reg_dword(dev, R852_DMA_ADDR, + cpu_to_le32(dev->phys_bounce_buffer)); + } else { dma_reg |= R852_DMA_MEMORY; r852_write_reg_dword(dev, R852_DMA_ADDR, cpu_to_le32(dev->phys_dma_addr)); } + /* Precaution: make sure write reached the device */ + r852_read_reg_dword(dev, R852_DMA_ADDR); + r852_write_reg_dword(dev, R852_DMA_SETTINGS, dma_reg); /* Set dma irq */ @@ -129,6 +136,11 @@ static void r852_dma_done(struct r852_device *dev, int error) r852_write_reg_dword(dev, R852_DMA_SETTINGS, 0); r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, 0); + /* Precaution to make sure HW doesn't write to random kernel memory */ + r852_write_reg_dword(dev, R852_DMA_ADDR, + cpu_to_le32(dev->phys_bounce_buffer)); + r852_read_reg_dword(dev, R852_DMA_ADDR); + dev->dma_error = error; dev->dma_stage = 0; @@ -579,6 +591,7 @@ void r852_card_update_present(struct r852_device *dev) void r852_update_card_detect(struct r852_device *dev) { int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE); + dev->card_unstable = 0; card_detect_reg &= ~(R852_CARD_IRQ_REMOVE | R852_CARD_IRQ_INSERT); card_detect_reg |= R852_CARD_IRQ_GENABLE; @@ -690,10 +703,10 @@ void r852_card_detect_work(struct work_struct *work) struct r852_device *dev = container_of(work, struct r852_device, card_detect_work.work); - r852_update_card_detect(dev); + r852_card_update_present(dev); dev->card_unstable = 0; - /* false alarm */ + /* False alarm */ if (dev->card_detected == dev->card_registred) goto exit; -- cgit v1.2.3-70-g09d2 From b2aaf7a2b476820cf5fd7738e8641ed88046acf5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 1 Mar 2010 13:54:19 -0800 Subject: mtd/nand/r852: fix build for CONFIG_PM=n Fix r852 build for the case of CONFIG_PM=n. drivers/mtd/nand/r852.c:1039: error: implicit declaration of function 'pci_prepare_to_sleep' drivers/mtd/nand/r852.c:1048: error: implicit declaration of function 'pci_back_from_sleep' This patch leaves r852_pm_ops untouched. Signed-off-by: Randy Dunlap Acked-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cb271167b4a..96db476ce3e 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -1019,6 +1019,7 @@ void r852_shutdown(struct pci_dev *pci_dev) pci_disable_device(pci_dev); } +#ifdef CONFIG_PM int r852_suspend(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1093,6 +1094,10 @@ int r852_resume(struct device *device) r852_update_card_detect(dev); return 0; } +#else +#define r852_suspend NULL +#define r852_resume NULL +#endif static const struct pci_device_id r852_pci_id_tbl[] = { -- cgit v1.2.3-70-g09d2 From ada496578850cb063ccf64d43a293cfcc9d32bf8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 1 Mar 2010 20:21:06 +1100 Subject: mtd: nand: r852: fix name space clash and include delay.h for msleep(). Signed-off-by: Stephen Rothwell Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 96db476ce3e..f5a0bc7adde 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -13,15 +13,16 @@ #include #include #include +#include #include #include #include "sm_common.h" #include "r852.h" -static int enable_dma = 1; -module_param(enable_dma, bool, S_IRUGO); -MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); +static int r852_enable_dma = 1; +module_param(r852_enable_dma, bool, S_IRUGO); +MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)"); static int debug; module_param(debug, int, S_IRUGO | S_IWUSR); @@ -75,7 +76,7 @@ static void r852_dma_test(struct r852_device *dev) if (!dev->dma_usable) message("Non dma capable device detected, dma disabled"); - if (!enable_dma) { + if (!r852_enable_dma) { message("disabling dma on user request"); dev->dma_usable = 0; } -- cgit v1.2.3-70-g09d2 From f696aa43fadb13a21c4e723fb6e51bf640dd1363 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 11 Mar 2010 09:10:32 -0800 Subject: mtd/nand/r852: fix build for CONFIG_PCI disabled r852 fails to build when CONFIG_PCI is not enabled since it uses pci_*() calls and is a PCI driver, so it should depend on PCI to prevent build errors. It should also #include . drivers/mtd/nand/r852.c:1053: error: implicit declaration of function 'pci_prepare_to_sleep' drivers/mtd/nand/r852.c:1062: error: implicit declaration of function 'pci_back_from_sleep' Signed-off-by: Randy Dunlap Cc: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 1 + drivers/mtd/nand/r852.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 6701a00b7a9..226206e0623 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -105,6 +105,7 @@ config MTD_NAND_IDS config MTD_NAND_RICOH tristate "Ricoh xD card reader" default n + depends on PCI select MTD_SM_COMMON help Enable support for Ricoh R5C852 xD card reader diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index f5a0bc7adde..06f07bb414a 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 0c82d3ce2f479c728f99e228d9ae32a9cd853c5a Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 11 Mar 2010 09:25:14 -0800 Subject: mtd/nand/r852: Use pci_dma_mapping_error() ... instead of comparing with DMA_ERROR_CODE, which will only work on powerpc/sparc/x86. Reported-by: Geert Uytterhoeven Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 06f07bb414a..96bfbd8e8fd 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -197,7 +197,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) R852_DMA_LEN, (do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); - if (dev->phys_dma_addr == DMA_ERROR_CODE) + if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr)) bounce = 1; } -- cgit v1.2.3-70-g09d2 From c3611570ddf601609f8803574ea83889ff969aa0 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 19 Apr 2010 18:20:41 +0300 Subject: mtd: sm_common: split smartmedia and xD table 2GB xD card, and 4MB SmartMedia ROM card share same ID, so to make both work split xD and smartmedia ID tables. Hardware driver must be able to know which type it handles (and probably just one). Signed-off-by: Maxim Levitsky Signed-off-by: David Woodhouse --- drivers/mtd/nand/r852.c | 2 +- drivers/mtd/nand/sm_common.c | 37 +++++++++++++++++++++---------------- drivers/mtd/nand/sm_common.h | 2 +- 3 files changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 96bfbd8e8fd..6dfbb471316 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -666,7 +666,7 @@ int r852_register_nand_device(struct r852_device *dev) r852_engine_enable(dev); - if (sm_register_device(dev->mtd)) + if (sm_register_device(dev->mtd, dev->sm)) goto error2; if (device_create_file(&dev->mtd->dev, &dev_attr_media_type)) diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index aae0b9acd7a..ac80fb362e6 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -68,8 +68,6 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) static struct nand_flash_dev nand_smartmedia_flash_ids[] = { - - /* SmartMedia */ {"SmartMedia 1MiB 5V", 0x6e, 256, 1, 0x1000, 0}, {"SmartMedia 1MiB 3,3V", 0xe8, 256, 1, 0x1000, 0}, {"SmartMedia 1MiB 3,3V", 0xec, 256, 1, 0x1000, 0}, @@ -82,28 +80,34 @@ static struct nand_flash_dev nand_smartmedia_flash_ids[] = { {"SmartMedia 4MiB 3,3V ROM", 0xd5, 512, 4, 0x2000, NAND_ROM}, {"SmartMedia 8MiB 3,3V", 0xe6, 512, 8, 0x2000, 0}, {"SmartMedia 8MiB 3,3V ROM", 0xd6, 512, 8, 0x2000, NAND_ROM}, - -#define XD_TYPEM (NAND_NO_AUTOINCR | NAND_BROKEN_XD) - /* xD / SmartMedia */ - {"SmartMedia/xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, + {"SmartMedia 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, {"SmartMedia 16MiB 3,3V ROM", 0x57, 512, 16, 0x4000, NAND_ROM}, - {"SmartMedia/xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, + {"SmartMedia 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, {"SmartMedia 32MiB 3,3V ROM", 0x58, 512, 32, 0x4000, NAND_ROM}, - {"SmartMedia/xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, + {"SmartMedia 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, {"SmartMedia 64MiB 3,3V ROM", 0xd9, 512, 64, 0x4000, NAND_ROM}, - {"SmartMedia/xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, + {"SmartMedia 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, {"SmartMedia 128MiB 3,3V ROM", 0xda, 512, 128, 0x4000, NAND_ROM}, - {"SmartMedia/xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, XD_TYPEM}, + {"SmartMedia 256MiB 3,3V", 0x71, 512, 256, 0x4000 }, {"SmartMedia 256MiB 3,3V ROM", 0x5b, 512, 256, 0x4000, NAND_ROM}, + {NULL,} +}; - /* xD only */ - {"xD 512MiB 3,3V", 0xDC, 512, 512, 0x4000, XD_TYPEM}, - {"xD 1GiB 3,3V", 0xD3, 512, 1024, 0x4000, XD_TYPEM}, - {"xD 2GiB 3,3V", 0xD5, 512, 2048, 0x4000, XD_TYPEM}, +#define XD_TYPEM (NAND_NO_AUTOINCR | NAND_BROKEN_XD) +static struct nand_flash_dev nand_xd_flash_ids[] = { + + {"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, + {"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, + {"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, + {"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, + {"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, XD_TYPEM}, + {"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, XD_TYPEM}, + {"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, XD_TYPEM}, + {"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, XD_TYPEM}, {NULL,} }; -int sm_register_device(struct mtd_info *mtd) +int sm_register_device(struct mtd_info *mtd, int smartmedia) { struct nand_chip *chip = (struct nand_chip *)mtd->priv; int ret; @@ -111,7 +115,8 @@ int sm_register_device(struct mtd_info *mtd) chip->options |= NAND_SKIP_BBTSCAN; /* Scan for card properties */ - ret = nand_scan_ident(mtd, 1, nand_smartmedia_flash_ids); + ret = nand_scan_ident(mtd, 1, smartmedia ? + nand_smartmedia_flash_ids : nand_xd_flash_ids); if (ret) return ret; diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/sm_common.h index 18284f5fae6..00f4a83359b 100644 --- a/drivers/mtd/nand/sm_common.h +++ b/drivers/mtd/nand/sm_common.h @@ -36,7 +36,7 @@ struct sm_oob { #define SM_SMALL_OOB_SIZE 8 -extern int sm_register_device(struct mtd_info *mtd); +extern int sm_register_device(struct mtd_info *mtd, int smartmedia); static inline int sm_sector_valid(struct sm_oob *oob) -- cgit v1.2.3-70-g09d2 From 05d71b4625bdadd7c7ae80455e7038e221c76e4d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 30 Mar 2010 02:52:39 +0900 Subject: mtd: update gfp/slab.h includes Implicit slab.h inclusion via percpu.h is about to go away. Make sure gfp.h or slab.h is included as necessary. Signed-off-by: Tejun Heo Signed-off-by: David Woodhouse --- drivers/mtd/mtdcore.c | 1 + drivers/mtd/nand/mpc5121_nfc.c | 1 + drivers/mtd/nand/r852.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers/mtd/nand/r852.c') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 3ae06c8935b..a1b8b70d2d0 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -21,6 +21,7 @@ #include #include #include +#include #include diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index f713b15fa45..3d0867d829c 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 6dfbb471316..78a42329547 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "sm_common.h" -- cgit v1.2.3-70-g09d2