--- "a/drivers/mtd/maps/lantiq-flash.c" +++ "b/drivers/mtd/maps/lantiq-flash.c" @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -39,10 +40,12 @@ LTQ_NOR_NORMAL }; +#define MAX_RESOURCES 4 + struct ltq_mtd { - struct resource *res; - struct mtd_info *mtd; - struct map_info *map; + struct mtd_info *mtd[MAX_RESOURCES]; + struct mtd_info *cmtd; + struct map_info map[MAX_RESOURCES]; }; static const char ltq_map_name[] = "ltq_nor"; @@ -110,12 +113,39 @@ } static int +ltq_mtd_remove(struct platform_device *pdev) +{ + struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); + int i; + + if (ltq_mtd == NULL) + return 0; + + if (ltq_mtd->cmtd) { + mtd_device_unregister(ltq_mtd->cmtd); + if (ltq_mtd->cmtd != ltq_mtd->mtd[0]) + mtd_concat_destroy(ltq_mtd->cmtd); + } + + for (i = 0; i < MAX_RESOURCES; i++) { + if (ltq_mtd->mtd[i] != NULL) + map_destroy(ltq_mtd->mtd[i]); + } + + kfree(ltq_mtd); + + return 0; +} + +static int ltq_mtd_probe(struct platform_device *pdev) { struct mtd_part_parser_data ppdata; struct ltq_mtd *ltq_mtd; struct cfi_private *cfi; - int err; + int err = 0; + int i; + int devices_found = 0; static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL @@ -131,88 +161,88 @@ ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); platform_set_drvdata(pdev, ltq_mtd); - ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!ltq_mtd->res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); - err = -ENOENT; - goto err_out; - } + for (i = 0; i < pdev->num_resources; i++) { + printk(KERN_NOTICE "lantiq nor flash device: %.8llx at %.8llx\n", + (unsigned long long)resource_size(&pdev->resource[i]), + (unsigned long long)pdev->resource[i].start); + + if (!devm_request_mem_region(&pdev->dev, + pdev->resource[i].start, + resource_size(&pdev->resource[i]), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Could not reserve memory region\n"); + err = -ENOMEM; + goto err_out; + } - ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); - if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL)) - ltq_mtd->map->phys = NO_XIP; - else - ltq_mtd->map->phys = ltq_mtd->res->start; - ltq_mtd->res->start; - ltq_mtd->map->size = resource_size(ltq_mtd->res); - ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); - if (IS_ERR(ltq_mtd->map->virt)) { - err = PTR_ERR(ltq_mtd->map->virt); - goto err_out; - } + ltq_mtd->map[i].name = ltq_map_name; + ltq_mtd->map[i].bankwidth = 2; + ltq_mtd->map[i].read = ltq_read16; + ltq_mtd->map[i].write = ltq_write16; + ltq_mtd->map[i].copy_from = ltq_copy_from; + ltq_mtd->map[i].copy_to = ltq_copy_to; + + if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL)) + ltq_mtd->map[i].phys = NO_XIP; + else + ltq_mtd->map[i].phys = pdev->resource[i].start; + ltq_mtd->map[i].size = resource_size(&pdev->resource[i]); + ltq_mtd->map[i].virt = devm_ioremap(&pdev->dev, ltq_mtd->map[i].phys, + ltq_mtd->map[i].size); + if (ltq_mtd->map[i].virt == NULL) { + dev_err(&pdev->dev, "Failed to ioremap flash region\n"); + err = PTR_ERR(ltq_mtd->map[i].virt); + goto err_out; + } - ltq_mtd->map->name = ltq_map_name; - ltq_mtd->map->bankwidth = 2; - ltq_mtd->map->read = ltq_read16; - ltq_mtd->map->write = ltq_write16; - ltq_mtd->map->copy_from = ltq_copy_from; - ltq_mtd->map->copy_to = ltq_copy_to; + ltq_mtd->map[i].map_priv_1 = LTQ_NOR_PROBING; + for (type = rom_probe_types; !ltq_mtd->mtd[i] && *type; type++) { + ltq_mtd->mtd[i] = do_map_probe(*type, <q_mtd->map[i]); + } + ltq_mtd->map[i].map_priv_1 = LTQ_NOR_NORMAL; - ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; + if (!ltq_mtd->mtd[i]) { + dev_err(&pdev->dev, "probing failed\n"); + err = -ENXIO; + goto err_out; + } else { + devices_found++; + } - for (type = rom_probe_types; !ltq_mtd->mtd && *type; type++) { - ltq_mtd->mtd = do_map_probe(*type, ltq_mtd->map); - } - - ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; + ltq_mtd->mtd[i]->owner = THIS_MODULE; + ltq_mtd->mtd[i]->dev.parent = &pdev->dev; - if (!ltq_mtd->mtd) { - dev_err(&pdev->dev, "probing failed\n"); - err = -ENXIO; - goto err_free; + cfi = ltq_mtd->map[i].fldrv_priv; + cfi->addr_unlock1 ^= 1; + cfi->addr_unlock2 ^= 1; + } + + if (devices_found == 1) { + ltq_mtd->cmtd = ltq_mtd->mtd[0]; + } else if (devices_found > 1) { + /* + * We detected multiple devices. Concatenate them together. + */ + ltq_mtd->cmtd = mtd_concat_create(ltq_mtd->mtd, devices_found, dev_name(&pdev->dev)); + if (ltq_mtd->cmtd == NULL) + err = -ENXIO; } - ltq_mtd->mtd->owner = THIS_MODULE; - - cfi = ltq_mtd->map->fldrv_priv; - cfi->addr_unlock1 ^= 1; - cfi->addr_unlock2 ^= 1; - ppdata.of_node = pdev->dev.of_node; - err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, + err = mtd_device_parse_register(ltq_mtd->cmtd, ltq_probe_types, &ppdata, NULL, 0); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); - goto err_destroy; + goto err_out; } return 0; -err_destroy: - map_destroy(ltq_mtd->mtd); -err_free: - kfree(ltq_mtd->map); err_out: - kfree(ltq_mtd); + ltq_mtd_remove(pdev); return err; } -static int -ltq_mtd_remove(struct platform_device *pdev) -{ - struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); - - if (ltq_mtd) { - if (ltq_mtd->mtd) { - mtd_device_unregister(ltq_mtd->mtd); - map_destroy(ltq_mtd->mtd); - } - kfree(ltq_mtd->map); - kfree(ltq_mtd); - } - return 0; -} - static const struct of_device_id ltq_mtd_match[] = { { .compatible = "lantiq,nor" }, {},