10e52fe8cSDavid S. Miller /* sun_uflash.c - Driver for user-programmable flash on 20e52fe8cSDavid S. Miller * Sun Microsystems SME boardsets. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This driver does NOT provide access to the OBP-flash for 51da177e4SLinus Torvalds * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Copyright (c) 2001 Eric Brower (ebrower@usa.net) 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/kernel.h> 111da177e4SLinus Torvalds #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/fs.h> 131da177e4SLinus Torvalds #include <linux/errno.h> 141da177e4SLinus Torvalds #include <linux/init.h> 151da177e4SLinus Torvalds #include <linux/ioport.h> 160e52fe8cSDavid S. Miller #include <linux/of.h> 170e52fe8cSDavid S. Miller #include <linux/of_device.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 1929f7ac7eSDavid S. Miller #include <asm/prom.h> 201da177e4SLinus Torvalds #include <asm/uaccess.h> 211da177e4SLinus Torvalds #include <asm/io.h> 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 241da177e4SLinus Torvalds #include <linux/mtd/map.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #define UFLASH_OBPNAME "flashprom" 270e52fe8cSDavid S. Miller #define DRIVER_NAME "sun_uflash" 280e52fe8cSDavid S. Miller #define PFX DRIVER_NAME ": " 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #define UFLASH_WINDOW_SIZE 0x200000 311da177e4SLinus Torvalds #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ 321da177e4SLinus Torvalds 3329f7ac7eSDavid S. Miller MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); 3429f7ac7eSDavid S. Miller MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); 350e52fe8cSDavid S. Miller MODULE_SUPPORTED_DEVICE(DRIVER_NAME); 3629f7ac7eSDavid S. Miller MODULE_LICENSE("GPL"); 370e52fe8cSDavid S. Miller MODULE_VERSION("2.1"); 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds struct uflash_dev { 40ccf0dec6SStephen Rothwell const char *name; /* device name */ 411da177e4SLinus Torvalds struct map_info map; /* mtd map info */ 421da177e4SLinus Torvalds struct mtd_info *mtd; /* mtd info */ 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds struct map_info uflash_map_templ = { 461da177e4SLinus Torvalds .name = "SUNW,???-????", 471da177e4SLinus Torvalds .size = UFLASH_WINDOW_SIZE, 481da177e4SLinus Torvalds .bankwidth = UFLASH_BUSWIDTH, 491da177e4SLinus Torvalds }; 501da177e4SLinus Torvalds 512dc11581SGrant Likely int uflash_devinit(struct platform_device *op, struct device_node *dp) 521da177e4SLinus Torvalds { 5329f7ac7eSDavid S. Miller struct uflash_dev *up; 541da177e4SLinus Torvalds 550e52fe8cSDavid S. Miller if (op->resource[1].flags) { 561da177e4SLinus Torvalds /* Non-CFI userflash device-- once I find one we 571da177e4SLinus Torvalds * can work on supporting it. 581da177e4SLinus Torvalds */ 590e52fe8cSDavid S. Miller printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n", 600e52fe8cSDavid S. Miller dp->full_name, (unsigned long long)op->resource[0].start); 6129f7ac7eSDavid S. Miller 621da177e4SLinus Torvalds return -ENODEV; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 6529f7ac7eSDavid S. Miller up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); 660e52fe8cSDavid S. Miller if (!up) { 670e52fe8cSDavid S. Miller printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n"); 6829f7ac7eSDavid S. Miller return -ENOMEM; 690e52fe8cSDavid S. Miller } 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds /* copy defaults and tweak parameters */ 7229f7ac7eSDavid S. Miller memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); 730e52fe8cSDavid S. Miller 740e52fe8cSDavid S. Miller up->map.size = resource_size(&op->resource[0]); 751da177e4SLinus Torvalds 7629f7ac7eSDavid S. Miller up->name = of_get_property(dp, "model", NULL); 7729f7ac7eSDavid S. Miller if (up->name && 0 < strlen(up->name)) 78ccf0dec6SStephen Rothwell up->map.name = (char *)up->name; 7929f7ac7eSDavid S. Miller 800e52fe8cSDavid S. Miller up->map.phys = op->resource[0].start; 8129f7ac7eSDavid S. Miller 820e52fe8cSDavid S. Miller up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size, 830e52fe8cSDavid S. Miller DRIVER_NAME); 8429f7ac7eSDavid S. Miller if (!up->map.virt) { 850e52fe8cSDavid S. Miller printk(KERN_ERR PFX "Failed to map device.\n"); 8629f7ac7eSDavid S. Miller kfree(up); 8729f7ac7eSDavid S. Miller 8829f7ac7eSDavid S. Miller return -EINVAL; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 9129f7ac7eSDavid S. Miller simple_map_init(&up->map); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* MTD registration */ 9429f7ac7eSDavid S. Miller up->mtd = do_map_probe("cfi_probe", &up->map); 9529f7ac7eSDavid S. Miller if (!up->mtd) { 960e52fe8cSDavid S. Miller of_iounmap(&op->resource[0], up->map.virt, up->map.size); 9729f7ac7eSDavid S. Miller kfree(up); 9829f7ac7eSDavid S. Miller 9929f7ac7eSDavid S. Miller return -ENXIO; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 10229f7ac7eSDavid S. Miller up->mtd->owner = THIS_MODULE; 1031da177e4SLinus Torvalds 10429f7ac7eSDavid S. Miller add_mtd_device(up->mtd); 1051da177e4SLinus Torvalds 1060e52fe8cSDavid S. Miller dev_set_drvdata(&op->dev, up); 10729f7ac7eSDavid S. Miller 10829f7ac7eSDavid S. Miller return 0; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 111*1c48a5c9SGrant Likely static int __devinit uflash_probe(struct platform_device *op) 11229f7ac7eSDavid S. Miller { 11361c7a080SGrant Likely struct device_node *dp = op->dev.of_node; 11429f7ac7eSDavid S. Miller 1150e52fe8cSDavid S. Miller /* Flashprom must have the "user" property in order to 1160e52fe8cSDavid S. Miller * be used by this driver. 1170e52fe8cSDavid S. Miller */ 1180e52fe8cSDavid S. Miller if (!of_find_property(dp, "user", NULL)) 11929f7ac7eSDavid S. Miller return -ENODEV; 12029f7ac7eSDavid S. Miller 1210e52fe8cSDavid S. Miller return uflash_devinit(op, dp); 12229f7ac7eSDavid S. Miller } 12329f7ac7eSDavid S. Miller 1242dc11581SGrant Likely static int __devexit uflash_remove(struct platform_device *op) 12529f7ac7eSDavid S. Miller { 1260e52fe8cSDavid S. Miller struct uflash_dev *up = dev_get_drvdata(&op->dev); 12729f7ac7eSDavid S. Miller 12829f7ac7eSDavid S. Miller if (up->mtd) { 12929f7ac7eSDavid S. Miller del_mtd_device(up->mtd); 13029f7ac7eSDavid S. Miller map_destroy(up->mtd); 13129f7ac7eSDavid S. Miller } 13229f7ac7eSDavid S. Miller if (up->map.virt) { 1330e52fe8cSDavid S. Miller of_iounmap(&op->resource[0], up->map.virt, up->map.size); 13429f7ac7eSDavid S. Miller up->map.virt = NULL; 13529f7ac7eSDavid S. Miller } 13629f7ac7eSDavid S. Miller 13729f7ac7eSDavid S. Miller kfree(up); 13829f7ac7eSDavid S. Miller 13929f7ac7eSDavid S. Miller return 0; 14029f7ac7eSDavid S. Miller } 14129f7ac7eSDavid S. Miller 142fd098316SDavid S. Miller static const struct of_device_id uflash_match[] = { 14329f7ac7eSDavid S. Miller { 14429f7ac7eSDavid S. Miller .name = UFLASH_OBPNAME, 14529f7ac7eSDavid S. Miller }, 14629f7ac7eSDavid S. Miller {}, 14729f7ac7eSDavid S. Miller }; 14829f7ac7eSDavid S. Miller 14929f7ac7eSDavid S. Miller MODULE_DEVICE_TABLE(of, uflash_match); 15029f7ac7eSDavid S. Miller 151*1c48a5c9SGrant Likely static struct platform_driver uflash_driver = { 1524018294bSGrant Likely .driver = { 1530e52fe8cSDavid S. Miller .name = DRIVER_NAME, 1544018294bSGrant Likely .owner = THIS_MODULE, 1554018294bSGrant Likely .of_match_table = uflash_match, 1564018294bSGrant Likely }, 15729f7ac7eSDavid S. Miller .probe = uflash_probe, 15829f7ac7eSDavid S. Miller .remove = __devexit_p(uflash_remove), 15929f7ac7eSDavid S. Miller }; 16029f7ac7eSDavid S. Miller 1611da177e4SLinus Torvalds static int __init uflash_init(void) 1621da177e4SLinus Torvalds { 163*1c48a5c9SGrant Likely return platform_driver_register(&uflash_driver); 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 16629f7ac7eSDavid S. Miller static void __exit uflash_exit(void) 1671da177e4SLinus Torvalds { 168*1c48a5c9SGrant Likely platform_driver_unregister(&uflash_driver); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds module_init(uflash_init); 17229f7ac7eSDavid S. Miller module_exit(uflash_exit); 173