|

楼主 |
发表于 2014-2-19 19:17:44
|
显示全部楼层
- static int sunxi_nand_chip_ecc_init(struct device *dev,
- struct sunxi_nand_chip *chip,
- struct mtd_info *mtd,
- struct device_node *np)
- {
- struct nand_chip *nand = &chip->nand;
- u32 strength;
- u32 blk_size;
- int ret;
- nand->ecc.mode = of_get_nand_ecc_mode(np);
- if (!of_get_nand_ecc_level(np, &strength, &blk_size)) {
- nand->ecc_step_ds = blk_size;
- nand->ecc_strength_ds = strength;
- }
- switch (nand->ecc.mode) {
- case NAND_ECC_SOFT_BCH:
- nand->ecc.size = nand->ecc_step_ds;
- nand->ecc.bytes = ((nand->ecc_strength_ds *
- fls(8 * nand->ecc_step_ds)) + 7) / 8;
- break;
- case NAND_ECC_HW:
- ret = sunxi_nand_chip_hwecc_init(dev, chip, mtd, np);
- if (ret)
- return ret;
- break;
- case NAND_ECC_NONE:
- default:
- break;
- }
- return 0;
- }
- static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
- struct device_node *np)
- {
- const struct nand_sdr_timings *timings;
- struct sunxi_nand_chip *chip;
- struct mtd_part_parser_data ppdata;
- struct mtd_info *mtd;
- struct nand_chip *nand;
- int nsels;
- int ret;
- int i;
- u32 tmp;
- if (!of_get_property(np, "reg", &nsels))
- return -EINVAL;
- nsels /= sizeof(u32);
- if (!nsels)
- return -EINVAL;
- chip = devm_kzalloc(dev,
- sizeof(*chip) +
- (nsels * sizeof(struct sunxi_nand_chip_sel)),
- GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
- chip->nsels = nsels;
- chip->selected = -1;
- for (i = 0; i < nsels; i++) {
- ret = of_property_read_u32_index(np, "reg", i, &tmp);
- if (ret)
- return ret;
- if (tmp > 7)
- return -EINVAL;
- if (test_and_set_bit(tmp, &nfc->assigned_cs))
- return -EINVAL;
- chip->sels[i].cs = tmp;
- if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
- tmp < 2) {
- chip->sels[i].rb.type = RB_NATIVE;
- chip->sels[i].rb.info.nativeid = tmp;
- } else {
- ret = of_get_named_gpio(np, "rb-gpios", i);
- if (ret >= 0) {
- tmp = ret;
- chip->sels[i].rb.type = RB_GPIO;
- chip->sels[i].rb.info.gpio = tmp;
- ret = devm_gpio_request(dev, tmp, "nand-rb");
- if (ret)
- return ret;
- ret = gpio_direction_input(tmp);
- if (ret)
- return ret;
- } else {
- chip->sels[i].rb.type = RB_NONE;
- }
- }
- }
- timings = onfi_async_timing_mode_to_sdr_timings(0);
- if (IS_ERR(timings))
- return PTR_ERR(timings);
- ret = sunxi_nand_chip_set_timings(chip, timings);
- nand = &chip->nand;
- nand->controller = &nfc->controller;
- nand->select_chip = sunxi_nfc_select_chip;
- nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
- nand->read_buf = sunxi_nfc_read_buf;
- nand->write_buf = sunxi_nfc_write_buf;
- nand->read_byte = sunxi_nfc_read_byte;
- if (of_get_nand_on_flash_bbt(np))
- nand->bbt_options |= NAND_BBT_USE_FLASH;
- mtd = &chip->mtd;
- mtd->priv = nand;
- mtd->owner = THIS_MODULE;
- ret = nand_scan_ident(mtd, nsels, NULL);
- if (ret)
- return ret;
- ret = sunxi_nand_chip_init_timings(chip, np);
- if (ret)
- return ret;
- ret = sunxi_nand_chip_ecc_init(dev, chip, mtd, np);
- if (ret)
- return ret;
- ret = nand_scan_tail(mtd);
- if (ret)
- return ret;
- if (of_property_read_string(np, "nand-name", &mtd->name)) {
- snprintf(chip->default_name, MAX_NAME_SIZE,
- DEFAULT_NAME_FORMAT, chip->sels[i].cs);
- mtd->name = chip->default_name;
- }
- ppdata.of_node = np;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
- if (!ret)
- return ret;
- list_add_tail(&chip->node, &nfc->chips);
- return 0;
- }
- static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
- {
- struct device_node *np = dev->of_node;
- struct device_node *nand_np;
- int nchips = of_get_child_count(np);
- int ret;
- if (nchips > 8)
- return -EINVAL;
- for_each_child_of_node(np, nand_np) {
- ret = sunxi_nand_chip_init(dev, nfc, nand_np);
- if (ret)
- return ret;
- }
- return 0;
- }
- static int sunxi_nfc_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct resource *r;
- struct sunxi_nfc *nfc;
- int ret;
- nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
- if (!nfc) {
- dev_err(dev, "failed to allocate NFC struct\n");
- return -ENOMEM;
- }
- spin_lock_init(&nfc->controller.lock);
- init_waitqueue_head(&nfc->controller.wq);
- INIT_LIST_HEAD(&nfc->chips);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nfc->regs = devm_ioremap_resource(dev, r);
- if (IS_ERR(nfc->regs)) {
- dev_err(dev, "failed to remap iomem\n");
- return PTR_ERR(nfc->regs);
- }
- nfc->irq = platform_get_irq(pdev, 0);
- if (nfc->irq < 0) {
- dev_err(dev, "failed to retrieve irq\n");
- return nfc->irq;
- }
- nfc->ahb_clk = devm_clk_get(dev, "ahb_clk");
- if (IS_ERR(nfc->ahb_clk)) {
- dev_err(dev, "failed to retrieve ahb_clk\n");
- return PTR_ERR(nfc->ahb_clk);
- }
- ret = clk_prepare_enable(nfc->ahb_clk);
- if (ret)
- return ret;
- nfc->sclk = devm_clk_get(dev, "sclk");
- if (IS_ERR(nfc->sclk)) {
- dev_err(dev, "failed to retrieve nand_clk\n");
- ret = PTR_ERR(nfc->sclk);
- goto out_ahb_clk_unprepare;
- }
- ret = clk_prepare_enable(nfc->sclk);
- if (ret)
- goto out_ahb_clk_unprepare;
- /* Reset NFC */
- writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RESET,
- nfc->regs + NFC_REG_CTL);
- while (readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)
- ;
- writel(0, nfc->regs + NFC_REG_INT);
- ret = devm_request_irq(dev, nfc->irq, sunxi_nfc_interrupt,
- 0, "sunxi-nand", nfc);
- if (ret)
- goto out_sclk_unprepare;
- platform_set_drvdata(pdev, nfc);
- writel(0x100, nfc->regs + NFC_REG_TIMING_CTL);
- writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG);
- ret = sunxi_nand_chips_init(dev, nfc);
- if (ret) {
- dev_err(dev, "failed to init nand chips\n");
- goto out_sclk_unprepare;
- }
- return 0;
- out_sclk_unprepare:
- clk_disable_unprepare(nfc->sclk);
- out_ahb_clk_unprepare:
- clk_disable_unprepare(nfc->ahb_clk);
- return ret;
- }
- static const struct of_device_id sunxi_nfc_ids[] = {
- { .compatible = "allwinner,sun4i-nand" },
- { /* sentinel */ }
- };
- MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
- static struct platform_driver sunxi_nfc_driver = {
- .driver = {
- .name = "sunxi_nand",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(sunxi_nfc_ids),
- },
- .probe = sunxi_nfc_probe,
- };
- module_platform_driver(sunxi_nfc_driver);
- MODULE_LICENSE("GPL v2");
- MODULE_AUTHOR("Boris BREZILLON");
- MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
- MODULE_ALIAS("platform:sunxi_nfc");
复制代码 |
|