/* *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. *This interrupt is normally disabled, but for long operations like *erase and write, we enable it to wake us up. The irq handler *disables the interrupt. */ static int tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) { struct tmio_nand *tmio = mtd_to_tmio(mtd); long timeout; /* enable RDYREQ interrupt */ tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); timeout = wait_event_timeout(nand_chip->controller->wq, tmio_nand_dev_ready(mtd), msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); if (unlikely(!tmio_nand_dev_ready(mtd))) { tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", nand_chip->state == FL_ERASING ? "erase" : "program", nand_chip->state == FL_ERASING ? 400 : 20); } else if (unlikely(!timeout)) { tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n"); } nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); return nand_chip->read_byte(mtd); }
static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct tmio_nand *tmio = mtd_to_tmio(mtd); struct nand_chip *chip = mtd->priv; if (ctrl & NAND_CTRL_CHANGE) { u8 mode; if (ctrl & NAND_NCE) { mode = FCR_MODE_DATA; if (ctrl & NAND_CLE) mode |= FCR_MODE_CLE; else mode &= ~FCR_MODE_CLE; if (ctrl & NAND_ALE) mode |= FCR_MODE_ALE; else mode &= ~FCR_MODE_ALE; } else { mode = FCR_MODE_STANDBY; } tmio_iowrite8(mode, tmio->fcr + FCR_MODE); tmio->read_good = 0; } if (cmd != NAND_CMD_NONE) tmio_iowrite8(cmd, chip->IO_ADDR_W); }
static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode) { struct tmio_nand *tmio = mtd_to_tmio(mtd); tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE); tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */ tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE); }
static void tmio_start_hc(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct tmio_hcd *tmio = hcd_to_tmio(hcd); unsigned long base = hcd->rsrc_start; tmio_write_pm(dev); tmio_iowrite16(base, tmio->ccr + CCR_BASE); tmio_iowrite16(base >> 16, tmio->ccr + CCR_BASE + 2); tmio_iowrite8(1, tmio->ccr + CCR_ILME); tmio_iowrite8(2, tmio->ccr + CCR_INTC); dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", tmio_ioread8(tmio->ccr + CCR_REVID), hcd->rsrc_start, hcd->irq); }
static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state) { const struct mfd_cell *cell = mfd_get_cell(dev); struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); unsigned long flags; u8 misc; int ret; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; spin_lock_irqsave(&tmio->lock, flags); misc = tmio_ioread8(tmio->ccr + CCR_MISC); misc |= 1 << 3; /* USSUSP */ tmio_iowrite8(misc, tmio->ccr + CCR_MISC); spin_unlock_irqrestore(&tmio->lock, flags); if (cell->suspend) { ret = cell->suspend(dev); if (ret) return ret; } return 0; }
static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) { const struct mfd_cell *cell = mfd_get_cell(dev); struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); unsigned long flags; u8 misc; int ret; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; if (cell->resume) { ret = cell->resume(dev); if (ret) return ret; } tmio_start_hc(dev); spin_lock_irqsave(&tmio->lock, flags); misc = tmio_ioread8(tmio->ccr + CCR_MISC); misc &= ~(1 << 3); /* USSUSP */ tmio_iowrite8(misc, tmio->ccr + CCR_MISC); spin_unlock_irqrestore(&tmio->lock, flags); ohci_finish_controller_resume(hcd); return 0; }
static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) { struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); if (cell->disable) cell->disable(dev); }
static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) { const struct mfd_cell *cell = mfd_get_cell(dev); tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); if (cell->disable) cell->disable(dev); }
static void t7l66xb_irq_unmask(unsigned int irq) { struct t7l66xb *t7l66xb = get_irq_chip_data(irq); unsigned long flags; u8 imr; spin_lock_irqsave(&t7l66xb->lock, flags); imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); imr &= ~(1 << (irq - t7l66xb->irq_base)); tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); spin_unlock_irqrestore(&t7l66xb->lock, flags); }
static void tc6393xb_irq_unmask(struct irq_data *data) { struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); unsigned long flags; u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); imr &= ~(1 << (data->irq - tc6393xb->irq_base)); tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); }
static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { struct tmio_nand *tmio = mtd_to_tmio(mtd); unsigned int ecc; tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE); ecc = tmio_ioread16(tmio->fcr + FCR_DATA); ecc_code[1] = ecc; /* 000-255 LP7-0 */ ecc_code[0] = ecc >> 8; /* 000-255 LP15-8 */ ecc = tmio_ioread16(tmio->fcr + FCR_DATA); ecc_code[2] = ecc; /* 000-255 CP5-0,11b */ ecc_code[4] = ecc >> 8; /* 256-511 LP7-0 */ ecc = tmio_ioread16(tmio->fcr + FCR_DATA); ecc_code[3] = ecc; /* 256-511 LP15-8 */ ecc_code[5] = ecc >> 8; /* 256-511 CP5-0,11b */ tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE); return 0; }
static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) { struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; int ret; if (cell->enable) { ret = cell->enable(dev); if (ret) return ret; } tmio_iowrite8(0x81, tmio->ccr + CCR_ICC); tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE); tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2); tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND); tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC); tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC); tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE); tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE); tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA); tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE); mdelay(5); return 0; }
static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) { const struct mfd_cell *cell = mfd_get_cell(dev); int ret; if (cell->enable) { ret = cell->enable(dev); if (ret) return ret; } /* (4Ch) CLKRUN Enable 1st spcrunc */ tmio_iowrite8(0x81, tmio->ccr + CCR_ICC); /* (10h)BaseAddress 0x1000 spba.spba2 */ tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE); tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2); /* (04h)Command Register I/O spcmd */ tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND); /* (62h) Power Supply Control ssmpwc */ /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC); /* (63h) Detect Control ssmdtc */ tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC); /* Interrupt status register clear sintst */ tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); /* After power supply, Media are reset smode */ tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE); tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE); tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA); /* Standby Mode smode */ tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE); mdelay(5); return 0; }
static irqreturn_t tmio_irq(int irq, void *__tmio) { struct tmio_nand *tmio = __tmio; struct nand_chip *nand_chip = &tmio->chip; /* disable RDYREQ interrupt */ tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); if (unlikely(!waitqueue_active(&nand_chip->controller->wq))) dev_warn(&tmio->dev->dev, "spurious interrupt\n"); wake_up(&nand_chip->controller->wq); return IRQ_HANDLED; }
static void __tc6393xb_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); u8 dsr; dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); if (value) dsr |= TC_GPIO_BIT(offset); else dsr &= ~TC_GPIO_BIT(offset); tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); }
static void tmio_stop_hc(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); u16 pm; pm = CCR_PM_GKEN | CCR_PM_CKRNEN; switch (ohci->num_ports) { default: dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports); case 3: pm |= CCR_PM_USBPW3; case 2: pm |= CCR_PM_USBPW2; case 1: pm |= CCR_PM_USBPW1; } tmio_iowrite8(0, tmio->ccr + CCR_INTC); tmio_iowrite8(0, tmio->ccr + CCR_ILME); tmio_iowrite16(0, tmio->ccr + CCR_BASE); tmio_iowrite16(0, tmio->ccr + CCR_BASE + 2); tmio_iowrite16(pm, tmio->ccr + CCR_PM); }
static int tc6393xb_nand_enable(struct platform_device *nand) { struct platform_device *dev = to_platform_device(nand->dev.parent); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&tc6393xb->lock, flags); /* SMD buffer on */ dev_dbg(&dev->dev, "SMD buffer on\n"); tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); spin_unlock_irqrestore(&tc6393xb->lock, flags); return 0; }
static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); unsigned long flags; u8 doecr; spin_lock_irqsave(&tc6393xb->lock, flags); doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); doecr &= ~TC_GPIO_BIT(offset); tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); spin_unlock_irqrestore(&tc6393xb->lock, flags); return 0; }
static int t7l66xb_mmc_disable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); struct t7l66xb *t7l66xb = platform_get_drvdata(dev); unsigned long flags; u8 dev_ctl; spin_lock_irqsave(&t7l66xb->lock, flags); dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); dev_ctl &= ~SCR_DEV_CTL_MMC; tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); spin_unlock_irqrestore(&t7l66xb->lock, flags); clk_disable(t7l66xb->clk32k); return 0; }
static int tc6393xb_ohci_disable(struct platform_device *dev) { struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); unsigned long flags; u16 ccr; u8 fer; spin_lock_irqsave(&tc6393xb->lock, flags); fer = tmio_ioread8(tc6393xb->scr + SCR_FER); fer &= ~SCR_FER_USBEN; tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); ccr &= ~SCR_CCR_USBCK; tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); spin_unlock_irqrestore(&tc6393xb->lock, flags); return 0; }
static int t7l66xb_mmc_enable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); struct t7l66xb *t7l66xb = platform_get_drvdata(dev); unsigned long flags; u8 dev_ctl; clk_enable(t7l66xb->clk32k); spin_lock_irqsave(&t7l66xb->lock, flags); dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); dev_ctl |= SCR_DEV_CTL_MMC; tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); spin_unlock_irqrestore(&t7l66xb->lock, flags); tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, t7l66xb_mmc_resources[0].start & 0xfffe); return 0; }
static int t7l66xb_probe(struct platform_device *dev) { struct t7l66xb_platform_data *pdata = dev->dev.platform_data; struct t7l66xb *t7l66xb; struct resource *iomem, *rscr; int ret; iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!iomem) return -EINVAL; t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); if (!t7l66xb) return -ENOMEM; spin_lock_init(&t7l66xb->lock); platform_set_drvdata(dev, t7l66xb); ret = platform_get_irq(dev, 0); if (ret >= 0) t7l66xb->irq = ret; else goto err_noirq; t7l66xb->irq_base = pdata->irq_base; t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K"); if (IS_ERR(t7l66xb->clk32k)) { ret = PTR_ERR(t7l66xb->clk32k); goto err_clk32k_get; } t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M"); if (IS_ERR(t7l66xb->clk48m)) { ret = PTR_ERR(t7l66xb->clk48m); clk_put(t7l66xb->clk32k); goto err_clk48m_get; } rscr = &t7l66xb->rscr; rscr->name = "t7l66xb-core"; rscr->start = iomem->start; rscr->end = iomem->start + 0xff; rscr->flags = IORESOURCE_MEM; ret = request_resource(iomem, rscr); if (ret) goto err_request_scr; t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); if (!t7l66xb->scr) { ret = -ENOMEM; goto err_ioremap; } clk_enable(t7l66xb->clk48m); if (pdata && pdata->enable) pdata->enable(dev); /* Mask all interrupts */ tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), (unsigned long)iomem->start, t7l66xb->irq); t7l66xb_attach_irq(dev); t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = &t7l66xb_cells[T7L66XB_CELL_NAND]; t7l66xb_cells[T7L66XB_CELL_NAND].data_size = sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = &t7l66xb_cells[T7L66XB_CELL_MMC]; t7l66xb_cells[T7L66XB_CELL_MMC].data_size = sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); ret = mfd_add_devices(&dev->dev, dev->id, t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), iomem, t7l66xb->irq_base); if (!ret) return 0; t7l66xb_detach_irq(dev); iounmap(t7l66xb->scr); err_ioremap: release_resource(&t7l66xb->rscr); err_request_scr: kfree(t7l66xb); clk_put(t7l66xb->clk48m); err_clk48m_get: clk_put(t7l66xb->clk32k); err_clk32k_get: err_noirq: return ret; }