return IRQ_HANDLED;
}
-static int bf5xx_nand_dma_rw(struct mtd_info *mtd,
+static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
uint8_t *buf, int is_read)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
/* setup DMA register with Blackfin DMA API */
set_dma_config(CH_NFC, 0x0);
set_dma_start_addr(CH_NFC, (unsigned long) buf);
+
+/* The DMAs have different size on BF52x and BF54x */
+#ifdef CONFIG_BF52x
+ set_dma_x_count(CH_NFC, (page_size >> 1));
+ set_dma_x_modify(CH_NFC, 2);
+ val = DI_EN | WDSIZE_16;
+#endif
+
+#ifdef CONFIG_BF54x
set_dma_x_count(CH_NFC, (page_size >> 2));
set_dma_x_modify(CH_NFC, 4);
-
- /* setup write or read operation */
val = DI_EN | WDSIZE_32;
+#endif
+ /* setup write or read operation */
if (is_read)
val |= WNR;
set_dma_config(CH_NFC, val);
else
bfin_write_NFC_PGCTL(0x2);
wait_for_completion(&info->dma_completion);
-
- return 0;
}
static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
/*
* System initialization functions
*/
-
static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
{
int ret;
- unsigned short val;
/* Do not use dma */
if (!hardware_ecc)
init_completion(&info->dma_completion);
-#ifdef CONFIG_BF54x
- /* Setup DMAC1 channel mux for NFC which shared with SDH */
- val = bfin_read_DMAC1_PERIMUX();
- val &= 0xFFFE;
- bfin_write_DMAC1_PERIMUX(val);
- SSYNC();
-#endif
/* Request NFC DMA channel */
ret = request_dma(CH_NFC, "BF5XX NFC driver");
if (ret < 0) {
return ret;
}
- set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info);
+#ifdef CONFIG_BF54x
+ /* Setup DMAC1 channel mux for NFC which shared with SDH */
+ bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
+ SSYNC();
+#endif
+
+ set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
/* Turn off the DMA channel first */
disable_dma(CH_NFC);
return 0;
}
+static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
+{
+ /* Free NFC DMA channel */
+ if (hardware_ecc)
+ free_dma(CH_NFC);
+}
+
/*
* BF5XX NFC hardware initialization
* - pin mux setup
/*
* Device management interface
*/
-static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
{
struct mtd_info *mtd = &info->mtd;
}
peripheral_free_list(bfin_nfc_pin_req);
+ bf5xx_nand_dma_remove(info);
/* free the common resources */
kfree(info);
dev_dbg(&pdev->dev, "(%p)\n", pdev);
- if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
- return -EFAULT;
- }
-
if (!plat) {
dev_err(&pdev->dev, "no platform specific information\n");
- goto exit_error;
+ return -EINVAL;
+ }
+
+ if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+ dev_err(&pdev->dev, "requesting Peripherals failed\n");
+ return -EFAULT;
}
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info\n");
err = -ENOMEM;
- goto exit_error;
+ goto out_err_kzalloc;
}
platform_set_drvdata(pdev, info);
/* initialise the hardware */
err = bf5xx_nand_hw_init(info);
- if (err != 0)
- goto exit_error;
+ if (err)
+ goto out_err_hw_init;
/* setup hardware ECC data struct */
if (hardware_ecc) {
/* scan hardware nand chip and setup mtd info data struct */
if (nand_scan(mtd, 1)) {
err = -ENXIO;
- goto exit_error;
+ goto out_err_nand_scan;
}
/* add NAND partition */
dev_dbg(&pdev->dev, "initialised ok\n");
return 0;
-exit_error:
- bf5xx_nand_remove(pdev);
+out_err_nand_scan:
+ bf5xx_nand_dma_remove(info);
+out_err_hw_init:
+ platform_set_drvdata(pdev, NULL);
+ kfree(info);
+out_err_kzalloc:
+ peripheral_free_list(bfin_nfc_pin_req);
- if (err == 0)
- err = -EINVAL;
return err;
}