diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2012-04-23 05:23:35 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-05-14 00:01:39 -0400 |
commit | e4303b25f4452dd6a0a49c318e5e93d0c5f8b1ba (patch) | |
tree | 024262f7aaafb2ecc1e52890bb04c6b42f5b0c0e /drivers/mtd | |
parent | 8556958af4ef58147c11f772e6171c149efee53c (diff) |
mtd: mxc_nand: move function pointers to a per-SOC struct
This prepares switching to platform ids and of-tree probing.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 170 |
1 files changed, 104 insertions, 66 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 6f6068043fad..b6e4618bb043 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -140,6 +140,19 @@ | |||
140 | 140 | ||
141 | #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) | 141 | #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) |
142 | 142 | ||
143 | struct mxc_nand_host; | ||
144 | |||
145 | struct mxc_nand_devtype_data { | ||
146 | void (*preset)(struct mtd_info *); | ||
147 | void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); | ||
148 | void (*send_addr)(struct mxc_nand_host *, uint16_t, int); | ||
149 | void (*send_page)(struct mtd_info *, unsigned int); | ||
150 | void (*send_read_id)(struct mxc_nand_host *); | ||
151 | uint16_t (*get_dev_status)(struct mxc_nand_host *); | ||
152 | int (*check_int)(struct mxc_nand_host *); | ||
153 | void (*irq_control)(struct mxc_nand_host *, int); | ||
154 | }; | ||
155 | |||
143 | struct mxc_nand_host { | 156 | struct mxc_nand_host { |
144 | struct mtd_info mtd; | 157 | struct mtd_info mtd; |
145 | struct nand_chip nand; | 158 | struct nand_chip nand; |
@@ -165,14 +178,7 @@ struct mxc_nand_host { | |||
165 | unsigned int buf_start; | 178 | unsigned int buf_start; |
166 | int spare_len; | 179 | int spare_len; |
167 | 180 | ||
168 | void (*preset)(struct mtd_info *); | 181 | const struct mxc_nand_devtype_data *devtype_data; |
169 | void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); | ||
170 | void (*send_addr)(struct mxc_nand_host *, uint16_t, int); | ||
171 | void (*send_page)(struct mtd_info *, unsigned int); | ||
172 | void (*send_read_id)(struct mxc_nand_host *); | ||
173 | uint16_t (*get_dev_status)(struct mxc_nand_host *); | ||
174 | int (*check_int)(struct mxc_nand_host *); | ||
175 | void (*irq_control)(struct mxc_nand_host *, int); | ||
176 | 182 | ||
177 | /* | 183 | /* |
178 | * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked | 184 | * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked |
@@ -315,7 +321,7 @@ static void irq_control(struct mxc_nand_host *host, int activate) | |||
315 | else | 321 | else |
316 | disable_irq_nosync(host->irq); | 322 | disable_irq_nosync(host->irq); |
317 | } else { | 323 | } else { |
318 | host->irq_control(host, activate); | 324 | host->devtype_data->irq_control(host, activate); |
319 | } | 325 | } |
320 | } | 326 | } |
321 | 327 | ||
@@ -323,7 +329,7 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
323 | { | 329 | { |
324 | struct mxc_nand_host *host = dev_id; | 330 | struct mxc_nand_host *host = dev_id; |
325 | 331 | ||
326 | if (!host->check_int(host)) | 332 | if (!host->devtype_data->check_int(host)) |
327 | return IRQ_NONE; | 333 | return IRQ_NONE; |
328 | 334 | ||
329 | irq_control(host, 0); | 335 | irq_control(host, 0); |
@@ -341,14 +347,14 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) | |||
341 | int max_retries = 8000; | 347 | int max_retries = 8000; |
342 | 348 | ||
343 | if (useirq) { | 349 | if (useirq) { |
344 | if (!host->check_int(host)) { | 350 | if (!host->devtype_data->check_int(host)) { |
345 | INIT_COMPLETION(host->op_completion); | 351 | INIT_COMPLETION(host->op_completion); |
346 | irq_control(host, 1); | 352 | irq_control(host, 1); |
347 | wait_for_completion(&host->op_completion); | 353 | wait_for_completion(&host->op_completion); |
348 | } | 354 | } |
349 | } else { | 355 | } else { |
350 | while (max_retries-- > 0) { | 356 | while (max_retries-- > 0) { |
351 | if (host->check_int(host)) | 357 | if (host->devtype_data->check_int(host)) |
352 | break; | 358 | break; |
353 | 359 | ||
354 | udelay(1); | 360 | udelay(1); |
@@ -621,7 +627,7 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
621 | 627 | ||
622 | /* Check for status request */ | 628 | /* Check for status request */ |
623 | if (host->status_request) | 629 | if (host->status_request) |
624 | return host->get_dev_status(host) & 0xFF; | 630 | return host->devtype_data->get_dev_status(host) & 0xFF; |
625 | 631 | ||
626 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | 632 | ret = *(uint8_t *)(host->data_buf + host->buf_start); |
627 | host->buf_start++; | 633 | host->buf_start++; |
@@ -756,34 +762,44 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | |||
756 | * perform a read/write buf operation, the saved column | 762 | * perform a read/write buf operation, the saved column |
757 | * address is used to index into the full page. | 763 | * address is used to index into the full page. |
758 | */ | 764 | */ |
759 | host->send_addr(host, 0, page_addr == -1); | 765 | host->devtype_data->send_addr(host, 0, page_addr == -1); |
760 | if (mtd->writesize > 512) | 766 | if (mtd->writesize > 512) |
761 | /* another col addr cycle for 2k page */ | 767 | /* another col addr cycle for 2k page */ |
762 | host->send_addr(host, 0, false); | 768 | host->devtype_data->send_addr(host, 0, false); |
763 | } | 769 | } |
764 | 770 | ||
765 | /* Write out page address, if necessary */ | 771 | /* Write out page address, if necessary */ |
766 | if (page_addr != -1) { | 772 | if (page_addr != -1) { |
767 | /* paddr_0 - p_addr_7 */ | 773 | /* paddr_0 - p_addr_7 */ |
768 | host->send_addr(host, (page_addr & 0xff), false); | 774 | host->devtype_data->send_addr(host, (page_addr & 0xff), false); |
769 | 775 | ||
770 | if (mtd->writesize > 512) { | 776 | if (mtd->writesize > 512) { |
771 | if (mtd->size >= 0x10000000) { | 777 | if (mtd->size >= 0x10000000) { |
772 | /* paddr_8 - paddr_15 */ | 778 | /* paddr_8 - paddr_15 */ |
773 | host->send_addr(host, (page_addr >> 8) & 0xff, false); | 779 | host->devtype_data->send_addr(host, |
774 | host->send_addr(host, (page_addr >> 16) & 0xff, true); | 780 | (page_addr >> 8) & 0xff, |
781 | false); | ||
782 | host->devtype_data->send_addr(host, | ||
783 | (page_addr >> 16) & 0xff, | ||
784 | true); | ||
775 | } else | 785 | } else |
776 | /* paddr_8 - paddr_15 */ | 786 | /* paddr_8 - paddr_15 */ |
777 | host->send_addr(host, (page_addr >> 8) & 0xff, true); | 787 | host->devtype_data->send_addr(host, |
788 | (page_addr >> 8) & 0xff, true); | ||
778 | } else { | 789 | } else { |
779 | /* One more address cycle for higher density devices */ | 790 | /* One more address cycle for higher density devices */ |
780 | if (mtd->size >= 0x4000000) { | 791 | if (mtd->size >= 0x4000000) { |
781 | /* paddr_8 - paddr_15 */ | 792 | /* paddr_8 - paddr_15 */ |
782 | host->send_addr(host, (page_addr >> 8) & 0xff, false); | 793 | host->devtype_data->send_addr(host, |
783 | host->send_addr(host, (page_addr >> 16) & 0xff, true); | 794 | (page_addr >> 8) & 0xff, |
795 | false); | ||
796 | host->devtype_data->send_addr(host, | ||
797 | (page_addr >> 16) & 0xff, | ||
798 | true); | ||
784 | } else | 799 | } else |
785 | /* paddr_8 - paddr_15 */ | 800 | /* paddr_8 - paddr_15 */ |
786 | host->send_addr(host, (page_addr >> 8) & 0xff, true); | 801 | host->devtype_data->send_addr(host, |
802 | (page_addr >> 8) & 0xff, true); | ||
787 | } | 803 | } |
788 | } | 804 | } |
789 | } | 805 | } |
@@ -942,15 +958,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
942 | /* Command pre-processing step */ | 958 | /* Command pre-processing step */ |
943 | switch (command) { | 959 | switch (command) { |
944 | case NAND_CMD_RESET: | 960 | case NAND_CMD_RESET: |
945 | host->preset(mtd); | 961 | host->devtype_data->preset(mtd); |
946 | host->send_cmd(host, command, false); | 962 | host->devtype_data->send_cmd(host, command, false); |
947 | break; | 963 | break; |
948 | 964 | ||
949 | case NAND_CMD_STATUS: | 965 | case NAND_CMD_STATUS: |
950 | host->buf_start = 0; | 966 | host->buf_start = 0; |
951 | host->status_request = true; | 967 | host->status_request = true; |
952 | 968 | ||
953 | host->send_cmd(host, command, true); | 969 | host->devtype_data->send_cmd(host, command, true); |
954 | mxc_do_addr_cycle(mtd, column, page_addr); | 970 | mxc_do_addr_cycle(mtd, column, page_addr); |
955 | break; | 971 | break; |
956 | 972 | ||
@@ -963,13 +979,14 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
963 | 979 | ||
964 | command = NAND_CMD_READ0; /* only READ0 is valid */ | 980 | command = NAND_CMD_READ0; /* only READ0 is valid */ |
965 | 981 | ||
966 | host->send_cmd(host, command, false); | 982 | host->devtype_data->send_cmd(host, command, false); |
967 | mxc_do_addr_cycle(mtd, column, page_addr); | 983 | mxc_do_addr_cycle(mtd, column, page_addr); |
968 | 984 | ||
969 | if (mtd->writesize > 512) | 985 | if (mtd->writesize > 512) |
970 | host->send_cmd(host, NAND_CMD_READSTART, true); | 986 | host->devtype_data->send_cmd(host, |
987 | NAND_CMD_READSTART, true); | ||
971 | 988 | ||
972 | host->send_page(mtd, NFC_OUTPUT); | 989 | host->devtype_data->send_page(mtd, NFC_OUTPUT); |
973 | 990 | ||
974 | memcpy(host->data_buf, host->main_area0, mtd->writesize); | 991 | memcpy(host->data_buf, host->main_area0, mtd->writesize); |
975 | copy_spare(mtd, true); | 992 | copy_spare(mtd, true); |
@@ -982,28 +999,28 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
982 | 999 | ||
983 | host->buf_start = column; | 1000 | host->buf_start = column; |
984 | 1001 | ||
985 | host->send_cmd(host, command, false); | 1002 | host->devtype_data->send_cmd(host, command, false); |
986 | mxc_do_addr_cycle(mtd, column, page_addr); | 1003 | mxc_do_addr_cycle(mtd, column, page_addr); |
987 | break; | 1004 | break; |
988 | 1005 | ||
989 | case NAND_CMD_PAGEPROG: | 1006 | case NAND_CMD_PAGEPROG: |
990 | memcpy(host->main_area0, host->data_buf, mtd->writesize); | 1007 | memcpy(host->main_area0, host->data_buf, mtd->writesize); |
991 | copy_spare(mtd, false); | 1008 | copy_spare(mtd, false); |
992 | host->send_page(mtd, NFC_INPUT); | 1009 | host->devtype_data->send_page(mtd, NFC_INPUT); |
993 | host->send_cmd(host, command, true); | 1010 | host->devtype_data->send_cmd(host, command, true); |
994 | mxc_do_addr_cycle(mtd, column, page_addr); | 1011 | mxc_do_addr_cycle(mtd, column, page_addr); |
995 | break; | 1012 | break; |
996 | 1013 | ||
997 | case NAND_CMD_READID: | 1014 | case NAND_CMD_READID: |
998 | host->send_cmd(host, command, true); | 1015 | host->devtype_data->send_cmd(host, command, true); |
999 | mxc_do_addr_cycle(mtd, column, page_addr); | 1016 | mxc_do_addr_cycle(mtd, column, page_addr); |
1000 | host->send_read_id(host); | 1017 | host->devtype_data->send_read_id(host); |
1001 | host->buf_start = column; | 1018 | host->buf_start = column; |
1002 | break; | 1019 | break; |
1003 | 1020 | ||
1004 | case NAND_CMD_ERASE1: | 1021 | case NAND_CMD_ERASE1: |
1005 | case NAND_CMD_ERASE2: | 1022 | case NAND_CMD_ERASE2: |
1006 | host->send_cmd(host, command, false); | 1023 | host->devtype_data->send_cmd(host, command, false); |
1007 | mxc_do_addr_cycle(mtd, column, page_addr); | 1024 | mxc_do_addr_cycle(mtd, column, page_addr); |
1008 | 1025 | ||
1009 | break; | 1026 | break; |
@@ -1037,6 +1054,42 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1037 | .pattern = mirror_pattern, | 1054 | .pattern = mirror_pattern, |
1038 | }; | 1055 | }; |
1039 | 1056 | ||
1057 | /* v1: i.MX21, i.MX27, i.MX31 */ | ||
1058 | static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { | ||
1059 | .preset = preset_v1_v2, | ||
1060 | .send_cmd = send_cmd_v1_v2, | ||
1061 | .send_addr = send_addr_v1_v2, | ||
1062 | .send_page = send_page_v1_v2, | ||
1063 | .send_read_id = send_read_id_v1_v2, | ||
1064 | .get_dev_status = get_dev_status_v1_v2, | ||
1065 | .check_int = check_int_v1_v2, | ||
1066 | .irq_control = irq_control_v1_v2, | ||
1067 | }; | ||
1068 | |||
1069 | /* v21: i.MX25, i.MX35 */ | ||
1070 | static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { | ||
1071 | .preset = preset_v1_v2, | ||
1072 | .send_cmd = send_cmd_v1_v2, | ||
1073 | .send_addr = send_addr_v1_v2, | ||
1074 | .send_page = send_page_v1_v2, | ||
1075 | .send_read_id = send_read_id_v1_v2, | ||
1076 | .get_dev_status = get_dev_status_v1_v2, | ||
1077 | .check_int = check_int_v1_v2, | ||
1078 | .irq_control = irq_control_v1_v2, | ||
1079 | }; | ||
1080 | |||
1081 | /* v3: i.MX51, i.MX53 */ | ||
1082 | static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { | ||
1083 | .preset = preset_v3, | ||
1084 | .send_cmd = send_cmd_v3, | ||
1085 | .send_addr = send_addr_v3, | ||
1086 | .send_page = send_page_v3, | ||
1087 | .send_read_id = send_read_id_v3, | ||
1088 | .get_dev_status = get_dev_status_v3, | ||
1089 | .check_int = check_int_v3, | ||
1090 | .irq_control = irq_control_v3, | ||
1091 | }; | ||
1092 | |||
1040 | static int __init mxcnd_probe(struct platform_device *pdev) | 1093 | static int __init mxcnd_probe(struct platform_device *pdev) |
1041 | { | 1094 | { |
1042 | struct nand_chip *this; | 1095 | struct nand_chip *this; |
@@ -1100,27 +1153,10 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1100 | 1153 | ||
1101 | host->main_area0 = host->base; | 1154 | host->main_area0 = host->base; |
1102 | 1155 | ||
1103 | if (nfc_is_v1() || nfc_is_v21()) { | 1156 | if (nfc_is_v1()) { |
1104 | host->preset = preset_v1_v2; | 1157 | host->devtype_data = &imx21_nand_devtype_data; |
1105 | host->send_cmd = send_cmd_v1_v2; | ||
1106 | host->send_addr = send_addr_v1_v2; | ||
1107 | host->send_page = send_page_v1_v2; | ||
1108 | host->send_read_id = send_read_id_v1_v2; | ||
1109 | host->get_dev_status = get_dev_status_v1_v2; | ||
1110 | host->check_int = check_int_v1_v2; | ||
1111 | host->irq_control = irq_control_v1_v2; | ||
1112 | if (cpu_is_mx21()) | 1158 | if (cpu_is_mx21()) |
1113 | host->irqpending_quirk = 1; | 1159 | host->irqpending_quirk = 1; |
1114 | } | ||
1115 | |||
1116 | if (nfc_is_v21()) { | ||
1117 | host->regs = host->base + 0x1e00; | ||
1118 | host->spare0 = host->base + 0x1000; | ||
1119 | host->spare_len = 64; | ||
1120 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
1121 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
1122 | this->ecc.bytes = 9; | ||
1123 | } else if (nfc_is_v1()) { | ||
1124 | host->regs = host->base + 0xe00; | 1160 | host->regs = host->base + 0xe00; |
1125 | host->spare0 = host->base + 0x800; | 1161 | host->spare0 = host->base + 0x800; |
1126 | host->spare_len = 16; | 1162 | host->spare_len = 16; |
@@ -1128,7 +1164,16 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1128 | oob_largepage = &nandv1_hw_eccoob_largepage; | 1164 | oob_largepage = &nandv1_hw_eccoob_largepage; |
1129 | this->ecc.bytes = 3; | 1165 | this->ecc.bytes = 3; |
1130 | host->eccsize = 1; | 1166 | host->eccsize = 1; |
1167 | } else if (nfc_is_v21()) { | ||
1168 | host->devtype_data = &imx25_nand_devtype_data; | ||
1169 | host->regs = host->base + 0x1e00; | ||
1170 | host->spare0 = host->base + 0x1000; | ||
1171 | host->spare_len = 64; | ||
1172 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
1173 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
1174 | this->ecc.bytes = 9; | ||
1131 | } else if (nfc_is_v3_2()) { | 1175 | } else if (nfc_is_v3_2()) { |
1176 | host->devtype_data = &imx51_nand_devtype_data; | ||
1132 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1177 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
1133 | if (!res) { | 1178 | if (!res) { |
1134 | err = -ENODEV; | 1179 | err = -ENODEV; |
@@ -1142,14 +1187,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1142 | host->regs_axi = host->base + 0x1e00; | 1187 | host->regs_axi = host->base + 0x1e00; |
1143 | host->spare0 = host->base + 0x1000; | 1188 | host->spare0 = host->base + 0x1000; |
1144 | host->spare_len = 64; | 1189 | host->spare_len = 64; |
1145 | host->preset = preset_v3; | ||
1146 | host->send_cmd = send_cmd_v3; | ||
1147 | host->send_addr = send_addr_v3; | ||
1148 | host->send_page = send_page_v3; | ||
1149 | host->send_read_id = send_read_id_v3; | ||
1150 | host->check_int = check_int_v3; | ||
1151 | host->get_dev_status = get_dev_status_v3; | ||
1152 | host->irq_control = irq_control_v3; | ||
1153 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | 1190 | oob_smallpage = &nandv2_hw_eccoob_smallpage; |
1154 | oob_largepage = &nandv2_hw_eccoob_largepage; | 1191 | oob_largepage = &nandv2_hw_eccoob_largepage; |
1155 | } else | 1192 | } else |
@@ -1186,10 +1223,11 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1186 | host->irq = platform_get_irq(pdev, 0); | 1223 | host->irq = platform_get_irq(pdev, 0); |
1187 | 1224 | ||
1188 | /* | 1225 | /* |
1189 | * Use host->irq_control here instead of irq_control because we must not | 1226 | * Use host->devtype_data->irq_control() here instead of irq_control() |
1190 | * disable_irq_nosync without having requested the irq | 1227 | * because we must not disable_irq_nosync without having requested the |
1228 | * irq. | ||
1191 | */ | 1229 | */ |
1192 | host->irq_control(host, 0); | 1230 | host->devtype_data->irq_control(host, 0); |
1193 | 1231 | ||
1194 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); | 1232 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); |
1195 | if (err) | 1233 | if (err) |
@@ -1202,7 +1240,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1202 | */ | 1240 | */ |
1203 | if (host->irqpending_quirk) { | 1241 | if (host->irqpending_quirk) { |
1204 | disable_irq_nosync(host->irq); | 1242 | disable_irq_nosync(host->irq); |
1205 | host->irq_control(host, 1); | 1243 | host->devtype_data->irq_control(host, 1); |
1206 | } | 1244 | } |
1207 | 1245 | ||
1208 | /* first scan to find the device and get the page size */ | 1246 | /* first scan to find the device and get the page size */ |
@@ -1212,7 +1250,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1212 | } | 1250 | } |
1213 | 1251 | ||
1214 | /* Call preset again, with correct writesize this time */ | 1252 | /* Call preset again, with correct writesize this time */ |
1215 | host->preset(mtd); | 1253 | host->devtype_data->preset(mtd); |
1216 | 1254 | ||
1217 | if (mtd->writesize == 2048) | 1255 | if (mtd->writesize == 2048) |
1218 | this->ecc.layout = oob_largepage; | 1256 | this->ecc.layout = oob_largepage; |