0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/types.h>
0009 #include <linux/ioport.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/errno.h>
0013 #include <linux/slab.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/err.h>
0016 #include <linux/io.h>
0017
0018 #include <linux/mtd/mtd.h>
0019 #include <linux/mtd/map.h>
0020 #include <linux/mtd/partitions.h>
0021 #include <linux/mtd/concat.h>
0022
0023 #include <mach/hardware.h>
0024 #include <linux/sizes.h>
0025 #include <asm/mach/flash.h>
0026
0027 struct sa_subdev_info {
0028 char name[16];
0029 struct map_info map;
0030 struct mtd_info *mtd;
0031 struct flash_platform_data *plat;
0032 };
0033
0034 struct sa_info {
0035 struct mtd_info *mtd;
0036 int num_subdev;
0037 struct sa_subdev_info subdev[];
0038 };
0039
0040 static DEFINE_SPINLOCK(sa1100_vpp_lock);
0041 static int sa1100_vpp_refcnt;
0042 static void sa1100_set_vpp(struct map_info *map, int on)
0043 {
0044 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
0045 unsigned long flags;
0046
0047 spin_lock_irqsave(&sa1100_vpp_lock, flags);
0048 if (on) {
0049 if (++sa1100_vpp_refcnt == 1)
0050 subdev->plat->set_vpp(1);
0051 } else {
0052 if (--sa1100_vpp_refcnt == 0)
0053 subdev->plat->set_vpp(0);
0054 }
0055 spin_unlock_irqrestore(&sa1100_vpp_lock, flags);
0056 }
0057
0058 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
0059 {
0060 if (subdev->mtd)
0061 map_destroy(subdev->mtd);
0062 if (subdev->map.virt)
0063 iounmap(subdev->map.virt);
0064 release_mem_region(subdev->map.phys, subdev->map.size);
0065 }
0066
0067 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
0068 {
0069 unsigned long phys;
0070 unsigned int size;
0071 int ret;
0072
0073 phys = res->start;
0074 size = res->end - phys + 1;
0075
0076
0077
0078
0079
0080 switch (phys) {
0081 default:
0082 printk(KERN_WARNING "SA1100 flash: unknown base address "
0083 "0x%08lx, assuming CS0\n", phys);
0084 fallthrough;
0085 case SA1100_CS0_PHYS:
0086 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
0087 break;
0088
0089 case SA1100_CS1_PHYS:
0090 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
0091 break;
0092 }
0093
0094 if (!request_mem_region(phys, size, subdev->name)) {
0095 ret = -EBUSY;
0096 goto out;
0097 }
0098
0099 if (subdev->plat->set_vpp)
0100 subdev->map.set_vpp = sa1100_set_vpp;
0101
0102 subdev->map.phys = phys;
0103 subdev->map.size = size;
0104 subdev->map.virt = ioremap(phys, size);
0105 if (!subdev->map.virt) {
0106 ret = -ENOMEM;
0107 goto err;
0108 }
0109
0110 simple_map_init(&subdev->map);
0111
0112
0113
0114
0115
0116 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
0117 if (subdev->mtd == NULL) {
0118 ret = -ENXIO;
0119 goto err;
0120 }
0121
0122 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
0123 phys, (unsigned)(subdev->mtd->size >> 20),
0124 subdev->map.bankwidth * 8);
0125
0126 return 0;
0127
0128 err:
0129 sa1100_destroy_subdev(subdev);
0130 out:
0131 return ret;
0132 }
0133
0134 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
0135 {
0136 int i;
0137
0138 if (info->mtd) {
0139 mtd_device_unregister(info->mtd);
0140 if (info->mtd != info->subdev[0].mtd)
0141 mtd_concat_destroy(info->mtd);
0142 }
0143
0144 for (i = info->num_subdev - 1; i >= 0; i--)
0145 sa1100_destroy_subdev(&info->subdev[i]);
0146 kfree(info);
0147
0148 if (plat->exit)
0149 plat->exit();
0150 }
0151
0152 static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
0153 struct flash_platform_data *plat)
0154 {
0155 struct sa_info *info;
0156 int nr, size, i, ret = 0;
0157
0158
0159
0160
0161 for (nr = 0; ; nr++)
0162 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
0163 break;
0164
0165 if (nr == 0) {
0166 ret = -ENODEV;
0167 goto out;
0168 }
0169
0170 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
0171
0172
0173
0174
0175 info = kzalloc(size, GFP_KERNEL);
0176 if (!info) {
0177 ret = -ENOMEM;
0178 goto out;
0179 }
0180
0181 if (plat->init) {
0182 ret = plat->init();
0183 if (ret)
0184 goto err;
0185 }
0186
0187
0188
0189
0190 for (i = 0; i < nr; i++) {
0191 struct sa_subdev_info *subdev = &info->subdev[i];
0192 struct resource *res;
0193
0194 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
0195 if (!res)
0196 break;
0197
0198 subdev->map.name = subdev->name;
0199 sprintf(subdev->name, "%s-%d", plat->name, i);
0200 subdev->plat = plat;
0201
0202 ret = sa1100_probe_subdev(subdev, res);
0203 if (ret)
0204 break;
0205 }
0206
0207 info->num_subdev = i;
0208
0209
0210
0211
0212 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
0213 goto err;
0214
0215
0216
0217
0218
0219
0220 if (info->num_subdev == 1) {
0221 strcpy(info->subdev[0].name, plat->name);
0222 info->mtd = info->subdev[0].mtd;
0223 ret = 0;
0224 } else if (info->num_subdev > 1) {
0225 struct mtd_info **cdev;
0226
0227 cdev = kmalloc_array(nr, sizeof(*cdev), GFP_KERNEL);
0228 if (!cdev) {
0229 ret = -ENOMEM;
0230 goto err;
0231 }
0232
0233
0234
0235
0236 for (i = 0; i < info->num_subdev; i++)
0237 cdev[i] = info->subdev[i].mtd;
0238
0239 info->mtd = mtd_concat_create(cdev, info->num_subdev,
0240 plat->name);
0241 kfree(cdev);
0242 if (info->mtd == NULL) {
0243 ret = -ENXIO;
0244 goto err;
0245 }
0246 }
0247 info->mtd->dev.parent = &pdev->dev;
0248
0249 if (ret == 0)
0250 return info;
0251
0252 err:
0253 sa1100_destroy(info, plat);
0254 out:
0255 return ERR_PTR(ret);
0256 }
0257
0258 static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL };
0259
0260 static int sa1100_mtd_probe(struct platform_device *pdev)
0261 {
0262 struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
0263 struct sa_info *info;
0264 int err;
0265
0266 if (!plat)
0267 return -ENODEV;
0268
0269 info = sa1100_setup_mtd(pdev, plat);
0270 if (IS_ERR(info)) {
0271 err = PTR_ERR(info);
0272 goto out;
0273 }
0274
0275
0276
0277
0278 mtd_device_parse_register(info->mtd, part_probes, NULL, plat->parts,
0279 plat->nr_parts);
0280
0281 platform_set_drvdata(pdev, info);
0282 err = 0;
0283
0284 out:
0285 return err;
0286 }
0287
0288 static int sa1100_mtd_remove(struct platform_device *pdev)
0289 {
0290 struct sa_info *info = platform_get_drvdata(pdev);
0291 struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
0292
0293 sa1100_destroy(info, plat);
0294
0295 return 0;
0296 }
0297
0298 static struct platform_driver sa1100_mtd_driver = {
0299 .probe = sa1100_mtd_probe,
0300 .remove = sa1100_mtd_remove,
0301 .driver = {
0302 .name = "sa1100-mtd",
0303 },
0304 };
0305
0306 module_platform_driver(sa1100_mtd_driver);
0307
0308 MODULE_AUTHOR("Nicolas Pitre");
0309 MODULE_DESCRIPTION("SA1100 CFI map driver");
0310 MODULE_LICENSE("GPL");
0311 MODULE_ALIAS("platform:sa1100-mtd");