Loading drivers/sbus/char/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ config OBP_FLASH config TADPOLE_TS102_UCTRL tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" depends on EXPERIMENTAL && SPARC32 depends on EXPERIMENTAL help Say Y here to directly support the TS102 Microcontroller interface on the Tadpole Sparcbook 3. This device handles power-management Loading drivers/sbus/char/uctrl.c +120 −96 Original line number Diff line number Diff line /* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $ * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 /* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 * * Copyright 1999 Derrick J Brashear (shadow@dementia.org) * Copyright 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> Loading @@ -14,6 +14,8 @@ #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/of.h> #include <linux/of_device.h> #include <asm/openprom.h> #include <asm/oplib.h> Loading @@ -21,7 +23,6 @@ #include <asm/irq.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/sbus.h> #define UCTRL_MINOR 174 Loading @@ -33,26 +34,26 @@ #endif struct uctrl_regs { volatile u32 uctrl_intr; volatile u32 uctrl_data; volatile u32 uctrl_stat; volatile u32 uctrl_xxx[5]; u32 uctrl_intr; u32 uctrl_data; u32 uctrl_stat; u32 uctrl_xxx[5]; }; struct ts102_regs { volatile u32 card_a_intr; volatile u32 card_a_stat; volatile u32 card_a_ctrl; volatile u32 card_a_xxx; volatile u32 card_b_intr; volatile u32 card_b_stat; volatile u32 card_b_ctrl; volatile u32 card_b_xxx; volatile u32 uctrl_intr; volatile u32 uctrl_data; volatile u32 uctrl_stat; volatile u32 uctrl_xxx; volatile u32 ts102_xxx[4]; u32 card_a_intr; u32 card_a_stat; u32 card_a_ctrl; u32 card_a_xxx; u32 card_b_intr; u32 card_b_stat; u32 card_b_ctrl; u32 card_b_xxx; u32 uctrl_intr; u32 uctrl_data; u32 uctrl_stat; u32 uctrl_xxx; u32 ts102_xxx[4]; }; /* Bits for uctrl_intr register */ Loading Loading @@ -186,17 +187,15 @@ enum uctrl_opcode { POWER_RESTART=0x83, }; struct uctrl_driver { struct uctrl_regs *regs; static struct uctrl_driver { struct uctrl_regs __iomem *regs; int irq; int pending; struct uctrl_status status; }; static struct uctrl_driver drv; } *global_driver; static void uctrl_get_event_status(void); static void uctrl_get_external_status(void); static void uctrl_get_event_status(struct uctrl_driver *); static void uctrl_get_external_status(struct uctrl_driver *); static int uctrl_ioctl(struct inode *inode, struct file *file, Loading @@ -213,16 +212,14 @@ static int uctrl_open(struct inode *inode, struct file *file) { lock_kernel(); uctrl_get_event_status(); uctrl_get_external_status(); uctrl_get_event_status(global_driver); uctrl_get_external_status(global_driver); unlock_kernel(); return 0; } static irqreturn_t uctrl_interrupt(int irq, void *dev_id) { struct uctrl_driver *driver = (struct uctrl_driver *)dev_id; printk("in uctrl_interrupt\n"); return IRQ_HANDLED; } Loading @@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = { { \ unsigned int i; \ for (i = 0; i < 10000; i++) { \ if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \ if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \ break; \ } \ dprintk(("write data 0x%02x\n", value)); \ driver->regs->uctrl_data = value; \ sbus_writel(value, &driver->regs->uctrl_data); \ } /* Wait for something to read, read it, then clear the bit */ Loading @@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = { unsigned int i; \ value = 0; \ for (i = 0; i < 10000; i++) { \ if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \ if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \ break; \ udelay(1); \ } \ value = driver->regs->uctrl_data; \ value = sbus_readl(&driver->regs->uctrl_data); \ dprintk(("read data 0x%02x\n", value)); \ driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \ sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \ } static void uctrl_do_txn(struct uctrl_txn *txn) static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn) { struct uctrl_driver *driver = &drv; int stat, incnt, outcnt, bytecnt, intr; u32 byte; stat = driver->regs->uctrl_stat; intr = driver->regs->uctrl_intr; driver->regs->uctrl_stat = stat; stat = sbus_readl(&driver->regs->uctrl_stat); intr = sbus_readl(&driver->regs->uctrl_intr); sbus_writel(stat, &driver->regs->uctrl_stat); dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr)); Loading Loading @@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn) } } static void uctrl_get_event_status(void) static void uctrl_get_event_status(struct uctrl_driver *driver) { struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; Loading @@ -317,7 +312,7 @@ static void uctrl_get_event_status(void) txn.inbuf = NULL; txn.outbuf = outbits; uctrl_do_txn(&txn); uctrl_do_txn(driver, &txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.event_status = Loading @@ -325,9 +320,8 @@ static void uctrl_get_event_status(void) dprintk(("ev is %x\n", driver->status.event_status)); } static void uctrl_get_external_status(void) static void uctrl_get_external_status(struct uctrl_driver *driver) { struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; int i, v; Loading @@ -338,7 +332,7 @@ static void uctrl_get_external_status(void) txn.inbuf = NULL; txn.outbuf = outbits; uctrl_do_txn(&txn); uctrl_do_txn(driver, &txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.external_status = Loading @@ -354,71 +348,101 @@ static void uctrl_get_external_status(void) } static int __init ts102_uctrl_init(void) static int __devinit uctrl_probe(struct of_device *op, const struct of_device_id *match) { struct uctrl_driver *driver = &drv; int len; struct linux_prom_irqs tmp_irq[2]; unsigned int vaddr[2] = { 0, 0 }; int tmpnode, uctrlnode = prom_getchild(prom_root_node); int err; struct uctrl_driver *p; int err = -ENOMEM; tmpnode = prom_searchsiblings(uctrlnode, "obio"); p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) { printk(KERN_ERR "uctrl: Unable to allocate device struct.\n"); goto out; } if (tmpnode) uctrlnode = prom_getchild(tmpnode); p->regs = of_ioremap(&op->resource[0], 0, resource_size(&op->resource[0]), "uctrl"); if (!p->regs) { printk(KERN_ERR "uctrl: Unable to map registers.\n"); goto out_free; } uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); p->irq = op->irqs[0]; err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p); if (err) { printk(KERN_ERR "uctrl: Unable to register irq.\n"); goto out_iounmap; } if (!uctrlnode) return -ENODEV; err = misc_register(&uctrl_dev); if (err) { printk(KERN_ERR "uctrl: Unable to register misc device.\n"); goto out_free_irq; } /* the prom mapped it for us */ len = prom_getproperty(uctrlnode, "address", (void *) vaddr, sizeof(vaddr)); driver->regs = (struct uctrl_regs *)vaddr[0]; sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr); printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n", op->node->full_name, p->regs, p->irq); uctrl_get_event_status(p); uctrl_get_external_status(p); len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, sizeof(tmp_irq)); dev_set_drvdata(&op->dev, p); global_driver = p; /* Flush device */ READUCTLDATA(len); out: return err; if(!driver->irq) driver->irq = tmp_irq[0].pri; out_free_irq: free_irq(p->irq, p); err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); if (err) { printk("%s: unable to register irq %d\n", __func__, driver->irq); return err; } out_iounmap: of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); if (misc_register(&uctrl_dev)) { printk("%s: unable to get misc minor %d\n", __func__, uctrl_dev.minor); free_irq(driver->irq, driver); return -ENODEV; out_free: kfree(p); goto out; } driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); uctrl_get_event_status(); uctrl_get_external_status(); static int __devexit uctrl_remove(struct of_device *op) { struct uctrl_driver *p = dev_get_drvdata(&op->dev); if (p) { misc_deregister(&uctrl_dev); free_irq(p->irq, p); of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); kfree(p); } return 0; } static void __exit ts102_uctrl_cleanup(void) static struct of_device_id uctrl_match[] = { { struct uctrl_driver *driver = &drv; .name = "uctrl", }, {}, }; MODULE_DEVICE_TABLE(of, uctrl_match); misc_deregister(&uctrl_dev); if (driver->irq) free_irq(driver->irq, driver); if (driver->regs) driver->regs = NULL; static struct of_platform_driver uctrl_driver = { .name = "uctrl", .match_table = uctrl_match, .probe = uctrl_probe, .remove = __devexit_p(uctrl_remove), }; static int __init uctrl_init(void) { return of_register_driver(&uctrl_driver, &of_bus_type); } static void __exit uctrl_exit(void) { of_unregister_driver(&uctrl_driver); } module_init(ts102_uctrl_init); module_exit(ts102_uctrl_cleanup); module_init(uctrl_init); module_exit(uctrl_exit); MODULE_LICENSE("GPL"); Loading
drivers/sbus/char/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ config OBP_FLASH config TADPOLE_TS102_UCTRL tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" depends on EXPERIMENTAL && SPARC32 depends on EXPERIMENTAL help Say Y here to directly support the TS102 Microcontroller interface on the Tadpole Sparcbook 3. This device handles power-management Loading
drivers/sbus/char/uctrl.c +120 −96 Original line number Diff line number Diff line /* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $ * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 /* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 * * Copyright 1999 Derrick J Brashear (shadow@dementia.org) * Copyright 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> Loading @@ -14,6 +14,8 @@ #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/of.h> #include <linux/of_device.h> #include <asm/openprom.h> #include <asm/oplib.h> Loading @@ -21,7 +23,6 @@ #include <asm/irq.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/sbus.h> #define UCTRL_MINOR 174 Loading @@ -33,26 +34,26 @@ #endif struct uctrl_regs { volatile u32 uctrl_intr; volatile u32 uctrl_data; volatile u32 uctrl_stat; volatile u32 uctrl_xxx[5]; u32 uctrl_intr; u32 uctrl_data; u32 uctrl_stat; u32 uctrl_xxx[5]; }; struct ts102_regs { volatile u32 card_a_intr; volatile u32 card_a_stat; volatile u32 card_a_ctrl; volatile u32 card_a_xxx; volatile u32 card_b_intr; volatile u32 card_b_stat; volatile u32 card_b_ctrl; volatile u32 card_b_xxx; volatile u32 uctrl_intr; volatile u32 uctrl_data; volatile u32 uctrl_stat; volatile u32 uctrl_xxx; volatile u32 ts102_xxx[4]; u32 card_a_intr; u32 card_a_stat; u32 card_a_ctrl; u32 card_a_xxx; u32 card_b_intr; u32 card_b_stat; u32 card_b_ctrl; u32 card_b_xxx; u32 uctrl_intr; u32 uctrl_data; u32 uctrl_stat; u32 uctrl_xxx; u32 ts102_xxx[4]; }; /* Bits for uctrl_intr register */ Loading Loading @@ -186,17 +187,15 @@ enum uctrl_opcode { POWER_RESTART=0x83, }; struct uctrl_driver { struct uctrl_regs *regs; static struct uctrl_driver { struct uctrl_regs __iomem *regs; int irq; int pending; struct uctrl_status status; }; static struct uctrl_driver drv; } *global_driver; static void uctrl_get_event_status(void); static void uctrl_get_external_status(void); static void uctrl_get_event_status(struct uctrl_driver *); static void uctrl_get_external_status(struct uctrl_driver *); static int uctrl_ioctl(struct inode *inode, struct file *file, Loading @@ -213,16 +212,14 @@ static int uctrl_open(struct inode *inode, struct file *file) { lock_kernel(); uctrl_get_event_status(); uctrl_get_external_status(); uctrl_get_event_status(global_driver); uctrl_get_external_status(global_driver); unlock_kernel(); return 0; } static irqreturn_t uctrl_interrupt(int irq, void *dev_id) { struct uctrl_driver *driver = (struct uctrl_driver *)dev_id; printk("in uctrl_interrupt\n"); return IRQ_HANDLED; } Loading @@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = { { \ unsigned int i; \ for (i = 0; i < 10000; i++) { \ if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \ if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \ break; \ } \ dprintk(("write data 0x%02x\n", value)); \ driver->regs->uctrl_data = value; \ sbus_writel(value, &driver->regs->uctrl_data); \ } /* Wait for something to read, read it, then clear the bit */ Loading @@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = { unsigned int i; \ value = 0; \ for (i = 0; i < 10000; i++) { \ if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \ if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \ break; \ udelay(1); \ } \ value = driver->regs->uctrl_data; \ value = sbus_readl(&driver->regs->uctrl_data); \ dprintk(("read data 0x%02x\n", value)); \ driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \ sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \ } static void uctrl_do_txn(struct uctrl_txn *txn) static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn) { struct uctrl_driver *driver = &drv; int stat, incnt, outcnt, bytecnt, intr; u32 byte; stat = driver->regs->uctrl_stat; intr = driver->regs->uctrl_intr; driver->regs->uctrl_stat = stat; stat = sbus_readl(&driver->regs->uctrl_stat); intr = sbus_readl(&driver->regs->uctrl_intr); sbus_writel(stat, &driver->regs->uctrl_stat); dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr)); Loading Loading @@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn) } } static void uctrl_get_event_status(void) static void uctrl_get_event_status(struct uctrl_driver *driver) { struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; Loading @@ -317,7 +312,7 @@ static void uctrl_get_event_status(void) txn.inbuf = NULL; txn.outbuf = outbits; uctrl_do_txn(&txn); uctrl_do_txn(driver, &txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.event_status = Loading @@ -325,9 +320,8 @@ static void uctrl_get_event_status(void) dprintk(("ev is %x\n", driver->status.event_status)); } static void uctrl_get_external_status(void) static void uctrl_get_external_status(struct uctrl_driver *driver) { struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; int i, v; Loading @@ -338,7 +332,7 @@ static void uctrl_get_external_status(void) txn.inbuf = NULL; txn.outbuf = outbits; uctrl_do_txn(&txn); uctrl_do_txn(driver, &txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.external_status = Loading @@ -354,71 +348,101 @@ static void uctrl_get_external_status(void) } static int __init ts102_uctrl_init(void) static int __devinit uctrl_probe(struct of_device *op, const struct of_device_id *match) { struct uctrl_driver *driver = &drv; int len; struct linux_prom_irqs tmp_irq[2]; unsigned int vaddr[2] = { 0, 0 }; int tmpnode, uctrlnode = prom_getchild(prom_root_node); int err; struct uctrl_driver *p; int err = -ENOMEM; tmpnode = prom_searchsiblings(uctrlnode, "obio"); p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) { printk(KERN_ERR "uctrl: Unable to allocate device struct.\n"); goto out; } if (tmpnode) uctrlnode = prom_getchild(tmpnode); p->regs = of_ioremap(&op->resource[0], 0, resource_size(&op->resource[0]), "uctrl"); if (!p->regs) { printk(KERN_ERR "uctrl: Unable to map registers.\n"); goto out_free; } uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); p->irq = op->irqs[0]; err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p); if (err) { printk(KERN_ERR "uctrl: Unable to register irq.\n"); goto out_iounmap; } if (!uctrlnode) return -ENODEV; err = misc_register(&uctrl_dev); if (err) { printk(KERN_ERR "uctrl: Unable to register misc device.\n"); goto out_free_irq; } /* the prom mapped it for us */ len = prom_getproperty(uctrlnode, "address", (void *) vaddr, sizeof(vaddr)); driver->regs = (struct uctrl_regs *)vaddr[0]; sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr); printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n", op->node->full_name, p->regs, p->irq); uctrl_get_event_status(p); uctrl_get_external_status(p); len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, sizeof(tmp_irq)); dev_set_drvdata(&op->dev, p); global_driver = p; /* Flush device */ READUCTLDATA(len); out: return err; if(!driver->irq) driver->irq = tmp_irq[0].pri; out_free_irq: free_irq(p->irq, p); err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); if (err) { printk("%s: unable to register irq %d\n", __func__, driver->irq); return err; } out_iounmap: of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); if (misc_register(&uctrl_dev)) { printk("%s: unable to get misc minor %d\n", __func__, uctrl_dev.minor); free_irq(driver->irq, driver); return -ENODEV; out_free: kfree(p); goto out; } driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); uctrl_get_event_status(); uctrl_get_external_status(); static int __devexit uctrl_remove(struct of_device *op) { struct uctrl_driver *p = dev_get_drvdata(&op->dev); if (p) { misc_deregister(&uctrl_dev); free_irq(p->irq, p); of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); kfree(p); } return 0; } static void __exit ts102_uctrl_cleanup(void) static struct of_device_id uctrl_match[] = { { struct uctrl_driver *driver = &drv; .name = "uctrl", }, {}, }; MODULE_DEVICE_TABLE(of, uctrl_match); misc_deregister(&uctrl_dev); if (driver->irq) free_irq(driver->irq, driver); if (driver->regs) driver->regs = NULL; static struct of_platform_driver uctrl_driver = { .name = "uctrl", .match_table = uctrl_match, .probe = uctrl_probe, .remove = __devexit_p(uctrl_remove), }; static int __init uctrl_init(void) { return of_register_driver(&uctrl_driver, &of_bus_type); } static void __exit uctrl_exit(void) { of_unregister_driver(&uctrl_driver); } module_init(ts102_uctrl_init); module_exit(ts102_uctrl_cleanup); module_init(uctrl_init); module_exit(uctrl_exit); MODULE_LICENSE("GPL");