diff options
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r-- | drivers/sbus/char/display7seg.c | 251 |
1 files changed, 146 insertions, 105 deletions
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index d8f5c0ca236..2f16d78e92d 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -1,10 +1,7 @@ -/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $ - * - * display7seg - Driver implementation for the 7-segment display - * present on Sun Microsystems CP1400 and CP1500 +/* display7seg.c - Driver implementation for the 7-segment display + * present on Sun Microsystems CP1400 and CP1500 * * Copyright (c) 2000 Eric Brower (ebrower@usa.net) - * */ #include <linux/kernel.h> @@ -16,22 +13,20 @@ #include <linux/miscdevice.h> #include <linux/ioport.h> /* request_region */ #include <linux/smp_lock.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/atomic.h> -#include <asm/ebus.h> /* EBus device */ -#include <asm/oplib.h> /* OpenProm Library */ #include <asm/uaccess.h> /* put_/get_user */ #include <asm/io.h> #include <asm/display7seg.h> #define D7S_MINOR 193 -#define D7S_OBPNAME "display7seg" -#define D7S_DEVNAME "d7s" +#define DRIVER_NAME "d7s" +#define PFX DRIVER_NAME ": " static int sol_compat = 0; /* Solaris compatibility mode */ -#ifdef MODULE - /* Solaris compatibility flag - * The Solaris implementation omits support for several * documented driver features (ref Sun doc 806-0180-03). @@ -46,20 +41,20 @@ static int sol_compat = 0; /* Solaris compatibility mode */ * If you wish the device to operate as under Solaris, * omitting above features, set this parameter to non-zero. */ -module_param - (sol_compat, int, 0); -MODULE_PARM_DESC - (sol_compat, - "Disables documented functionality omitted from Solaris driver"); - -MODULE_AUTHOR - ("Eric Brower <ebrower@usa.net>"); -MODULE_DESCRIPTION - ("7-Segment Display driver for Sun Microsystems CP1400/1500"); +module_param(sol_compat, int, 0); +MODULE_PARM_DESC(sol_compat, + "Disables documented functionality omitted from Solaris driver"); + +MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); +MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE - ("d7s"); -#endif /* ifdef MODULE */ +MODULE_SUPPORTED_DEVICE("d7s"); + +struct d7s { + void __iomem *regs; + bool flipped; +}; +struct d7s *d7s_device; /* * Register block address- see header for details @@ -72,22 +67,6 @@ MODULE_SUPPORTED_DEVICE * FLIP - Inverts display for upside-down mounted board * bits 0-4 - 7-segment display contents */ -static void __iomem* d7s_regs; - -static inline void d7s_free(void) -{ - iounmap(d7s_regs); -} - -static inline int d7s_obpflipped(void) -{ - int opt_node; - - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1); -} - static atomic_t d7s_users = ATOMIC_INIT(0); static int d7s_open(struct inode *inode, struct file *f) @@ -106,12 +85,15 @@ static int d7s_release(struct inode *inode, struct file *f) * are not operating in solaris-compat mode */ if (atomic_dec_and_test(&d7s_users) && !sol_compat) { - int regval = 0; - - regval = readb(d7s_regs); - (0 == d7s_obpflipped()) ? - writeb(regval |= D7S_FLIP, d7s_regs): - writeb(regval &= ~D7S_FLIP, d7s_regs); + struct d7s *p = d7s_device; + u8 regval = 0; + + regval = readb(p->regs); + if (p->flipped) + regval |= D7S_FLIP; + else + regval &= ~D7S_FLIP; + writeb(regval, p->regs); } return 0; @@ -119,9 +101,10 @@ static int d7s_release(struct inode *inode, struct file *f) static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - __u8 regs = readb(d7s_regs); - __u8 ireg = 0; + struct d7s *p = d7s_device; + u8 regs = readb(p->regs); int error = 0; + u8 ireg = 0; if (D7S_MINOR != iminor(file->f_path.dentry->d_inode)) return -ENODEV; @@ -129,18 +112,20 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) lock_kernel(); switch (cmd) { case D7SIOCWR: - /* assign device register values - * we mask-out D7S_FLIP if in sol_compat mode + /* assign device register values we mask-out D7S_FLIP + * if in sol_compat mode */ if (get_user(ireg, (int __user *) arg)) { error = -EFAULT; break; } - if (0 != sol_compat) { - (regs & D7S_FLIP) ? - (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP); + if (sol_compat) { + if (regs & D7S_FLIP) + ireg |= D7S_FLIP; + else + ireg &= ~D7S_FLIP; } - writeb(ireg, d7s_regs); + writeb(ireg, p->regs); break; case D7SIOCRD: @@ -158,9 +143,11 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case D7SIOCTM: /* toggle device mode-- flip display orientation */ - (regs & D7S_FLIP) ? - (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP); - writeb(regs, d7s_regs); + if (regs & D7S_FLIP) + regs &= ~D7S_FLIP; + else + regs |= D7S_FLIP; + writeb(regs, p->regs); break; }; unlock_kernel(); @@ -176,69 +163,123 @@ static const struct file_operations d7s_fops = { .release = d7s_release, }; -static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops }; +static struct miscdevice d7s_miscdev = { + .minor = D7S_MINOR, + .name = DRIVER_NAME, + .fops = &d7s_fops +}; -static int __init d7s_init(void) +static int __devinit d7s_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - int iTmp = 0, regs = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, D7S_OBPNAME)) - goto ebus_done; - } + struct device_node *opts; + int err = -EINVAL; + struct d7s *p; + u8 regs; + + if (d7s_device) + goto out; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + err = -ENOMEM; + if (!p) + goto out; + + p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s"); + if (!p->regs) { + printk(KERN_ERR PFX "Cannot map chip registers\n"); + goto out_free; } -ebus_done: - if(!edev) { - printk("%s: unable to locate device\n", D7S_DEVNAME); - return -ENODEV; + err = misc_register(&d7s_miscdev); + if (err) { + printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n", + D7S_MINOR); + goto out_iounmap; } - d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8)); - - iTmp = misc_register(&d7s_miscdev); - if (0 != iTmp) { - printk("%s: unable to acquire miscdevice minor %i\n", - D7S_DEVNAME, D7S_MINOR); - iounmap(d7s_regs); - return iTmp; - } - - /* OBP option "d7s-flipped?" is honored as default - * for the device, and reset default when detached + /* OBP option "d7s-flipped?" is honored as default for the + * device, and reset default when detached */ - regs = readb(d7s_regs); - iTmp = d7s_obpflipped(); - (0 == iTmp) ? - writeb(regs |= D7S_FLIP, d7s_regs): - writeb(regs &= ~D7S_FLIP, d7s_regs); - - printk("%s: 7-Segment Display%s at 0x%lx %s\n", - D7S_DEVNAME, - (0 == iTmp) ? (" (FLIPPED)") : (""), - edev->resource[0].start, - (0 != sol_compat) ? ("in sol_compat mode") : ("")); - - return 0; + regs = readb(p->regs); + opts = of_find_node_by_path("/options"); + if (opts && + of_get_property(opts, "d7s-flipped?", NULL)) + p->flipped = true; + + if (p->flipped) + regs |= D7S_FLIP; + else + regs &= ~D7S_FLIP; + + writeb(regs, p->regs); + + printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n", + op->node->full_name, + (regs & D7S_FLIP) ? " (FLIPPED)" : "", + op->resource[0].start, + sol_compat ? "in sol_compat mode" : ""); + + dev_set_drvdata(&op->dev, p); + d7s_device = p; + err = 0; + +out: + return err; + +out_iounmap: + of_iounmap(&op->resource[0], p->regs, sizeof(u8)); + +out_free: + kfree(p); + goto out; } -static void __exit d7s_cleanup(void) +static int __devexit d7s_remove(struct of_device *op) { - int regs = readb(d7s_regs); + struct d7s *p = dev_get_drvdata(&op->dev); + u8 regs = readb(p->regs); /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */ - if (0 == sol_compat) { - (0 == d7s_obpflipped()) ? - writeb(regs |= D7S_FLIP, d7s_regs): - writeb(regs &= ~D7S_FLIP, d7s_regs); + if (sol_compat) { + if (p->flipped) + regs |= D7S_FLIP; + else + regs &= ~D7S_FLIP; + writeb(regs, p->regs); } misc_deregister(&d7s_miscdev); - d7s_free(); + of_iounmap(&op->resource[0], p->regs, sizeof(u8)); + kfree(p); + + return 0; +} + +static struct of_device_id d7s_match[] = { + { + .name = "display7seg", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, d7s_match); + +static struct of_platform_driver d7s_driver = { + .name = DRIVER_NAME, + .match_table = d7s_match, + .probe = d7s_probe, + .remove = __devexit_p(d7s_remove), +}; + +static int __init d7s_init(void) +{ + return of_register_driver(&d7s_driver, &of_bus_type); +} + +static void __exit d7s_exit(void) +{ + of_unregister_driver(&d7s_driver); } module_init(d7s_init); -module_exit(d7s_cleanup); +module_exit(d7s_exit); |