aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2011-11-19 10:02:48 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-01-09 13:07:18 -0500
commitae9d4934b2d76a9fba21f5ad3692378d0e7fc24b (patch)
tree32dc01f47b5dc4ed0ff8e0d4b05f662e826d2745 /drivers/mtd/devices
parent32a50b3a457fda9606fd0946eb77ba28a520cd7f (diff)
mtd: docg3: add multiple floor support
Add support for multiple floors, ie. cascaded docg3 chips. There might be 4 docg3 chips cascaded, sharing the same address space, and providing up to 4 times the storage capacity of a unique chip. Each floor will be seen as an independant mtd device. Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Reviewed-by: Ivan Djelic <ivan.djelic@parrot.com> Reviewed-by: Mike Dunn <mikedunn@newsguy.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r--drivers/mtd/devices/docg3.c181
-rw-r--r--drivers/mtd/devices/docg3.h1
2 files changed, 126 insertions, 56 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 1c2f54d23c7e..6eca7f6c072c 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -948,7 +948,8 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
948 948
949 switch (chip_id) { 949 switch (chip_id) {
950 case DOC_CHIPID_G3: 950 case DOC_CHIPID_G3:
951 mtd->name = "DiskOnChip G3"; 951 mtd->name = kasprintf(GFP_KERNEL, "DiskOnChip G3 floor %d",
952 docg3->device_id);
952 docg3->max_block = 2047; 953 docg3->max_block = 2047;
953 break; 954 break;
954 } 955 }
@@ -975,22 +976,24 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
975} 976}
976 977
977/** 978/**
978 * doc_probe - Probe the IO space for a DiskOnChip G3 chip 979 * doc_probe_device - Check if a device is available
979 * @pdev: platform device 980 * @base: the io space where the device is probed
981 * @floor: the floor of the probed device
982 * @dev: the device
980 * 983 *
981 * Probes for a G3 chip at the specified IO space in the platform data 984 * Checks whether a device at the specified IO range, and floor is available.
982 * ressources.
983 * 985 *
984 * Returns 0 on success, -ENOMEM, -ENXIO on error 986 * Returns a mtd_info struct if there is a device, ENODEV if none found, ENOMEM
987 * if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is
988 * launched.
985 */ 989 */
986static int __init docg3_probe(struct platform_device *pdev) 990static struct mtd_info *doc_probe_device(void __iomem *base, int floor,
991 struct device *dev)
987{ 992{
988 struct device *dev = &pdev->dev;
989 struct docg3 *docg3;
990 struct mtd_info *mtd;
991 struct resource *ress;
992 int ret, bbt_nbpages; 993 int ret, bbt_nbpages;
993 u16 chip_id, chip_id_inv; 994 u16 chip_id, chip_id_inv;
995 struct docg3 *docg3;
996 struct mtd_info *mtd;
994 997
995 ret = -ENOMEM; 998 ret = -ENOMEM;
996 docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL); 999 docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL);
@@ -1000,69 +1003,132 @@ static int __init docg3_probe(struct platform_device *pdev)
1000 if (!mtd) 1003 if (!mtd)
1001 goto nomem2; 1004 goto nomem2;
1002 mtd->priv = docg3; 1005 mtd->priv = docg3;
1006 bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1,
1007 8 * DOC_LAYOUT_PAGE_SIZE);
1008 docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL);
1009 if (!docg3->bbt)
1010 goto nomem3;
1003 1011
1004 ret = -ENXIO; 1012 docg3->dev = dev;
1005 ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1013 docg3->device_id = floor;
1006 if (!ress) { 1014 docg3->base = base;
1007 dev_err(dev, "No I/O memory resource defined\n");
1008 goto noress;
1009 }
1010 docg3->base = ioremap(ress->start, DOC_IOSPACE_SIZE);
1011
1012 docg3->dev = &pdev->dev;
1013 docg3->device_id = 0;
1014 doc_set_device_id(docg3, docg3->device_id); 1015 doc_set_device_id(docg3, docg3->device_id);
1015 doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); 1016 if (!floor)
1017 doc_set_asic_mode(docg3, DOC_ASICMODE_RESET);
1016 doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL); 1018 doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL);
1017 1019
1018 chip_id = doc_register_readw(docg3, DOC_CHIPID); 1020 chip_id = doc_register_readw(docg3, DOC_CHIPID);
1019 chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV); 1021 chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV);
1020 1022
1021 ret = -ENODEV; 1023 ret = 0;
1022 if (chip_id != (u16)(~chip_id_inv)) { 1024 if (chip_id != (u16)(~chip_id_inv)) {
1023 doc_info("No device found at IO addr %p\n", 1025 goto nomem3;
1024 (void *)ress->start);
1025 goto nochipfound;
1026 } 1026 }
1027 1027
1028 switch (chip_id) { 1028 switch (chip_id) {
1029 case DOC_CHIPID_G3: 1029 case DOC_CHIPID_G3:
1030 doc_info("Found a G3 DiskOnChip at addr %p\n", 1030 doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n",
1031 (void *)ress->start); 1031 base, floor);
1032 break; 1032 break;
1033 default: 1033 default:
1034 doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); 1034 doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id);
1035 goto nochipfound; 1035 goto nomem3;
1036 } 1036 }
1037 1037
1038 doc_set_driver_info(chip_id, mtd); 1038 doc_set_driver_info(chip_id, mtd);
1039 platform_set_drvdata(pdev, mtd);
1040 1039
1041 ret = -ENOMEM;
1042 bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1,
1043 8 * DOC_LAYOUT_PAGE_SIZE);
1044 docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL);
1045 if (!docg3->bbt)
1046 goto nochipfound;
1047 doc_reload_bbt(docg3); 1040 doc_reload_bbt(docg3);
1041 return mtd;
1048 1042
1049 ret = mtd_device_parse_register(mtd, part_probes, 1043nomem3:
1050 NULL, NULL, 0);
1051 if (ret)
1052 goto register_error;
1053
1054 doc_dbg_register(docg3);
1055 return 0;
1056
1057register_error:
1058 kfree(docg3->bbt);
1059nochipfound:
1060 iounmap(docg3->base);
1061noress:
1062 kfree(mtd); 1044 kfree(mtd);
1063nomem2: 1045nomem2:
1064 kfree(docg3); 1046 kfree(docg3);
1065nomem1: 1047nomem1:
1048 return ERR_PTR(ret);
1049}
1050
1051/**
1052 * doc_release_device - Release a docg3 floor
1053 * @mtd: the device
1054 */
1055static void doc_release_device(struct mtd_info *mtd)
1056{
1057 struct docg3 *docg3 = mtd->priv;
1058
1059 mtd_device_unregister(mtd);
1060 kfree(docg3->bbt);
1061 kfree(docg3);
1062 kfree(mtd->name);
1063 kfree(mtd);
1064}
1065
1066/**
1067 * doc_probe - Probe the IO space for a DiskOnChip G3 chip
1068 * @pdev: platform device
1069 *
1070 * Probes for a G3 chip at the specified IO space in the platform data
1071 * ressources. The floor 0 must be available.
1072 *
1073 * Returns 0 on success, -ENOMEM, -ENXIO on error
1074 */
1075static int __init docg3_probe(struct platform_device *pdev)
1076{
1077 struct device *dev = &pdev->dev;
1078 struct mtd_info *mtd;
1079 struct resource *ress;
1080 void __iomem *base;
1081 int ret, floor, found = 0;
1082 struct mtd_info **docg3_floors;
1083
1084 ret = -ENXIO;
1085 ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1086 if (!ress) {
1087 dev_err(dev, "No I/O memory resource defined\n");
1088 goto noress;
1089 }
1090 base = ioremap(ress->start, DOC_IOSPACE_SIZE);
1091
1092 ret = -ENOMEM;
1093 docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS,
1094 GFP_KERNEL);
1095 if (!docg3_floors)
1096 goto nomem;
1097
1098 ret = 0;
1099 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
1100 mtd = doc_probe_device(base, floor, dev);
1101 if (floor == 0 && !mtd)
1102 goto notfound;
1103 if (!IS_ERR_OR_NULL(mtd))
1104 ret = mtd_device_parse_register(mtd, part_probes,
1105 NULL, NULL, 0);
1106 else
1107 ret = PTR_ERR(mtd);
1108 docg3_floors[floor] = mtd;
1109 if (ret)
1110 goto err_probe;
1111 if (mtd)
1112 found++;
1113 }
1114
1115 if (!found)
1116 goto notfound;
1117
1118 platform_set_drvdata(pdev, docg3_floors);
1119 doc_dbg_register(docg3_floors[0]->priv);
1120 return 0;
1121
1122notfound:
1123 ret = -ENODEV;
1124 dev_info(dev, "No supported DiskOnChip found\n");
1125err_probe:
1126 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
1127 if (docg3_floors[floor])
1128 doc_release_device(docg3_floors[floor]);
1129nomem:
1130 iounmap(base);
1131noress:
1066 return ret; 1132 return ret;
1067} 1133}
1068 1134
@@ -1074,15 +1140,18 @@ nomem1:
1074 */ 1140 */
1075static int __exit docg3_release(struct platform_device *pdev) 1141static int __exit docg3_release(struct platform_device *pdev)
1076{ 1142{
1077 struct mtd_info *mtd = platform_get_drvdata(pdev); 1143 struct mtd_info **docg3_floors = platform_get_drvdata(pdev);
1078 struct docg3 *docg3 = mtd->priv; 1144 struct docg3 *docg3 = docg3_floors[0]->priv;
1145 void __iomem *base = docg3->base;
1146 int floor;
1079 1147
1080 doc_dbg_unregister(docg3); 1148 doc_dbg_unregister(docg3);
1081 mtd_device_unregister(mtd); 1149 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
1082 iounmap(docg3->base); 1150 if (docg3_floors[floor])
1083 kfree(docg3->bbt); 1151 doc_release_device(docg3_floors[floor]);
1084 kfree(docg3); 1152
1085 kfree(mtd); 1153 kfree(docg3_floors);
1154 iounmap(base);
1086 return 0; 1155 return 0;
1087} 1156}
1088 1157
diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h
index 62af5aaeec43..75df3a1060fb 100644
--- a/drivers/mtd/devices/docg3.h
+++ b/drivers/mtd/devices/docg3.h
@@ -80,6 +80,7 @@
80 80
81#define DOC_CHIPID_G3 0x200 81#define DOC_CHIPID_G3 0x200
82#define DOC_ERASE_MARK 0xaa 82#define DOC_ERASE_MARK 0xaa
83#define DOC_MAX_NBFLOORS 4
83/* 84/*
84 * Flash registers 85 * Flash registers
85 */ 86 */