diff options
Diffstat (limited to 'drivers/block/xsysace.c')
-rw-r--r-- | drivers/block/xsysace.c | 274 |
1 files changed, 203 insertions, 71 deletions
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3ede0b63da13..9e7652dcde6c 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c | |||
@@ -91,6 +91,10 @@ | |||
91 | #include <linux/blkdev.h> | 91 | #include <linux/blkdev.h> |
92 | #include <linux/hdreg.h> | 92 | #include <linux/hdreg.h> |
93 | #include <linux/platform_device.h> | 93 | #include <linux/platform_device.h> |
94 | #if defined(CONFIG_OF) | ||
95 | #include <linux/of_device.h> | ||
96 | #include <linux/of_platform.h> | ||
97 | #endif | ||
94 | 98 | ||
95 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | 99 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); |
96 | MODULE_DESCRIPTION("Xilinx SystemACE device driver"); | 100 | MODULE_DESCRIPTION("Xilinx SystemACE device driver"); |
@@ -158,6 +162,9 @@ MODULE_LICENSE("GPL"); | |||
158 | #define ACE_FIFO_SIZE (32) | 162 | #define ACE_FIFO_SIZE (32) |
159 | #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE) | 163 | #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE) |
160 | 164 | ||
165 | #define ACE_BUS_WIDTH_8 0 | ||
166 | #define ACE_BUS_WIDTH_16 1 | ||
167 | |||
161 | struct ace_reg_ops; | 168 | struct ace_reg_ops; |
162 | 169 | ||
163 | struct ace_device { | 170 | struct ace_device { |
@@ -188,7 +195,7 @@ struct ace_device { | |||
188 | 195 | ||
189 | /* Details of hardware device */ | 196 | /* Details of hardware device */ |
190 | unsigned long physaddr; | 197 | unsigned long physaddr; |
191 | void *baseaddr; | 198 | void __iomem *baseaddr; |
192 | int irq; | 199 | int irq; |
193 | int bus_width; /* 0 := 8 bit; 1 := 16 bit */ | 200 | int bus_width; /* 0 := 8 bit; 1 := 16 bit */ |
194 | struct ace_reg_ops *reg_ops; | 201 | struct ace_reg_ops *reg_ops; |
@@ -220,20 +227,20 @@ struct ace_reg_ops { | |||
220 | /* 8 Bit bus width */ | 227 | /* 8 Bit bus width */ |
221 | static u16 ace_in_8(struct ace_device *ace, int reg) | 228 | static u16 ace_in_8(struct ace_device *ace, int reg) |
222 | { | 229 | { |
223 | void *r = ace->baseaddr + reg; | 230 | void __iomem *r = ace->baseaddr + reg; |
224 | return in_8(r) | (in_8(r + 1) << 8); | 231 | return in_8(r) | (in_8(r + 1) << 8); |
225 | } | 232 | } |
226 | 233 | ||
227 | static void ace_out_8(struct ace_device *ace, int reg, u16 val) | 234 | static void ace_out_8(struct ace_device *ace, int reg, u16 val) |
228 | { | 235 | { |
229 | void *r = ace->baseaddr + reg; | 236 | void __iomem *r = ace->baseaddr + reg; |
230 | out_8(r, val); | 237 | out_8(r, val); |
231 | out_8(r + 1, val >> 8); | 238 | out_8(r + 1, val >> 8); |
232 | } | 239 | } |
233 | 240 | ||
234 | static void ace_datain_8(struct ace_device *ace) | 241 | static void ace_datain_8(struct ace_device *ace) |
235 | { | 242 | { |
236 | void *r = ace->baseaddr + 0x40; | 243 | void __iomem *r = ace->baseaddr + 0x40; |
237 | u8 *dst = ace->data_ptr; | 244 | u8 *dst = ace->data_ptr; |
238 | int i = ACE_FIFO_SIZE; | 245 | int i = ACE_FIFO_SIZE; |
239 | while (i--) | 246 | while (i--) |
@@ -243,7 +250,7 @@ static void ace_datain_8(struct ace_device *ace) | |||
243 | 250 | ||
244 | static void ace_dataout_8(struct ace_device *ace) | 251 | static void ace_dataout_8(struct ace_device *ace) |
245 | { | 252 | { |
246 | void *r = ace->baseaddr + 0x40; | 253 | void __iomem *r = ace->baseaddr + 0x40; |
247 | u8 *src = ace->data_ptr; | 254 | u8 *src = ace->data_ptr; |
248 | int i = ACE_FIFO_SIZE; | 255 | int i = ACE_FIFO_SIZE; |
249 | while (i--) | 256 | while (i--) |
@@ -931,9 +938,11 @@ static int __devinit ace_setup(struct ace_device *ace) | |||
931 | { | 938 | { |
932 | u16 version; | 939 | u16 version; |
933 | u16 val; | 940 | u16 val; |
934 | |||
935 | int rc; | 941 | int rc; |
936 | 942 | ||
943 | dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace); | ||
944 | dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq); | ||
945 | |||
937 | spin_lock_init(&ace->lock); | 946 | spin_lock_init(&ace->lock); |
938 | init_completion(&ace->id_completion); | 947 | init_completion(&ace->id_completion); |
939 | 948 | ||
@@ -944,15 +953,6 @@ static int __devinit ace_setup(struct ace_device *ace) | |||
944 | if (!ace->baseaddr) | 953 | if (!ace->baseaddr) |
945 | goto err_ioremap; | 954 | goto err_ioremap; |
946 | 955 | ||
947 | if (ace->irq != NO_IRQ) { | ||
948 | rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); | ||
949 | if (rc) { | ||
950 | /* Failure - fall back to polled mode */ | ||
951 | dev_err(ace->dev, "request_irq failed\n"); | ||
952 | ace->irq = NO_IRQ; | ||
953 | } | ||
954 | } | ||
955 | |||
956 | /* | 956 | /* |
957 | * Initialize the state machine tasklet and stall timer | 957 | * Initialize the state machine tasklet and stall timer |
958 | */ | 958 | */ |
@@ -982,7 +982,7 @@ static int __devinit ace_setup(struct ace_device *ace) | |||
982 | snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); | 982 | snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); |
983 | 983 | ||
984 | /* set bus width */ | 984 | /* set bus width */ |
985 | if (ace->bus_width == 1) { | 985 | if (ace->bus_width == ACE_BUS_WIDTH_16) { |
986 | /* 0x0101 should work regardless of endianess */ | 986 | /* 0x0101 should work regardless of endianess */ |
987 | ace_out_le16(ace, ACE_BUSMODE, 0x0101); | 987 | ace_out_le16(ace, ACE_BUSMODE, 0x0101); |
988 | 988 | ||
@@ -1005,6 +1005,16 @@ static int __devinit ace_setup(struct ace_device *ace) | |||
1005 | ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE | | 1005 | ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE | |
1006 | ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ); | 1006 | ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ); |
1007 | 1007 | ||
1008 | /* Now we can hook up the irq handler */ | ||
1009 | if (ace->irq != NO_IRQ) { | ||
1010 | rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); | ||
1011 | if (rc) { | ||
1012 | /* Failure - fall back to polled mode */ | ||
1013 | dev_err(ace->dev, "request_irq failed\n"); | ||
1014 | ace->irq = NO_IRQ; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1008 | /* Enable interrupts */ | 1018 | /* Enable interrupts */ |
1009 | val = ace_in(ace, ACE_CTRL); | 1019 | val = ace_in(ace, ACE_CTRL); |
1010 | val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; | 1020 | val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; |
@@ -1024,16 +1034,14 @@ static int __devinit ace_setup(struct ace_device *ace) | |||
1024 | 1034 | ||
1025 | return 0; | 1035 | return 0; |
1026 | 1036 | ||
1027 | err_read: | 1037 | err_read: |
1028 | put_disk(ace->gd); | 1038 | put_disk(ace->gd); |
1029 | err_alloc_disk: | 1039 | err_alloc_disk: |
1030 | blk_cleanup_queue(ace->queue); | 1040 | blk_cleanup_queue(ace->queue); |
1031 | err_blk_initq: | 1041 | err_blk_initq: |
1032 | iounmap(ace->baseaddr); | 1042 | iounmap(ace->baseaddr); |
1033 | if (ace->irq != NO_IRQ) | 1043 | err_ioremap: |
1034 | free_irq(ace->irq, ace); | 1044 | dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", |
1035 | err_ioremap: | ||
1036 | printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n", | ||
1037 | ace->physaddr); | 1045 | ace->physaddr); |
1038 | return -ENOMEM; | 1046 | return -ENOMEM; |
1039 | } | 1047 | } |
@@ -1056,98 +1064,222 @@ static void __devexit ace_teardown(struct ace_device *ace) | |||
1056 | iounmap(ace->baseaddr); | 1064 | iounmap(ace->baseaddr); |
1057 | } | 1065 | } |
1058 | 1066 | ||
1059 | /* --------------------------------------------------------------------- | 1067 | static int __devinit |
1060 | * Platform Bus Support | 1068 | ace_alloc(struct device *dev, int id, unsigned long physaddr, |
1061 | */ | 1069 | int irq, int bus_width) |
1062 | |||
1063 | static int __devinit ace_probe(struct device *device) | ||
1064 | { | 1070 | { |
1065 | struct platform_device *dev = to_platform_device(device); | ||
1066 | struct ace_device *ace; | 1071 | struct ace_device *ace; |
1067 | int i; | 1072 | int rc; |
1073 | dev_dbg(dev, "ace_alloc(%p)\n", dev); | ||
1068 | 1074 | ||
1069 | dev_dbg(device, "ace_probe(%p)\n", device); | 1075 | if (!physaddr) { |
1076 | rc = -ENODEV; | ||
1077 | goto err_noreg; | ||
1078 | } | ||
1070 | 1079 | ||
1071 | /* | 1080 | /* Allocate and initialize the ace device structure */ |
1072 | * Allocate the ace device structure | ||
1073 | */ | ||
1074 | ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL); | 1081 | ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL); |
1075 | if (!ace) | 1082 | if (!ace) { |
1083 | rc = -ENOMEM; | ||
1076 | goto err_alloc; | 1084 | goto err_alloc; |
1077 | |||
1078 | ace->dev = device; | ||
1079 | ace->id = dev->id; | ||
1080 | ace->irq = NO_IRQ; | ||
1081 | |||
1082 | for (i = 0; i < dev->num_resources; i++) { | ||
1083 | if (dev->resource[i].flags & IORESOURCE_MEM) | ||
1084 | ace->physaddr = dev->resource[i].start; | ||
1085 | if (dev->resource[i].flags & IORESOURCE_IRQ) | ||
1086 | ace->irq = dev->resource[i].start; | ||
1087 | } | 1085 | } |
1088 | 1086 | ||
1089 | /* FIXME: Should get bus_width from the platform_device struct */ | 1087 | ace->dev = dev; |
1090 | ace->bus_width = 1; | 1088 | ace->id = id; |
1091 | 1089 | ace->physaddr = physaddr; | |
1092 | dev_set_drvdata(&dev->dev, ace); | 1090 | ace->irq = irq; |
1091 | ace->bus_width = bus_width; | ||
1093 | 1092 | ||
1094 | /* Call the bus-independant setup code */ | 1093 | /* Call the setup code */ |
1095 | if (ace_setup(ace) != 0) | 1094 | rc = ace_setup(ace); |
1095 | if (rc) | ||
1096 | goto err_setup; | 1096 | goto err_setup; |
1097 | 1097 | ||
1098 | dev_set_drvdata(dev, ace); | ||
1098 | return 0; | 1099 | return 0; |
1099 | 1100 | ||
1100 | err_setup: | 1101 | err_setup: |
1101 | dev_set_drvdata(&dev->dev, NULL); | 1102 | dev_set_drvdata(dev, NULL); |
1102 | kfree(ace); | 1103 | kfree(ace); |
1103 | err_alloc: | 1104 | err_alloc: |
1104 | printk(KERN_ERR "xsysace: could not initialize device\n"); | 1105 | err_noreg: |
1105 | return -ENOMEM; | 1106 | dev_err(dev, "could not initialize device, err=%i\n", rc); |
1107 | return rc; | ||
1106 | } | 1108 | } |
1107 | 1109 | ||
1108 | /* | 1110 | static void __devexit ace_free(struct device *dev) |
1109 | * Platform bus remove() method | ||
1110 | */ | ||
1111 | static int __devexit ace_remove(struct device *device) | ||
1112 | { | 1111 | { |
1113 | struct ace_device *ace = dev_get_drvdata(device); | 1112 | struct ace_device *ace = dev_get_drvdata(dev); |
1114 | 1113 | dev_dbg(dev, "ace_free(%p)\n", dev); | |
1115 | dev_dbg(device, "ace_remove(%p)\n", device); | ||
1116 | 1114 | ||
1117 | if (ace) { | 1115 | if (ace) { |
1118 | ace_teardown(ace); | 1116 | ace_teardown(ace); |
1117 | dev_set_drvdata(dev, NULL); | ||
1119 | kfree(ace); | 1118 | kfree(ace); |
1120 | } | 1119 | } |
1120 | } | ||
1121 | |||
1122 | /* --------------------------------------------------------------------- | ||
1123 | * Platform Bus Support | ||
1124 | */ | ||
1125 | |||
1126 | static int __devinit ace_probe(struct platform_device *dev) | ||
1127 | { | ||
1128 | unsigned long physaddr = 0; | ||
1129 | int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */ | ||
1130 | int id = dev->id; | ||
1131 | int irq = NO_IRQ; | ||
1132 | int i; | ||
1121 | 1133 | ||
1134 | dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); | ||
1135 | |||
1136 | for (i = 0; i < dev->num_resources; i++) { | ||
1137 | if (dev->resource[i].flags & IORESOURCE_MEM) | ||
1138 | physaddr = dev->resource[i].start; | ||
1139 | if (dev->resource[i].flags & IORESOURCE_IRQ) | ||
1140 | irq = dev->resource[i].start; | ||
1141 | } | ||
1142 | |||
1143 | /* Call the bus-independant setup code */ | ||
1144 | return ace_alloc(&dev->dev, id, physaddr, irq, bus_width); | ||
1145 | } | ||
1146 | |||
1147 | /* | ||
1148 | * Platform bus remove() method | ||
1149 | */ | ||
1150 | static int __devexit ace_remove(struct platform_device *dev) | ||
1151 | { | ||
1152 | ace_free(&dev->dev); | ||
1122 | return 0; | 1153 | return 0; |
1123 | } | 1154 | } |
1124 | 1155 | ||
1125 | static struct device_driver ace_driver = { | 1156 | static struct platform_driver ace_platform_driver = { |
1126 | .name = "xsysace", | ||
1127 | .bus = &platform_bus_type, | ||
1128 | .probe = ace_probe, | 1157 | .probe = ace_probe, |
1129 | .remove = __devexit_p(ace_remove), | 1158 | .remove = __devexit_p(ace_remove), |
1159 | .driver = { | ||
1160 | .owner = THIS_MODULE, | ||
1161 | .name = "xsysace", | ||
1162 | }, | ||
1163 | }; | ||
1164 | |||
1165 | /* --------------------------------------------------------------------- | ||
1166 | * OF_Platform Bus Support | ||
1167 | */ | ||
1168 | |||
1169 | #if defined(CONFIG_OF) | ||
1170 | static int __devinit | ||
1171 | ace_of_probe(struct of_device *op, const struct of_device_id *match) | ||
1172 | { | ||
1173 | struct resource res; | ||
1174 | unsigned long physaddr; | ||
1175 | const u32 *id; | ||
1176 | int irq, bus_width, rc; | ||
1177 | |||
1178 | dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match); | ||
1179 | |||
1180 | /* device id */ | ||
1181 | id = of_get_property(op->node, "port-number", NULL); | ||
1182 | |||
1183 | /* physaddr */ | ||
1184 | rc = of_address_to_resource(op->node, 0, &res); | ||
1185 | if (rc) { | ||
1186 | dev_err(&op->dev, "invalid address\n"); | ||
1187 | return rc; | ||
1188 | } | ||
1189 | physaddr = res.start; | ||
1190 | |||
1191 | /* irq */ | ||
1192 | irq = irq_of_parse_and_map(op->node, 0); | ||
1193 | |||
1194 | /* bus width */ | ||
1195 | bus_width = ACE_BUS_WIDTH_16; | ||
1196 | if (of_find_property(op->node, "8-bit", NULL)) | ||
1197 | bus_width = ACE_BUS_WIDTH_8; | ||
1198 | |||
1199 | /* Call the bus-independant setup code */ | ||
1200 | return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width); | ||
1201 | } | ||
1202 | |||
1203 | static int __devexit ace_of_remove(struct of_device *op) | ||
1204 | { | ||
1205 | ace_free(&op->dev); | ||
1206 | return 0; | ||
1207 | } | ||
1208 | |||
1209 | /* Match table for of_platform binding */ | ||
1210 | static struct of_device_id __devinit ace_of_match[] = { | ||
1211 | { .compatible = "xilinx,xsysace", }, | ||
1212 | {}, | ||
1213 | }; | ||
1214 | MODULE_DEVICE_TABLE(of, ace_of_match); | ||
1215 | |||
1216 | static struct of_platform_driver ace_of_driver = { | ||
1217 | .owner = THIS_MODULE, | ||
1218 | .name = "xsysace", | ||
1219 | .match_table = ace_of_match, | ||
1220 | .probe = ace_of_probe, | ||
1221 | .remove = __devexit_p(ace_of_remove), | ||
1222 | .driver = { | ||
1223 | .name = "xsysace", | ||
1224 | }, | ||
1130 | }; | 1225 | }; |
1131 | 1226 | ||
1227 | /* Registration helpers to keep the number of #ifdefs to a minimum */ | ||
1228 | static inline int __init ace_of_register(void) | ||
1229 | { | ||
1230 | pr_debug("xsysace: registering OF binding\n"); | ||
1231 | return of_register_platform_driver(&ace_of_driver); | ||
1232 | } | ||
1233 | |||
1234 | static inline void __exit ace_of_unregister(void) | ||
1235 | { | ||
1236 | of_unregister_platform_driver(&ace_of_driver); | ||
1237 | } | ||
1238 | #else /* CONFIG_OF */ | ||
1239 | /* CONFIG_OF not enabled; do nothing helpers */ | ||
1240 | static inline int __init ace_of_register(void) { return 0; } | ||
1241 | static inline void __exit ace_of_unregister(void) { } | ||
1242 | #endif /* CONFIG_OF */ | ||
1243 | |||
1132 | /* --------------------------------------------------------------------- | 1244 | /* --------------------------------------------------------------------- |
1133 | * Module init/exit routines | 1245 | * Module init/exit routines |
1134 | */ | 1246 | */ |
1135 | static int __init ace_init(void) | 1247 | static int __init ace_init(void) |
1136 | { | 1248 | { |
1249 | int rc; | ||
1250 | |||
1137 | ace_major = register_blkdev(ace_major, "xsysace"); | 1251 | ace_major = register_blkdev(ace_major, "xsysace"); |
1138 | if (ace_major <= 0) { | 1252 | if (ace_major <= 0) { |
1139 | printk(KERN_WARNING "xsysace: register_blkdev() failed\n"); | 1253 | rc = -ENOMEM; |
1140 | return ace_major; | 1254 | goto err_blk; |
1141 | } | 1255 | } |
1142 | 1256 | ||
1143 | pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major); | 1257 | rc = ace_of_register(); |
1144 | return driver_register(&ace_driver); | 1258 | if (rc) |
1259 | goto err_of; | ||
1260 | |||
1261 | pr_debug("xsysace: registering platform binding\n"); | ||
1262 | rc = platform_driver_register(&ace_platform_driver); | ||
1263 | if (rc) | ||
1264 | goto err_plat; | ||
1265 | |||
1266 | pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); | ||
1267 | return 0; | ||
1268 | |||
1269 | err_plat: | ||
1270 | ace_of_unregister(); | ||
1271 | err_of: | ||
1272 | unregister_blkdev(ace_major, "xsysace"); | ||
1273 | err_blk: | ||
1274 | printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); | ||
1275 | return rc; | ||
1145 | } | 1276 | } |
1146 | 1277 | ||
1147 | static void __exit ace_exit(void) | 1278 | static void __exit ace_exit(void) |
1148 | { | 1279 | { |
1149 | pr_debug("Unregistering Xilinx SystemACE driver\n"); | 1280 | pr_debug("Unregistering Xilinx SystemACE driver\n"); |
1150 | driver_unregister(&ace_driver); | 1281 | platform_driver_unregister(&ace_platform_driver); |
1282 | ace_of_unregister(); | ||
1151 | unregister_blkdev(ace_major, "xsysace"); | 1283 | unregister_blkdev(ace_major, "xsysace"); |
1152 | } | 1284 | } |
1153 | 1285 | ||