diff options
Diffstat (limited to 'drivers')
72 files changed, 3677 insertions, 5893 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index f17cd4b572f..78fbec8ceda 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -7,7 +7,6 @@ menuconfig ATA depends on HAS_IOMEM depends on BLOCK depends on !(M32R || M68K) || BROKEN - depends on !SUN4 || BROKEN select SCSI ---help--- If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 73338d231db..937c9c0ef4c 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -47,8 +47,9 @@ #include <asm/atomic.h> #ifdef CONFIG_SBUS +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/pgtable.h> @@ -661,249 +662,189 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page) #ifdef CONFIG_SBUS -static u32 -fore200e_sba_read(volatile u32 __iomem *addr) +static u32 fore200e_sba_read(volatile u32 __iomem *addr) { return sbus_readl(addr); } - -static void -fore200e_sba_write(u32 val, volatile u32 __iomem *addr) +static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr) { sbus_writel(val, addr); } - -static u32 -fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) +static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction) { - u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction); + struct of_device *op = fore200e->bus_dev; + u32 dma_addr; - DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", - virt_addr, size, direction, dma_addr); + dma_addr = dma_map_single(&op->dev, virt_addr, size, direction); + + DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", + virt_addr, size, direction, dma_addr); - return dma_addr; + return dma_addr; } - -static void -fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", - dma_addr, size, direction); + struct of_device *op = fore200e->bus_dev; - sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); -} + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", + dma_addr, size, direction); + dma_unmap_single(&op->dev, dma_addr, size, direction); +} -static void -fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); + struct of_device *op = fore200e->bus_dev; + + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); + dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction); } -static void -fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - - sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); -} + struct of_device *op = fore200e->bus_dev; + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); -/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism - (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + dma_sync_single_for_device(&op->dev, dma_addr, size, direction); +} -static int -fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, - int size, int nbr, int alignment) +/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism + * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter. + */ +static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, + int size, int nbr, int alignment) { - chunk->alloc_size = chunk->align_size = size * nbr; + struct of_device *op = fore200e->bus_dev; - /* returned chunks are page-aligned */ - chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev, - chunk->alloc_size, - &chunk->dma_addr); + chunk->alloc_size = chunk->align_size = size * nbr; - if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) - return -ENOMEM; + /* returned chunks are page-aligned */ + chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size, + &chunk->dma_addr, GFP_ATOMIC); - chunk->align_addr = chunk->alloc_addr; + if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; - return 0; + return 0; } - /* free a DVMA consistent chunk of memory */ - -static void -fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk) { - sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev, - chunk->alloc_size, - chunk->alloc_addr, - chunk->dma_addr); -} + struct of_device *op = fore200e->bus_dev; + dma_free_coherent(&op->dev, chunk->alloc_size, + chunk->alloc_addr, chunk->dma_addr); +} -static void -fore200e_sba_irq_enable(struct fore200e* fore200e) +static void fore200e_sba_irq_enable(struct fore200e *fore200e) { - u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; - fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); } - -static int -fore200e_sba_irq_check(struct fore200e* fore200e) +static int fore200e_sba_irq_check(struct fore200e *fore200e) { - return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; + return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; } - -static void -fore200e_sba_irq_ack(struct fore200e* fore200e) +static void fore200e_sba_irq_ack(struct fore200e *fore200e) { - u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; - fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); } - -static void -fore200e_sba_reset(struct fore200e* fore200e) +static void fore200e_sba_reset(struct fore200e *fore200e) { - fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); - fore200e_spin(10); - fore200e->bus->write(0, fore200e->regs.sba.hcr); + fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); + fore200e_spin(10); + fore200e->bus->write(0, fore200e->regs.sba.hcr); } - -static int __init -fore200e_sba_map(struct fore200e* fore200e) +static int __init fore200e_sba_map(struct fore200e *fore200e) { - struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; - unsigned int bursts; + struct of_device *op = fore200e->bus_dev; + unsigned int bursts; - /* gain access to the SBA specific registers */ - fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); - fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); - fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); - fore200e->virt_base = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); + /* gain access to the SBA specific registers */ + fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); + fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); + fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); + fore200e->virt_base = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); - if (fore200e->virt_base == NULL) { - printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); - return -EFAULT; - } + if (!fore200e->virt_base) { + printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); + return -EFAULT; + } - DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); - fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ + fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ - /* get the supported DVMA burst sizes */ - bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00); + /* get the supported DVMA burst sizes */ + bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00); - if (sbus_can_dma_64bit(sbus_dev)) - sbus_set_sbus64(sbus_dev, bursts); + if (sbus_can_dma_64bit()) + sbus_set_sbus64(&op->dev, bursts); - fore200e->state = FORE200E_STATE_MAP; - return 0; + fore200e->state = FORE200E_STATE_MAP; + return 0; } - -static void -fore200e_sba_unmap(struct fore200e* fore200e) +static void fore200e_sba_unmap(struct fore200e *fore200e) { - sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); - sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); - sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); - sbus_iounmap(fore200e->virt_base, SBA200E_RAM_LENGTH); -} + struct of_device *op = fore200e->bus_dev; + of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); + of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); + of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); + of_iounmap(&op->resource[3], fore200e->virt_base, SBA200E_RAM_LENGTH); +} -static int __init -fore200e_sba_configure(struct fore200e* fore200e) +static int __init fore200e_sba_configure(struct fore200e *fore200e) { - fore200e->state = FORE200E_STATE_CONFIGURE; - return 0; + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; } - -static struct fore200e* __init -fore200e_sba_detect(const struct fore200e_bus* bus, int index) +static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom) { - struct fore200e* fore200e; - struct sbus_bus* sbus_bus; - struct sbus_dev* sbus_dev = NULL; - - unsigned int count = 0; - - for_each_sbus (sbus_bus) { - for_each_sbusdev (sbus_dev, sbus_bus) { - if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { - if (count >= index) - goto found; - count++; - } - } - } - return NULL; - - found: - if (sbus_dev->num_registers != 4) { - printk(FORE200E "this %s device has %d instead of 4 registers\n", - bus->model_name, sbus_dev->num_registers); - return NULL; - } - - fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); - if (fore200e == NULL) - return NULL; + struct of_device *op = fore200e->bus_dev; + const u8 *prop; + int len; - fore200e->bus = bus; - fore200e->bus_dev = sbus_dev; - fore200e->irq = sbus_dev->irqs[ 0 ]; + prop = of_get_property(op->node, "madaddrlo2", &len); + if (!prop) + return -ENODEV; + memcpy(&prom->mac_addr[4], prop, 4); - fore200e->phys_base = (unsigned long)sbus_dev; + prop = of_get_property(op->node, "madaddrhi4", &len); + if (!prop) + return -ENODEV; + memcpy(&prom->mac_addr[2], prop, 4); - sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0); + prom->hw_revision = of_getintprop_default(op->node, "promversion", 0); - return fore200e; + return 0; } - -static int __init -fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom) +static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page) { - struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev; - int len; - - len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); - if (len < 0) - return -EBUSY; - - len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); - if (len < 0) - return -EBUSY; - - prom_getproperty(sbus_dev->prom_node, "serialnumber", - (char*)&prom->serial_number, sizeof(prom->serial_number)); - - prom_getproperty(sbus_dev->prom_node, "promversion", - (char*)&prom->hw_revision, sizeof(prom->hw_revision)); - - return 0; -} + struct of_device *op = fore200e->bus_dev; + const struct linux_prom_registers *regs; + regs = of_get_property(op->node, "reg", NULL); -static int -fore200e_sba_proc_read(struct fore200e* fore200e, char *page) -{ - struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; - - return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); + return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", + (regs ? regs->which_io : 0), op->node->name); } #endif /* CONFIG_SBUS */ @@ -2572,7 +2513,7 @@ fore200e_load_and_start_fw(struct fore200e* fore200e) device = &((struct pci_dev *) fore200e->bus_dev)->dev; #ifdef CONFIG_SBUS else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0) - device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev; + device = &((struct of_device *) fore200e->bus_dev)->dev; #endif else return err; @@ -2701,6 +2642,66 @@ fore200e_init(struct fore200e* fore200e) return 0; } +#ifdef CONFIG_SBUS +static int __devinit fore200e_sba_probe(struct of_device *op, + const struct of_device_id *match) +{ + const struct fore200e_bus *bus = match->data; + struct fore200e *fore200e; + static int index = 0; + int err; + + fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); + if (!fore200e) + return -ENOMEM; + + fore200e->bus = bus; + fore200e->bus_dev = op; + fore200e->irq = op->irqs[0]; + fore200e->phys_base = op->resource[0].start; + + sprintf(fore200e->name, "%s-%d", bus->model_name, index); + + err = fore200e_init(fore200e); + if (err < 0) { + fore200e_shutdown(fore200e); + kfree(fore200e); + return err; + } + + index++; + dev_set_drvdata(&op->dev, fore200e); + + return 0; +} + +static int __devexit fore200e_sba_remove(struct of_device *op) +{ + struct fore200e *fore200e = dev_get_drvdata(&op->dev); + + fore200e_shutdown(fore200e); + kfree(fore200e); + + return 0; +} + +static const struct of_device_id fore200e_sba_match[] = { + { + .name = SBA200E_PROM_NAME, + .data = (void *) &fore200e_bus[1], + }, + {}, +}; +MODULE_DEVICE_TABLE(of, fore200e_sba_match); + +static struct of_platform_driver fore200e_sba_driver = { + .name = "fore_200e", + .match_table = fore200e_sba_match, + .probe = fore200e_sba_probe, + .remove = __devexit_p(fore200e_sba_remove), +}; +#endif + #ifdef CONFIG_PCI static int __devinit fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) @@ -2784,67 +2785,40 @@ static struct pci_driver fore200e_pca_driver = { }; #endif - -static int __init -fore200e_module_init(void) +static int __init fore200e_module_init(void) { - const struct fore200e_bus* bus; - struct fore200e* fore200e; - int index; - - printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); + int err; - /* for each configured bus interface */ - for (bus = fore200e_bus; bus->model_name; bus++) { + printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); - /* detect all boards present on that bus */ - for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) { - - printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", - fore200e->bus->model_name, - fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); - - sprintf(fore200e->name, "%s-%d", bus->model_name, index); - - if (fore200e_init(fore200e) < 0) { - - fore200e_shutdown(fore200e); - break; - } - - list_add(&fore200e->entry, &fore200e_boards); - } - } +#ifdef CONFIG_SBUS + err = of_register_driver(&fore200e_sba_driver, &of_bus_type); + if (err) + return err; +#endif #ifdef CONFIG_PCI - if (!pci_register_driver(&fore200e_pca_driver)) - return 0; + err = pci_register_driver(&fore200e_pca_driver); #endif - if (!list_empty(&fore200e_boards)) - return 0; +#ifdef CONFIG_SBUS + if (err) + of_unregister_driver(&fore200e_sba_driver); +#endif - return -ENODEV; + return err; } - -static void __exit -fore200e_module_cleanup(void) +static void __exit fore200e_module_cleanup(void) { - struct fore200e *fore200e, *next; - #ifdef CONFIG_PCI - pci_unregister_driver(&fore200e_pca_driver); + pci_unregister_driver(&fore200e_pca_driver); +#endif +#ifdef CONFIG_SBUS + of_unregister_driver(&fore200e_sba_driver); #endif - - list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) { - fore200e_shutdown(fore200e); - kfree(fore200e); - } - DPRINTK(1, "module being removed\n"); } - static int fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) { @@ -3163,7 +3137,6 @@ static const struct fore200e_bus fore200e_bus[] = { fore200e_pca_dma_sync_for_device, fore200e_pca_dma_chunk_alloc, fore200e_pca_dma_chunk_free, - NULL, fore200e_pca_configure, fore200e_pca_map, fore200e_pca_reset, @@ -3185,7 +3158,6 @@ static const struct fore200e_bus fore200e_bus[] = { fore200e_sba_dma_sync_for_device, fore200e_sba_dma_chunk_alloc, fore200e_sba_dma_chunk_free, - fore200e_sba_detect, fore200e_sba_configure, fore200e_sba_map, fore200e_sba_reset, diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index 5c6e7adcb19..7f97c09aaea 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -778,9 +778,9 @@ typedef struct fore200e_pca_regs { /* SBA-200E registers */ typedef struct fore200e_sba_regs { - volatile u32 __iomem *hcr; /* address of host control register */ - volatile u32 __iomem *bsr; /* address of burst transfer size register */ - volatile u32 __iomem *isr; /* address of interrupt level selection register */ + u32 __iomem *hcr; /* address of host control register */ + u32 __iomem *bsr; /* address of burst transfer size register */ + u32 __iomem *isr; /* address of interrupt level selection register */ } fore200e_sba_regs_t; @@ -810,7 +810,6 @@ typedef struct fore200e_bus { void (*dma_sync_for_device)(struct fore200e*, u32, int, int); int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); void (*dma_chunk_free)(struct fore200e*, struct chunk*); - struct fore200e* (*detect)(const struct fore200e_bus*, int); int (*configure)(struct fore200e*); int (*map)(struct fore200e*); void (*reset)(struct fore200e*); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index a8de037ecd4..953c0b83d75 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -1,6 +1,6 @@ /* sunvdc.c: Sun LDOM Virtual Disk Client. * - * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> */ #include <linux/module.h> @@ -834,7 +834,7 @@ static int vdc_port_remove(struct vio_dev *vdev) return 0; } -static struct vio_device_id vdc_port_match[] = { +static const struct vio_device_id vdc_port_match[] = { { .type = "vdc-port", }, diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 5220f541df2..8859aeac2d2 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -736,7 +736,7 @@ static int __devexit n2rng_remove(struct of_device *op) return 0; } -static struct of_device_id n2rng_match[] = { +static const struct of_device_id n2rng_match[] = { { .name = "random-number-generator", .compatible = "SUNW,n2-rng", diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index f53d4d00faf..b47710c1788 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -88,12 +88,12 @@ #endif #ifdef CONFIG_SPARC32 -#include <linux/pci.h> -#include <linux/jiffies.h> -#include <asm/ebus.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <asm/io.h> static unsigned long rtc_port; -static int rtc_irq = PCI_IRQ_NONE; +static int rtc_irq; #endif #ifdef CONFIG_HPET_RTC_IRQ @@ -973,8 +973,8 @@ static int __init rtc_init(void) char *guess = NULL; #endif #ifdef CONFIG_SPARC32 - struct linux_ebus *ebus; - struct linux_ebus_device *edev; + struct device_node *ebus_dp; + struct of_device *op; #else void *r; #ifdef RTC_IRQ @@ -983,12 +983,16 @@ static int __init rtc_init(void) #endif #ifdef CONFIG_SPARC32 - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (strcmp(edev->prom_node->name, "rtc") == 0) { - rtc_port = edev->resource[0].start; - rtc_irq = edev->irqs[0]; - goto found; + for_each_node_by_name(ebus_dp, "ebus") { + struct device_node *dp; + for (dp = ebus_dp; dp; dp = dp->sibling) { + if (!strcmp(dp->name, "rtc")) { + op = of_find_device_by_node(dp); + if (op) { + rtc_port = op->resource[0].start; + rtc_irq = op->irqs[0]; + goto found; + } } } } @@ -997,7 +1001,7 @@ static int __init rtc_init(void) return -EIO; found: - if (rtc_irq == PCI_IRQ_NONE) { + if (!rtc_irq) { rtc_has_irq = 0; goto no_irq; } diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3309e862f31..ebacc0af40f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -800,6 +800,13 @@ config SENSORS_W83627EHF This driver can also be built as a module. If so, the module will be called w83627ehf. +config SENSORS_ULTRA45 + tristate "Sun Ultra45 PIC16F747" + depends on SPARC64 + help + This driver provides support for the Ultra45 workstation environmental + sensors. + config SENSORS_HDAPS tristate "IBM Hard Drive Active Protection System (hdaps)" depends on INPUT && X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 6babc801b34..042d5a78622 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o +obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c new file mode 100644 index 00000000000..68e90abeba9 --- /dev/null +++ b/drivers/hwmon/ultra45_env.c @@ -0,0 +1,320 @@ +/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor. + * + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/of_device.h> +#include <linux/io.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> + +#define DRV_MODULE_VERSION "0.1" + +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("Ultra45 environmental monitor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +/* PIC device registers */ +#define REG_CMD 0x00UL +#define REG_CMD_RESET 0x80 +#define REG_CMD_ESTAR 0x01 +#define REG_STAT 0x01UL +#define REG_STAT_FWVER 0xf0 +#define REG_STAT_TGOOD 0x08 +#define REG_STAT_STALE 0x04 +#define REG_STAT_BUSY 0x02 +#define REG_STAT_FAULT 0x01 +#define REG_DATA 0x40UL +#define REG_ADDR 0x41UL +#define REG_SIZE 0x42UL + +/* Registers accessed indirectly via REG_DATA/REG_ADDR */ +#define IREG_FAN0 0x00 +#define IREG_FAN1 0x01 +#define IREG_FAN2 0x02 +#define IREG_FAN3 0x03 +#define IREG_FAN4 0x04 +#define IREG_FAN5 0x05 +#define IREG_LCL_TEMP 0x06 +#define IREG_RMT1_TEMP 0x07 +#define IREG_RMT2_TEMP 0x08 +#define IREG_RMT3_TEMP 0x09 +#define IREG_LM95221_TEMP 0x0a +#define IREG_FIRE_TEMP 0x0b +#define IREG_LSI1064_TEMP 0x0c +#define IREG_FRONT_TEMP 0x0d +#define IREG_FAN_STAT 0x0e +#define IREG_VCORE0 0x0f +#define IREG_VCORE1 0x10 +#define IREG_VMEM0 0x11 +#define IREG_VMEM1 0x12 +#define IREG_PSU_TEMP 0x13 + +struct env { + void __iomem *regs; + spinlock_t lock; + + struct device *hwmon_dev; +}; + +static u8 env_read(struct env *p, u8 ireg) +{ + u8 ret; + + spin_lock(&p->lock); + writeb(ireg, p->regs + REG_ADDR); + ret = readb(p->regs + REG_DATA); + spin_unlock(&p->lock); + + return ret; +} + +static void env_write(struct env *p, u8 ireg, u8 val) +{ + spin_lock(&p->lock); + writeb(ireg, p->regs + REG_ADDR); + writeb(val, p->regs + REG_DATA); + spin_unlock(&p->lock); +} + +/* There seems to be a adr7462 providing these values, thus a lot + * of these calculations are borrowed from the adt7470 driver. + */ +#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) +#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM +#define FAN_PERIOD_INVALID (0xff << 8) +#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) + +static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf) +{ + int fan_nr = to_sensor_dev_attr(attr)->index; + struct env *p = dev_get_drvdata(dev); + int rpm, period; + u8 val; + + val = env_read(p, IREG_FAN0 + fan_nr); + period = (int) val << 8; + if (FAN_DATA_VALID(period)) + rpm = FAN_PERIOD_TO_RPM(period); + else + rpm = 0; + + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int fan_nr = to_sensor_dev_attr(attr)->index; + int rpm = simple_strtol(buf, NULL, 10); + struct env *p = dev_get_drvdata(dev); + int period; + u8 val; + + if (!rpm) + return -EINVAL; + + period = FAN_RPM_TO_PERIOD(rpm); + val = period >> 8; + env_write(p, IREG_FAN0 + fan_nr, val); + + return count; +} + +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf) +{ + int fan_nr = to_sensor_dev_attr(attr)->index; + struct env *p = dev_get_drvdata(dev); + u8 val = env_read(p, IREG_FAN_STAT); + return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0); +} + +#define fan(index) \ +static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR, \ + show_fan_speed, set_fan_speed, index); \ +static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, \ + show_fan_fault, NULL, index) + +fan(0); +fan(1); +fan(2); +fan(3); +fan(4); + +static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6); + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + int temp_nr = to_sensor_dev_attr(attr)->index; + struct env *p = dev_get_drvdata(dev); + s8 val; + + val = env_read(p, IREG_LCL_TEMP + temp_nr); + return sprintf(buf, "%d\n", ((int) val) - 64); +} + +static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13); + +static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct env *p = dev_get_drvdata(dev); + u8 val; + + val = readb(p->regs + REG_STAT); + return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0); +} + +static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0); +static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1); +static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2); +static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3); + +static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct env *p = dev_get_drvdata(dev); + u8 val; + + val = readb(p->regs + REG_STAT); + return sprintf(buf, "%d\n", val >> 4); +} + +static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0); + +static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "ultra45\n"); +} + +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +static struct attribute *env_attributes[] = { + &sensor_dev_attr_fan0_speed.dev_attr.attr, + &sensor_dev_attr_fan0_fault.dev_attr.attr, + &sensor_dev_attr_fan1_speed.dev_attr.attr, + &sensor_dev_attr_fan1_fault.dev_attr.attr, + &sensor_dev_attr_fan2_speed.dev_attr.attr, + &sensor_dev_attr_fan2_fault.dev_attr.attr, + &sensor_dev_attr_fan3_speed.dev_attr.attr, + &sensor_dev_attr_fan3_fault.dev_attr.attr, + &sensor_dev_attr_fan4_speed.dev_attr.attr, + &sensor_dev_attr_fan4_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan_fault.dev_attr.attr, + &sensor_dev_attr_adt7462_local_temp.dev_attr.attr, + &sensor_dev_attr_cpu0_temp.dev_attr.attr, + &sensor_dev_attr_cpu1_temp.dev_attr.attr, + &sensor_dev_attr_motherboard_temp.dev_attr.attr, + &sensor_dev_attr_lm95221_local_temp.dev_attr.attr, + &sensor_dev_attr_fire_temp.dev_attr.attr, + &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr, + &sensor_dev_attr_front_panel_temp.dev_attr.attr, + &sensor_dev_attr_psu_temp.dev_attr.attr, + &sensor_dev_attr_fan_failure.dev_attr.attr, + &sensor_dev_attr_env_bus_busy.dev_attr.attr, + &sensor_dev_attr_env_data_stale.dev_attr.attr, + &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr, + &sensor_dev_attr_firmware_version.dev_attr.attr, + &sensor_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group env_group = { + .attrs = env_attributes, +}; + +static int __devinit env_probe(struct of_device *op, + const struct of_device_id *match) +{ + struct env *p = kzalloc(sizeof(*p), GFP_KERNEL); + int err = -ENOMEM; + + if (!p) + goto out; + + spin_lock_init(&p->lock); + + p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747"); + if (!p->regs) + goto out_free; + + err = sysfs_create_group(&op->dev.kobj, &env_group); + if (err) + goto out_iounmap; + + p->hwmon_dev = hwmon_device_register(&op->dev); + if (IS_ERR(p->hwmon_dev)) { + err = PTR_ERR(p->hwmon_dev); + goto out_sysfs_remove_group; + } + + dev_set_drvdata(&op->dev, p); + err = 0; + +out: + return err; + +out_sysfs_remove_group: + sysfs_remove_group(&op->dev.kobj, &env_group); + +out_iounmap: + of_iounmap(&op->resource[0], p->regs, REG_SIZE); + +out_free: + kfree(p); + goto out; +} + +static int __devexit env_remove(struct of_device *op) +{ + struct env *p = dev_get_drvdata(&op->dev); + + if (p) { + sysfs_remove_group(&op->dev.kobj, &env_group); + hwmon_device_unregister(p->hwmon_dev); + of_iounmap(&op->resource[0], p->regs, REG_SIZE); + kfree(p); + } + + return 0; +} + +static const struct of_device_id env_match[] = { + { + .name = "env-monitor", + .compatible = "SUNW,ebus-pic16f747-env", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, env_match); + +static struct of_platform_driver env_driver = { + .name = "ultra45_env", + .match_table = env_match, + .probe = env_probe, + .remove = __devexit_p(env_remove), +}; + +static int __init env_init(void) +{ + return of_register_driver(&env_driver, &of_bus_type); +} + +static void __exit env_exit(void) +{ + of_unregister_driver(&env_driver); +} + +module_init(env_init); +module_exit(env_exit); diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index d8765cc93d2..c4f42311fde 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -249,7 +249,7 @@ static int bbc_remove(struct of_device *op) return 0; } -static struct of_device_id bbc_beep_match[] = { +static const struct of_device_id bbc_beep_match[] = { { .name = "beep", .compatible = "SUNW,bbc-beep", @@ -328,7 +328,7 @@ static int grover_remove(struct of_device *op) return 0; } -static struct of_device_id grover_beep_match[] = { +static const struct of_device_id grover_beep_match[] = { { .name = "beep", .compatible = "SUNW,smbus-beep", diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index 692a79ec2a2..5071af2c060 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -87,7 +87,7 @@ static int __devexit sparc_i8042_remove(struct of_device *op) return 0; } -static struct of_device_id sparc_i8042_match[] = { +static const struct of_device_id sparc_i8042_match[] = { { .name = "8042", }, diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 5b14262af01..e3e40427e00 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -82,6 +82,14 @@ config LEDS_COBALT_RAQ help This option enables support for the Cobalt Raq series LEDs. +config LEDS_SUNFIRE + tristate "LED support for SunFire servers." + depends on LEDS_CLASS && SPARC64 + select LEDS_TRIGGERS + help + This option enables support for the Left, Middle, and Right + LEDs on the I/O and CPU boards of SunFire UltraSPARC servers. + config LEDS_HP6XX tristate "LED Support for the HP Jornada 6xx" depends on LEDS_CLASS && SH_HP6XX diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 3a8e6a04363..eb186c351a1 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o +obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c new file mode 100644 index 00000000000..6b008f0c3f6 --- /dev/null +++ b/drivers/leds/leds-sunfire.c @@ -0,0 +1,273 @@ +/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver. + * + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/leds.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <asm/fhc.h> +#include <asm/upa.h> + +#define DRIVER_NAME "leds-sunfire" +#define PFX DRIVER_NAME ": " + +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("Sun Fire LED driver"); +MODULE_LICENSE("GPL"); + +struct sunfire_led { + struct led_classdev led_cdev; + void __iomem *reg; +}; +#define to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev) + +static void __clockboard_set(struct led_classdev *led_cdev, + enum led_brightness led_val, u8 bit) +{ + struct sunfire_led *p = to_sunfire_led(led_cdev); + u8 reg = upa_readb(p->reg); + + switch (bit) { + case CLOCK_CTRL_LLED: + if (led_val) + reg &= ~bit; + else + reg |= bit; + break; + + default: + if (led_val) + reg |= bit; + else + reg &= ~bit; + break; + } + upa_writeb(reg, p->reg); +} + +static void clockboard_left_set(struct led_classdev *led_cdev, + enum led_brightness led_val) +{ + __clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED); +} + +static void clockboard_middle_set(struct led_classdev *led_cdev, + enum led_brightness led_val) +{ + __clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED); +} + +static void clockboard_right_set(struct led_classdev *led_cdev, + enum led_brightness led_val) +{ + __clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED); +} + +static void __fhc_set(struct led_classdev *led_cdev, + enum led_brightness led_val, u32 bit) +{ + struct sunfire_led *p = to_sunfire_led(led_cdev); + u32 reg = upa_readl(p->reg); + + switch (bit) { + case FHC_CONTROL_LLED: + if (led_val) + reg &= ~bit; + else + reg |= bit; + break; + + default: + if (led_val) + reg |= bit; + else + reg &= ~bit; + break; + } + upa_writel(reg, p->reg); +} + +static void fhc_left_set(struct led_classdev *led_cdev, + enum led_brightness led_val) +{ + __fhc_set(led_cdev, led_val, FHC_CONTROL_LLED); +} + +static void fhc_middle_set(struct led_classdev *led_cdev, + enum led_brightness led_val) +{ + __fhc_set(led_cdev, led_val, FHC_CONTROL_MLED); +} + +static void fhc_right_set(struct led_classdev *led_cdev, + enum led_brightness led_val) +{ + __fhc_set(led_cdev, led_val, FHC_CONTROL_RLED); +} + +typedef void (*set_handler)(struct led_classdev *, enum led_brightness); +struct led_type { + const char *name; + set_handler handler; + const char *default_trigger; +}; + +#define NUM_LEDS_PER_BOARD 3 +struct sunfire_drvdata { + struct sunfire_led leds[NUM_LEDS_PER_BOARD]; +}; + +static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, + struct led_type *types) +{ + struct sunfire_drvdata *p; + int i, err = -EINVAL; + + if (pdev->num_resources != 1) { + printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n", + pdev->num_resources); + goto out; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n"); + goto out; + } + + for (i = 0; i < NUM_LEDS_PER_BOARD; i++) { + struct led_classdev *lp = &p->leds[i].led_cdev; + + p->leds[i].reg = (void __iomem *) pdev->resource[0].start; + lp->name = types[i].name; + lp->brightness = LED_FULL; + lp->brightness_set = types[i].handler; + lp->default_trigger = types[i].default_trigger; + + err = led_classdev_register(&pdev->dev, lp); + if (err) { + printk(KERN_ERR PFX "Could not register %s LED\n", + lp->name); + goto out_unregister_led_cdevs; + } + } + + dev_set_drvdata(&pdev->dev, p); + + err = 0; +out: + return err; + +out_unregister_led_cdevs: + for (i--; i >= 0; i--) + led_classdev_unregister(&p->leds[i].led_cdev); + goto out; +} + +static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) +{ + struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev); + int i; + + for (i = 0; i < NUM_LEDS_PER_BOARD; i++) + led_classdev_unregister(&p->leds[i].led_cdev); + + kfree(p); + + return 0; +} + +static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = { + { + .name = "clockboard-left", + .handler = clockboard_left_set, + }, + { + .name = "clockboard-middle", + .handler = clockboard_middle_set, + }, + { + .name = "clockboard-right", + .handler = clockboard_right_set, + .default_trigger= "heartbeat", + }, +}; + +static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev) +{ + return sunfire_led_generic_probe(pdev, clockboard_led_types); +} + +static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = { + { + .name = "fhc-left", + .handler = fhc_left_set, + }, + { + .name = "fhc-middle", + .handler = fhc_middle_set, + }, + { + .name = "fhc-right", + .handler = fhc_right_set, + .default_trigger= "heartbeat", + }, +}; + +static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev) +{ + return sunfire_led_generic_probe(pdev, fhc_led_types); +} + +MODULE_ALIAS("platform:sunfire-clockboard-leds"); +MODULE_ALIAS("platform:sunfire-fhc-leds"); + +static struct platform_driver sunfire_clockboard_led_driver = { + .probe = sunfire_clockboard_led_probe, + .remove = __devexit_p(sunfire_led_generic_remove), + .driver = { + .name = "sunfire-clockboard-leds", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sunfire_fhc_led_driver = { + .probe = sunfire_fhc_led_probe, + .remove = __devexit_p(sunfire_led_generic_remove), + .driver = { + .name = "sunfire-fhc-leds", + .owner = THIS_MODULE, + }, +}; + +static int __init sunfire_leds_init(void) +{ + int err = platform_driver_register(&sunfire_clockboard_led_driver); + + if (err) { + printk(KERN_ERR PFX "Could not register clock board LED driver\n"); + return err; + } + + err = platform_driver_register(&sunfire_fhc_led_driver); + if (err) { + printk(KERN_ERR PFX "Could not register FHC LED driver\n"); + platform_driver_unregister(&sunfire_clockboard_led_driver); + } + + return err; +} + +static void __exit sunfire_leds_exit(void) +{ + platform_driver_unregister(&sunfire_clockboard_led_driver); + platform_driver_unregister(&sunfire_fhc_led_driver); +} + +module_init(sunfire_leds_init); +module_exit(sunfire_leds_exit); diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 0d7c88396c8..fd7a1017399 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -1,13 +1,10 @@ -/* - * - * sun_uflash - Driver implementation for user-programmable flash - * present on many Sun Microsystems SME boardsets. +/* sun_uflash.c - Driver for user-programmable flash on + * Sun Microsystems SME boardsets. * * This driver does NOT provide access to the OBP-flash for * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead. * * Copyright (c) 2001 Eric Brower (ebrower@usa.net) - * */ #include <linux/kernel.h> @@ -16,8 +13,8 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/ioport.h> -#include <asm/ebus.h> -#include <asm/oplib.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/prom.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -26,67 +23,65 @@ #include <linux/mtd/map.h> #define UFLASH_OBPNAME "flashprom" -#define UFLASH_DEVNAME "userflash" +#define DRIVER_NAME "sun_uflash" +#define PFX DRIVER_NAME ": " #define UFLASH_WINDOW_SIZE 0x200000 #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); -MODULE_SUPPORTED_DEVICE("userflash"); +MODULE_SUPPORTED_DEVICE(DRIVER_NAME); MODULE_LICENSE("GPL"); -MODULE_VERSION("2.0"); +MODULE_VERSION("2.1"); -static LIST_HEAD(device_list); struct uflash_dev { const char *name; /* device name */ struct map_info map; /* mtd map info */ struct mtd_info *mtd; /* mtd info */ }; - struct map_info uflash_map_templ = { .name = "SUNW,???-????", .size = UFLASH_WINDOW_SIZE, .bankwidth = UFLASH_BUSWIDTH, }; -int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) +int uflash_devinit(struct of_device *op, struct device_node *dp) { struct uflash_dev *up; - struct resource *res; - res = &edev->resource[0]; - - if (edev->num_addrs != 1) { + if (op->resource[1].flags) { /* Non-CFI userflash device-- once I find one we * can work on supporting it. */ - printk("%s: unsupported device at 0x%llx (%d regs): " \ - "email ebrower@usa.net\n", - dp->full_name, (unsigned long long)res->start, - edev->num_addrs); + printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n", + dp->full_name, (unsigned long long)op->resource[0].start); return -ENODEV; } up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); - if (!up) + if (!up) { + printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n"); return -ENOMEM; + } /* copy defaults and tweak parameters */ memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); - up->map.size = (res->end - res->start) + 1UL; + + up->map.size = resource_size(&op->resource[0]); up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) up->map.name = (char *)up->name; - up->map.phys = res->start; + up->map.phys = op->resource[0].start; - up->map.virt = ioremap_nocache(res->start, up->map.size); + up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size, + DRIVER_NAME); if (!up->map.virt) { - printk("%s: Failed to map device.\n", dp->full_name); + printk(KERN_ERR PFX "Failed to map device.\n"); kfree(up); return -EINVAL; @@ -97,7 +92,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) /* MTD registration */ up->mtd = do_map_probe("cfi_probe", &up->map); if (!up->mtd) { - iounmap(up->map.virt); + of_iounmap(&op->resource[0], up->map.virt, up->map.size); kfree(up); return -ENXIO; @@ -107,32 +102,34 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) add_mtd_device(up->mtd); - dev_set_drvdata(&edev->ofdev.dev, up); + dev_set_drvdata(&op->dev, up); return 0; } -static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match) { - struct linux_ebus_device *edev = to_ebus_device(&dev->dev); - struct device_node *dp = dev->node; + struct device_node *dp = op->node; - if (of_find_property(dp, "user", NULL)) + /* Flashprom must have the "user" property in order to + * be used by this driver. + */ + if (!of_find_property(dp, "user", NULL)) return -ENODEV; - return uflash_devinit(edev, dp); + return uflash_devinit(op, dp); } -static int __devexit uflash_remove(struct of_device *dev) +static int __devexit uflash_remove(struct of_device *op) { - struct uflash_dev *up = dev_get_drvdata(&dev->dev); + struct uflash_dev *up = dev_get_drvdata(&op->dev); if (up->mtd) { del_mtd_device(up->mtd); map_destroy(up->mtd); } if (up->map.virt) { - iounmap(up->map.virt); + of_iounmap(&op->resource[0], up->map.virt, up->map.size); up->map.virt = NULL; } @@ -141,7 +138,7 @@ static int __devexit uflash_remove(struct of_device *dev) return 0; } -static struct of_device_id uflash_match[] = { +static const struct of_device_id uflash_match[] = { { .name = UFLASH_OBPNAME, }, @@ -151,7 +148,7 @@ static struct of_device_id uflash_match[] = { MODULE_DEVICE_TABLE(of, uflash_match); static struct of_platform_driver uflash_driver = { - .name = UFLASH_DEVNAME, + .name = DRIVER_NAME, .match_table = uflash_match, .probe = uflash_probe, .remove = __devexit_p(uflash_remove), @@ -159,7 +156,7 @@ static struct of_platform_driver uflash_driver = { static int __init uflash_init(void) { - return of_register_driver(&uflash_driver, &ebus_bus_type); + return of_register_driver(&uflash_driver, &of_bus_type); } static void __exit uflash_exit(void) diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 06e682334c7..3ad7589d6a1 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1,6 +1,6 @@ /* myri_sbus.c: MyriCOM MyriNET SBUS card driver. * - * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net) */ static char version[] = @@ -22,6 +22,9 @@ static char version[] = #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <net/dst.h> #include <net/arp.h> @@ -33,7 +36,6 @@ static char version[] = #include <asm/dma.h> #include <asm/byteorder.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/auxio.h> @@ -243,7 +245,8 @@ static void myri_clean_rings(struct myri_eth *mp) u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + dma_unmap_single(&mp->myri_op->dev, dma_addr, + RX_ALLOC_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } @@ -259,7 +262,9 @@ static void myri_clean_rings(struct myri_eth *mp) u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE); + dma_unmap_single(&mp->myri_op->dev, dma_addr, + (skb->len + 3) & ~3, + DMA_TO_DEVICE); dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } @@ -288,7 +293,9 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + dma_addr = dma_map_single(&mp->myri_op->dev, + skb->data, RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len); sbus_writel(i, &rxd[i].ctx); @@ -344,7 +351,8 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) DTX(("SKB[%d] ", entry)); dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); + dma_unmap_single(&mp->myri_op->dev, dma_addr, + skb->len, DMA_TO_DEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; dev->stats.tx_packets++; @@ -423,9 +431,9 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) /* Check for errors. */ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); - sbus_dma_sync_single_for_cpu(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, DMA_FROM_DEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); dev->stats.rx_errors++; @@ -442,10 +450,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) drops++; DRX(("DROP ")); dev->stats.rx_dropped++; - sbus_dma_sync_single_for_device(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_device(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -464,17 +472,17 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) DRX(("skb_alloc(FAILED) ")); goto drop_it; } - sbus_unmap_single(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_unmap_single(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); - dma_addr = sbus_map_single(mp->myri_sdev, - new_skb->data, - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_addr = dma_map_single(&mp->myri_op->dev, + new_skb->data, + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(dma_addr, &rxd->myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); @@ -500,10 +508,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) /* Reuse original ring buffer. */ DRX(("reuse ")); - sbus_dma_sync_single_for_device(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_device(&mp->myri_op->dev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + DMA_FROM_DEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -652,7 +660,8 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]); } - dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE); + dma_addr = dma_map_single(&mp->myri_op->dev, skb->data, + len, DMA_TO_DEVICE); sbus_writel(dma_addr, &txd->myri_gathers[0].addr); sbus_writel(len, &txd->myri_gathers[0].len); sbus_writel(1, &txd->num_sg); @@ -891,30 +900,30 @@ static const struct header_ops myri_header_ops = { .cache_update = myri_header_cache_update, }; -static int __devinit myri_ether_init(struct sbus_dev *sdev) +static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match) { - static int num; + struct device_node *dp = op->node; static unsigned version_printed; struct net_device *dev; - struct myri_eth *mp; - unsigned char prop_buf[32]; - int i; DECLARE_MAC_BUF(mac); + struct myri_eth *mp; + const void *prop; + static int num; + int i, len; - DET(("myri_ether_init(%p,%d):\n", sdev, num)); + DET(("myri_ether_init(%p,%d):\n", op, num)); dev = alloc_etherdev(sizeof(struct myri_eth)); - if (!dev) return -ENOMEM; if (version_printed++ == 0) printk(version); - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); - mp = (struct myri_eth *) dev->priv; + mp = netdev_priv(dev); spin_lock_init(&mp->irq_lock); - mp->myri_sdev = sdev; + mp->myri_op = op; /* Clean out skb arrays. */ for (i = 0; i < (RX_RING_SIZE + 1); i++) @@ -924,55 +933,44 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) mp->tx_skbs[i] = NULL; /* First check for EEPROM information. */ - i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info", - (char *)&mp->eeprom, sizeof(struct myri_eeprom)); - DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i)); - if (i == 0 || i == -1) { + prop = of_get_property(dp, "myrinet-eeprom-info", &len); + + if (prop) + memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom)); + if (!prop) { /* No eeprom property, must cook up the values ourselves. */ DET(("No EEPROM: ")); mp->eeprom.bus_type = BUS_TYPE_SBUS; - mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0); - mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0); - mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0); - DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers, - mp->eeprom.cval, mp->eeprom.ramsz)); - if (mp->eeprom.cpuvers == 0) { - DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3)); + mp->eeprom.cpuvers = + of_getintprop_default(dp, "cpu_version", 0); + mp->eeprom.cval = + of_getintprop_default(dp, "clock_value", 0); + mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0); + if (!mp->eeprom.cpuvers) mp->eeprom.cpuvers = CPUVERS_2_3; - } - if (mp->eeprom.cpuvers < CPUVERS_3_0) { - DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n")); + if (mp->eeprom.cpuvers < CPUVERS_3_0) mp->eeprom.cval = 0; - } - if (mp->eeprom.ramsz == 0) { - DET(("EEPROM: ramsz == 0, setting to 128k\n")); + if (!mp->eeprom.ramsz) mp->eeprom.ramsz = (128 * 1024); - } - i = prom_getproperty(sdev->prom_node, "myrinet-board-id", - &prop_buf[0], 10); - DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i)); - if ((i != 0) && (i != -1)) - memcpy(&mp->eeprom.id[0], &prop_buf[0], 6); + + prop = of_get_property(dp, "myrinet-board-id", &len); + if (prop) + memcpy(&mp->eeprom.id[0], prop, 6); else set_boardid_from_idprom(mp, num); - i = prom_getproperty(sdev->prom_node, "fpga_version", - &mp->eeprom.fvers[0], 32); - DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i)); - if (i == 0 || i == -1) + + prop = of_get_property(dp, "fpga_version", &len); + if (prop) + memcpy(&mp->eeprom.fvers[0], prop, 32); + else memset(&mp->eeprom.fvers[0], 0, 32); if (mp->eeprom.cpuvers == CPUVERS_4_1) { - DET(("EEPROM: cpuvers CPUVERS_4_1, ")); - if (mp->eeprom.ramsz == (128 * 1024)) { - DET(("ramsize 128k, setting to 256k, ")); + if (mp->eeprom.ramsz == (128 * 1024)) mp->eeprom.ramsz = (256 * 1024); - } - if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){ - DET(("changing cval from %08x to %08x ", - mp->eeprom.cval, 0x50e450e4)); + if ((mp->eeprom.cval == 0x40414041) || + (mp->eeprom.cval == 0x90449044)) mp->eeprom.cval = 0x50e450e4; - } - DET(("\n")); } } #ifdef DEBUG_DETECT @@ -991,8 +989,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) * XXX only a valid version for PCI cards? Ask feldy... */ DET(("Mapping regs for cpuvers < CPUVERS_4_0\n")); - mp->regs = sbus_ioremap(&sdev->resource[0], 0, - mp->reg_size, "MyriCOM Regs"); + mp->regs = of_ioremap(&op->resource[0], 0, + mp->reg_size, "MyriCOM Regs"); if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); goto err; @@ -1001,13 +999,12 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) mp->lregs = mp->lanai + (0x10000 * 2); } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); - mp->cregs = sbus_ioremap(&sdev->resource[0], 0, - PAGE_SIZE, "MyriCOM Control Regs"); - mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), + mp->cregs = of_ioremap(&op->resource[0], 0, + PAGE_SIZE, "MyriCOM Control Regs"); + mp->lregs = of_ioremap(&op->resource[0], (256 * 1024), PAGE_SIZE, "MyriCOM LANAI Regs"); - mp->lanai = - sbus_ioremap(&sdev->resource[0], (512 * 1024), - mp->eeprom.ramsz, "MyriCOM SRAM"); + mp->lanai = of_ioremap(&op->resource[0], (512 * 1024), + mp->eeprom.ramsz, "MyriCOM SRAM"); } DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n", mp->cregs, mp->lregs, mp->lanai)); @@ -1039,16 +1036,15 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) myri_reset_on(mp->cregs); /* Get the supported DVMA burst sizes from our SBUS. */ - mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node, - "burst-sizes", 0x00); - - if (!sbus_can_burst64(sdev)) + mp->myri_bursts = of_getintprop_default(dp->parent, + "burst-sizes", 0x00); + if (!sbus_can_burst64()) mp->myri_bursts &= ~(DMA_BURST64); DET(("MYRI bursts %02x\n", mp->myri_bursts)); /* Encode SBUS interrupt level in second control register. */ - i = prom_getint(sdev->prom_node, "interrupts"); + i = of_getintprop_default(dp, "interrupts", 0); if (i == 0) i = 4; DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n", @@ -1063,7 +1059,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) dev->tx_timeout = &myri_tx_timeout; dev->watchdog_timeo = 5*HZ; dev->set_multicast_list = &myri_set_multicast; - dev->irq = sdev->irqs[0]; + dev->irq = op->irqs[0]; /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); @@ -1088,7 +1084,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) goto err_free_irq; } - dev_set_drvdata(&sdev->ofdev.dev, mp); + dev_set_drvdata(&op->dev, mp); num++; @@ -1105,17 +1101,9 @@ err: return -ENODEV; } - -static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - - return myri_ether_init(sdev); -} - -static int __devexit myri_sbus_remove(struct of_device *dev) +static int __devexit myri_sbus_remove(struct of_device *op) { - struct myri_eth *mp = dev_get_drvdata(&dev->dev); + struct myri_eth *mp = dev_get_drvdata(&op->dev); struct net_device *net_dev = mp->dev; unregister_netdev(net_dev); @@ -1123,21 +1111,21 @@ static int __devexit myri_sbus_remove(struct of_device *dev) free_irq(net_dev->irq, net_dev); if (mp->eeprom.cpuvers < CPUVERS_4_0) { - sbus_iounmap(mp->regs, mp->reg_size); + of_iounmap(&op->resource[0], mp->regs, mp->reg_size); } else { - sbus_iounmap(mp->cregs, PAGE_SIZE); - sbus_iounmap(mp->lregs, (256 * 1024)); - sbus_iounmap(mp->lanai, (512 * 1024)); + of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE); + of_iounmap(&op->resource[0], mp->lregs, (256 * 1024)); + of_iounmap(&op->resource[0], mp->lanai, (512 * 1024)); } free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id myri_sbus_match[] = { +static const struct of_device_id myri_sbus_match[] = { { .name = "MYRICOM,mlanai", }, @@ -1158,7 +1146,7 @@ static struct of_platform_driver myri_sbus_driver = { static int __init myri_sbus_init(void) { - return of_register_driver(&myri_sbus_driver, &sbus_bus_type); + return of_register_driver(&myri_sbus_driver, &of_bus_type); } static void __exit myri_sbus_exit(void) diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 5d93fcc95d5..ff363e95d9c 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -288,7 +288,7 @@ struct myri_eth { struct myri_eeprom eeprom; /* Local copy of EEPROM. */ unsigned int reg_size; /* Size of register space. */ unsigned int shmem_base; /* Offset to shared ram. */ - struct sbus_dev *myri_sdev; /* Our SBUS device struct. */ + struct of_device *myri_op; /* Our OF device struct. */ }; /* We use this to acquire receive skb's that we can DMA directly into. */ diff --git a/drivers/net/niu.c b/drivers/net/niu.c index e3be81eba8a..ebc81270290 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -9130,7 +9130,7 @@ static int __devexit niu_of_remove(struct of_device *op) return 0; } -static struct of_device_id niu_match[] = { +static const struct of_device_id niu_match[] = { { .name = "network", .compatible = "SUNW,niusl", diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 31e7384e312..018d0fca942 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1,7 +1,6 @@ -/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $ - * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. +/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * - * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -23,6 +22,9 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/auxio.h> #include <asm/byteorder.h> @@ -32,15 +34,14 @@ #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/pgtable.h> -#include <asm/sbus.h> #include <asm/system.h> #include "sunbmac.h" #define DRV_NAME "sunbmac" -#define DRV_VERSION "2.0" -#define DRV_RELDATE "11/24/03" -#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" +#define DRV_VERSION "2.1" +#define DRV_RELDATE "August 26, 2008" +#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; @@ -96,8 +97,8 @@ static int qec_global_reset(void __iomem *gregs) static void qec_init(struct bigmac *bp) { + struct of_device *qec_op = bp->qec_op; void __iomem *gregs = bp->gregs; - struct sbus_dev *qec_sdev = bp->qec_sdev; u8 bsizes = bp->bigmac_bursts; u32 regval; @@ -112,13 +113,13 @@ static void qec_init(struct bigmac *bp) sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE); /* All of memsize is given to bigmac. */ - sbus_writel(qec_sdev->reg_addrs[1].reg_size, + sbus_writel(resource_size(&qec_op->resource[1]), gregs + GLOB_MSIZE); /* Half to the transmitter, half to the receiver. */ - sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, + sbus_writel(resource_size(&qec_op->resource[1]) >> 1, gregs + GLOB_TSIZE); - sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, + sbus_writel(resource_size(&qec_op->resource[1]) >> 1, gregs + GLOB_RSIZE); } @@ -239,9 +240,10 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) skb_reserve(skb, 34); bb->be_rxd[i].rx_addr = - sbus_map_single(bp->bigmac_sdev, skb->data, - RX_BUF_ALLOC_SIZE - 34, - SBUS_DMA_FROMDEVICE); + dma_map_single(&bp->bigmac_op->dev, + skb->data, + RX_BUF_ALLOC_SIZE - 34, + DMA_FROM_DEVICE); bb->be_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); } @@ -776,9 +778,9 @@ static void bigmac_tx(struct bigmac *bp) skb = bp->tx_skbs[elem]; bp->enet_stats.tx_packets++; bp->enet_stats.tx_bytes += skb->len; - sbus_unmap_single(bp->bigmac_sdev, - this->tx_addr, skb->len, - SBUS_DMA_TODEVICE); + dma_unmap_single(&bp->bigmac_op->dev, + this->tx_addr, skb->len, + DMA_TO_DEVICE); DTX(("skb(%p) ", skb)); bp->tx_skbs[elem] = NULL; @@ -831,18 +833,19 @@ static void bigmac_rx(struct bigmac *bp) drops++; goto drop_it; } - sbus_unmap_single(bp->bigmac_sdev, - this->rx_addr, - RX_BUF_ALLOC_SIZE - 34, - SBUS_DMA_FROMDEVICE); + dma_unmap_single(&bp->bigmac_op->dev, + this->rx_addr, + RX_BUF_ALLOC_SIZE - 34, + DMA_FROM_DEVICE); bp->rx_skbs[elem] = new_skb; new_skb->dev = bp->dev; skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); - this->rx_addr = sbus_map_single(bp->bigmac_sdev, - new_skb->data, - RX_BUF_ALLOC_SIZE - 34, - SBUS_DMA_FROMDEVICE); + this->rx_addr = + dma_map_single(&bp->bigmac_op->dev, + new_skb->data, + RX_BUF_ALLOC_SIZE - 34, + DMA_FROM_DEVICE); this->rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -857,13 +860,13 @@ static void bigmac_rx(struct bigmac *bp) } skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, - this->rx_addr, len, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&bp->bigmac_op->dev, + this->rx_addr, len, + DMA_FROM_DEVICE); skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len); - sbus_dma_sync_single_for_device(bp->bigmac_sdev, - this->rx_addr, len, - SBUS_DMA_FROMDEVICE); + dma_sync_single_for_device(&bp->bigmac_op->dev, + this->rx_addr, len, + DMA_FROM_DEVICE); /* Reuse original ring buffer. */ this->rx_flags = @@ -959,7 +962,8 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 mapping; len = skb->len; - mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE); + mapping = dma_map_single(&bp->bigmac_op->dev, skb->data, + len, DMA_TO_DEVICE); /* Avoid a race... */ spin_lock_irq(&bp->lock); @@ -1051,12 +1055,8 @@ static void bigmac_set_multicast(struct net_device *dev) /* Ethtool support... */ static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct bigmac *bp = dev->priv; - strcpy(info->driver, "sunbmac"); strcpy(info->version, "2.0"); - sprintf(info->bus_info, "SBUS:%d", - bp->qec_sdev->slot); } static u32 bigmac_get_link(struct net_device *dev) @@ -1075,14 +1075,15 @@ static const struct ethtool_ops bigmac_ethtool_ops = { .get_link = bigmac_get_link, }; -static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) +static int __devinit bigmac_ether_init(struct of_device *op, + struct of_device *qec_op) { - struct net_device *dev; static int version_printed; - struct bigmac *bp; + struct net_device *dev; u8 bsizes, bsizes_more; - int i; DECLARE_MAC_BUF(mac); + struct bigmac *bp; + int i; /* Get a new device struct for this interface. */ dev = alloc_etherdev(sizeof(struct bigmac)); @@ -1092,32 +1093,21 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) if (version_printed++ == 0) printk(KERN_INFO "%s", version); - dev->base_addr = (long) qec_sdev; for (i = 0; i < 6; i++) dev->dev_addr[i] = idprom->id_ethaddr[i]; /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ - bp = dev->priv; - bp->qec_sdev = qec_sdev; - bp->bigmac_sdev = qec_sdev->child; + bp = netdev_priv(dev); + bp->qec_op = qec_op; + bp->bigmac_op = op; - SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); spin_lock_init(&bp->lock); - /* Verify the registers we expect, are actually there. */ - if ((bp->bigmac_sdev->num_registers != 3) || - (bp->qec_sdev->num_registers != 2)) { - printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n", - bp->qec_sdev->num_registers, - bp->bigmac_sdev->num_registers); - printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n"); - goto fail_and_cleanup; - } - /* Map in QEC global control registers. */ - bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0, - GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); + bp->gregs = of_ioremap(&qec_op->resource[0], 0, + GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); if (!bp->gregs) { printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n"); goto fail_and_cleanup; @@ -1134,13 +1124,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) goto fail_and_cleanup; /* Get supported SBUS burst sizes. */ - bsizes = prom_getintdefault(bp->qec_sdev->prom_node, - "burst-sizes", - 0xff); - - bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node, - "burst-sizes", - 0xff); + bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff); + bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff); bsizes &= 0xff; if (bsizes_more != 0xff) @@ -1154,16 +1139,16 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) qec_init(bp); /* Map in the BigMAC channel registers. */ - bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0, - CREG_REG_SIZE, "BigMAC QEC Channel Regs"); + bp->creg = of_ioremap(&op->resource[0], 0, + CREG_REG_SIZE, "BigMAC QEC Channel Regs"); if (!bp->creg) { printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n"); goto fail_and_cleanup; } /* Map in the BigMAC control registers. */ - bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0, - BMAC_REG_SIZE, "BigMAC Primary Regs"); + bp->bregs = of_ioremap(&op->resource[1], 0, + BMAC_REG_SIZE, "BigMAC Primary Regs"); if (!bp->bregs) { printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n"); goto fail_and_cleanup; @@ -1172,8 +1157,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) /* Map in the BigMAC transceiver registers, this is how you poke at * the BigMAC's PHY. */ - bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0, - TCVR_REG_SIZE, "BigMAC Transceiver Regs"); + bp->tregs = of_ioremap(&op->resource[2], 0, + TCVR_REG_SIZE, "BigMAC Transceiver Regs"); if (!bp->tregs) { printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n"); goto fail_and_cleanup; @@ -1183,17 +1168,17 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) bigmac_stop(bp); /* Allocate transmit/receive descriptor DVMA block. */ - bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev, - PAGE_SIZE, - &bp->bblock_dvma); + bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev, + PAGE_SIZE, + &bp->bblock_dvma, GFP_ATOMIC); if (bp->bmac_block == NULL || bp->bblock_dvma == 0) { printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n"); goto fail_and_cleanup; } /* Get the board revision of this BigMAC. */ - bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node, - "board-version", 1); + bp->board_rev = of_getintprop_default(bp->bigmac_op->node, + "board-version", 1); /* Init auto-negotiation timer state. */ init_timer(&bp->bigmac_timer); @@ -1217,7 +1202,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) dev->watchdog_timeo = 5*HZ; /* Finish net device registration. */ - dev->irq = bp->bigmac_sdev->irqs[0]; + dev->irq = bp->bigmac_op->irqs[0]; dev->dma = 0; if (register_netdev(dev)) { @@ -1225,7 +1210,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev) goto fail_and_cleanup; } - dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp); + dev_set_drvdata(&bp->bigmac_op->dev, bp); printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -1236,66 +1221,67 @@ fail_and_cleanup: /* Something went wrong, undo whatever we did so far. */ /* Free register mappings if any. */ if (bp->gregs) - sbus_iounmap(bp->gregs, GLOB_REG_SIZE); + of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE); if (bp->creg) - sbus_iounmap(bp->creg, CREG_REG_SIZE); + of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE); if (bp->bregs) - sbus_iounmap(bp->bregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE); if (bp->tregs) - sbus_iounmap(bp->tregs, TCVR_REG_SIZE); + of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE); if (bp->bmac_block) - sbus_free_consistent(bp->bigmac_sdev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); + dma_free_coherent(&bp->bigmac_op->dev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); /* This also frees the co-located 'dev->priv' */ free_netdev(dev); return -ENODEV; } -/* QEC can be the parent of either QuadEthernet or - * a BigMAC. We want the latter. +/* QEC can be the parent of either QuadEthernet or a BigMAC. We want + * the latter. */ -static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit bigmac_sbus_probe(struct of_device *op, + const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; + struct device *parent = op->dev.parent; + struct of_device *qec_op; - if (!strcmp(dp->name, "be")) - sdev = sdev->parent; + qec_op = to_of_device(parent); - return bigmac_ether_init(sdev); + return bigmac_ether_init(op, qec_op); } -static int __devexit bigmac_sbus_remove(struct of_device *dev) +static int __devexit bigmac_sbus_remove(struct of_device *op) { - struct bigmac *bp = dev_get_drvdata(&dev->dev); + struct bigmac *bp = dev_get_drvdata(&op->dev); + struct device *parent = op->dev.parent; struct net_device *net_dev = bp->dev; + struct of_device *qec_op; + + qec_op = to_of_device(parent); unregister_netdev(net_dev); - sbus_iounmap(bp->gregs, GLOB_REG_SIZE); - sbus_iounmap(bp->creg, CREG_REG_SIZE); - sbus_iounmap(bp->bregs, BMAC_REG_SIZE); - sbus_iounmap(bp->tregs, TCVR_REG_SIZE); - sbus_free_consistent(bp->bigmac_sdev, - PAGE_SIZE, - bp->bmac_block, - bp->bblock_dvma); + of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE); + of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE); + of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE); + dma_free_coherent(&op->dev, + PAGE_SIZE, + bp->bmac_block, + bp->bblock_dvma); free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id bigmac_sbus_match[] = { - { - .name = "qec", - }, +static const struct of_device_id bigmac_sbus_match[] = { { .name = "be", }, @@ -1313,7 +1299,7 @@ static struct of_platform_driver bigmac_sbus_driver = { static int __init bigmac_init(void) { - return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type); + return of_register_driver(&bigmac_sbus_driver, &of_bus_type); } static void __exit bigmac_exit(void) diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index b563d3c2993..8840bc0b840 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -329,8 +329,8 @@ struct bigmac { unsigned int timer_ticks; struct net_device_stats enet_stats; - struct sbus_dev *qec_sdev; - struct sbus_dev *bigmac_sdev; + struct of_device *qec_op; + struct of_device *bigmac_op; struct net_device *dev; }; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index b79d5f018f7..f1ebeb5f65b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3,7 +3,7 @@ * "Happy Meal Ethernet" found on SunSwift SBUS cards. * * Copyright (C) 1996, 1998, 1999, 2002, 2003, - 2006 David S. Miller (davem@davemloft.net) + * 2006, 2008 David S. Miller (davem@davemloft.net) * * Changes : * 2000/11/11 Willy Tarreau <willy AT meta-x.org> @@ -34,6 +34,7 @@ #include <linux/skbuff.h> #include <linux/mm.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> #include <asm/system.h> #include <asm/io.h> @@ -41,8 +42,9 @@ #include <asm/byteorder.h> #ifdef CONFIG_SPARC +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/prom.h> @@ -60,8 +62,8 @@ #include "sunhme.h" #define DRV_NAME "sunhme" -#define DRV_VERSION "3.00" -#define DRV_RELDATE "June 23, 2006" +#define DRV_VERSION "3.10" +#define DRV_RELDATE "August 26, 2008" #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = @@ -251,13 +253,13 @@ static u32 pci_hme_read_desc32(hme32 *p) #define hme_read_desc32(__hp, __p) \ ((__hp)->read_desc32(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ - ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir))) + ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir))) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir))) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))) + ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))) #else #ifdef CONFIG_SBUS /* SBUS only compilation */ @@ -277,13 +279,13 @@ do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ } while(0) #define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ - sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) + dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) + dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) + dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) + dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) #else /* PCI only compilation */ #define hme_write32(__hp, __reg, __val) \ @@ -305,36 +307,17 @@ static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) return le32_to_cpup((__le32 *)p); } #define hme_dma_map(__hp, __ptr, __size, __dir) \ - pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) + pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ - pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) + pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ - pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) + pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ - pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) + pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) #endif #endif -#ifdef SBUS_DMA_BIDIRECTIONAL -# define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL -#else -# define DMA_BIDIRECTIONAL 0 -#endif - -#ifdef SBUS_DMA_FROMDEVICE -# define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE -#else -# define DMA_TODEVICE 1 -#endif - -#ifdef SBUS_DMA_TODEVICE -# define DMA_TODEVICE SBUS_DMA_TODEVICE -#else -# define DMA_FROMDEVICE 2 -#endif - - /* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) { @@ -1224,7 +1207,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp) rxd = &hp->happy_block->happy_meal_rxd[i]; dma_addr = hme_read_desc32(hp, &rxd->rx_addr); - hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, + RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); hp->rx_skbs[i] = NULL; } @@ -1242,10 +1226,10 @@ static void happy_meal_clean_rings(struct happy_meal *hp) for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &hp->happy_block->happy_meal_txd[i]; dma_addr = hme_read_desc32(hp, &txd->tx_addr); - hme_dma_unmap(hp, dma_addr, - (hme_read_desc32(hp, &txd->tx_flags) - & TXFLAG_SIZE), - DMA_TODEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TO_DEVICE); if (frag != skb_shinfo(skb)->nr_frags) i++; @@ -1287,7 +1271,8 @@ static void happy_meal_init_rings(struct happy_meal *hp) skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); hme_write_rxd(hp, &hb->happy_meal_rxd[i], (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)), - hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); + dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE, + DMA_FROM_DEVICE)); skb_reserve(skb, RX_OFFSET); } @@ -1593,7 +1578,7 @@ static int happy_meal_init(struct happy_meal *hp) if ((hp->happy_bursts & DMA_BURST64) && ((hp->happy_flags & HFLAG_PCI) != 0 #ifdef CONFIG_SBUS - || sbus_can_burst64(hp->happy_dev) + || sbus_can_burst64() #endif || 0)) { u32 gcfg = GREG_CFG_BURST64; @@ -1603,11 +1588,13 @@ static int happy_meal_init(struct happy_meal *hp) * do not. -DaveM */ #ifdef CONFIG_SBUS - if ((hp->happy_flags & HFLAG_PCI) == 0 && - sbus_can_dma_64bit(hp->happy_dev)) { - sbus_set_sbus64(hp->happy_dev, - hp->happy_bursts); - gcfg |= GREG_CFG_64BIT; + if ((hp->happy_flags & HFLAG_PCI) == 0) { + struct of_device *op = hp->happy_dev; + if (sbus_can_dma_64bit()) { + sbus_set_sbus64(&op->dev, + hp->happy_bursts); + gcfg |= GREG_CFG_64BIT; + } } #endif @@ -1966,7 +1953,7 @@ static void happy_meal_tx(struct happy_meal *hp) dma_len = hme_read_desc32(hp, &this->tx_flags); dma_len &= TXFLAG_SIZE; - hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); elem = NEXT_TX(elem); this = &txbase[elem]; @@ -2044,13 +2031,14 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) drops++; goto drop_it; } - hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); + dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); hp->rx_skbs[elem] = new_skb; new_skb->dev = dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), - hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); + dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE, + DMA_FROM_DEVICE)); skb_reserve(new_skb, RX_OFFSET); /* Trim the original skb for the netif. */ @@ -2065,10 +2053,9 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE); + dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE); skb_copy_from_linear_data(skb, copy_skb->data, len); - hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE); - + dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE); /* Reuse original ring buffer. */ hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), @@ -2300,7 +2287,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 mapping, len; len = skb->len; - mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); + mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE); tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], (tx_flags | (len & TXFLAG_SIZE)), @@ -2314,7 +2301,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) * Otherwise we could race with the device. */ first_len = skb_headlen(skb); - first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE); + first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len, + DMA_TO_DEVICE); entry = NEXT_TX(entry); for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { @@ -2322,10 +2310,9 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, mapping, this_txflags; len = this_frag->size; - mapping = hme_dma_map(hp, - ((void *) page_address(this_frag->page) + - this_frag->page_offset), - len, DMA_TODEVICE); + mapping = dma_map_page(hp->dma_dev, this_frag->page, + this_frag->page_offset, len, + DMA_TO_DEVICE); this_txflags = tx_flags; if (frag == skb_shinfo(skb)->nr_frags - 1) this_txflags |= TXFLAG_EOP; @@ -2493,9 +2480,12 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info } #ifdef CONFIG_SBUS else { - struct sbus_dev *sdev = hp->happy_dev; - sprintf(info->bus_info, "SBUS:%d", - sdev->slot); + const struct linux_prom_registers *regs; + struct of_device *op = hp->happy_dev; + regs = of_get_property(op->node, "regs", NULL); + if (regs) + sprintf(info->bus_info, "SBUS:%d", + regs->which_io); } #endif } @@ -2521,63 +2511,21 @@ static const struct ethtool_ops hme_ethtool_ops = { static int hme_version_printed; #ifdef CONFIG_SBUS -void __devinit quattro_get_ranges(struct quattro *qp) -{ - struct sbus_dev *sdev = qp->quattro_dev; - int err; - - err = prom_getproperty(sdev->prom_node, - "ranges", - (char *)&qp->ranges[0], - sizeof(qp->ranges)); - if (err == 0 || err == -1) { - qp->nranges = 0; - return; - } - qp->nranges = (err / sizeof(struct linux_prom_ranges)); -} - -static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) -{ - struct sbus_dev *sdev = hp->happy_dev; - int rng; - - for (rng = 0; rng < qp->nranges; rng++) { - struct linux_prom_ranges *rngp = &qp->ranges[rng]; - int reg; - - for (reg = 0; reg < 5; reg++) { - if (sdev->reg_addrs[reg].which_io == - rngp->ot_child_space) - break; - } - if (reg == 5) - continue; - - sdev->reg_addrs[reg].which_io = rngp->ot_parent_space; - sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base; - } -} - /* Given a happy meal sbus device, find it's quattro parent. * If none exist, allocate and return a new one. * * Return NULL on failure. */ -static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) +static struct quattro * __devinit quattro_sbus_find(struct of_device *child) { - struct sbus_dev *sdev; + struct device *parent = child->dev.parent; + struct of_device *op; struct quattro *qp; - int i; - for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - for (i = 0, sdev = qp->quattro_dev; - (sdev != NULL) && (i < 4); - sdev = sdev->next, i++) { - if (sdev == goal_sdev) - return qp; - } - } + op = to_of_device(parent); + qp = dev_get_drvdata(&op->dev); + if (qp) + return qp; qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); if (qp != NULL) { @@ -2586,10 +2534,11 @@ static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) for (i = 0; i < 4; i++) qp->happy_meals[i] = NULL; - qp->quattro_dev = goal_sdev; + qp->quattro_dev = child; qp->next = qfe_sbus_list; qfe_sbus_list = qp; - quattro_get_ranges(qp); + + dev_set_drvdata(&op->dev, qp); } return qp; } @@ -2602,10 +2551,10 @@ static void __init quattro_sbus_register_irqs(void) struct quattro *qp; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - struct sbus_dev *sdev = qp->quattro_dev; + struct of_device *op = qp->quattro_dev; int err; - err = request_irq(sdev->irqs[0], + err = request_irq(op->irqs[0], quattro_sbus_interrupt, IRQF_SHARED, "Quattro", qp); @@ -2621,9 +2570,9 @@ static void quattro_sbus_free_irqs(void) struct quattro *qp; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - struct sbus_dev *sdev = qp->quattro_dev; + struct of_device *op = qp->quattro_dev; - free_irq(sdev->irqs[0], qp); + free_irq(op->irqs[0], qp); } } #endif /* CONFIG_SBUS */ @@ -2660,9 +2609,9 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev) #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) +static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) { - struct device_node *dp = sdev->ofdev.node; + struct device_node *dp = op->node, *sbus_dp; struct quattro *qp = NULL; struct happy_meal *hp; struct net_device *dev; @@ -2671,7 +2620,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe DECLARE_MAC_BUF(mac); if (is_qfe) { - qp = quattro_sbus_find(sdev); + qp = quattro_sbus_find(op); if (qp == NULL) goto err_out; for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) @@ -2685,7 +2634,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev = alloc_etherdev(sizeof(struct happy_meal)); if (!dev) goto err_out; - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2713,56 +2662,50 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe memcpy(dev->dev_addr, idprom->id_ethaddr, 6); } - hp = dev->priv; + hp = netdev_priv(dev); - hp->happy_dev = sdev; + hp->happy_dev = op; + hp->dma_dev = &op->dev; spin_lock_init(&hp->happy_lock); err = -ENODEV; - if (sdev->num_registers != 5) { - printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n", - sdev->num_registers); - goto err_out_free_netdev; - } - if (qp != NULL) { hp->qfe_parent = qp; hp->qfe_ent = qfe_slot; qp->happy_meals[qfe_slot] = dev; - quattro_apply_ranges(qp, hp); } - hp->gregs = sbus_ioremap(&sdev->resource[0], 0, - GREG_REG_SIZE, "HME Global Regs"); + hp->gregs = of_ioremap(&op->resource[0], 0, + GREG_REG_SIZE, "HME Global Regs"); if (!hp->gregs) { printk(KERN_ERR "happymeal: Cannot map global registers.\n"); goto err_out_free_netdev; } - hp->etxregs = sbus_ioremap(&sdev->resource[1], 0, - ETX_REG_SIZE, "HME TX Regs"); + hp->etxregs = of_ioremap(&op->resource[1], 0, + ETX_REG_SIZE, "HME TX Regs"); if (!hp->etxregs) { printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n"); goto err_out_iounmap; } - hp->erxregs = sbus_ioremap(&sdev->resource[2], 0, - ERX_REG_SIZE, "HME RX Regs"); + hp->erxregs = of_ioremap(&op->resource[2], 0, + ERX_REG_SIZE, "HME RX Regs"); if (!hp->erxregs) { printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n"); goto err_out_iounmap; } - hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0, - BMAC_REG_SIZE, "HME BIGMAC Regs"); + hp->bigmacregs = of_ioremap(&op->resource[3], 0, + BMAC_REG_SIZE, "HME BIGMAC Regs"); if (!hp->bigmacregs) { printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n"); goto err_out_iounmap; } - hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0, - TCVR_REG_SIZE, "HME Tranceiver Regs"); + hp->tcvregs = of_ioremap(&op->resource[4], 0, + TCVR_REG_SIZE, "HME Tranceiver Regs"); if (!hp->tcvregs) { printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n"); goto err_out_iounmap; @@ -2781,13 +2724,18 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe if (qp != NULL) hp->happy_flags |= HFLAG_QUATTRO; + sbus_dp = to_of_device(op->dev.parent)->node; + if (is_qfe) + sbus_dp = to_of_device(op->dev.parent->parent)->node; + /* Get the supported DVMA burst sizes from our Happy SBUS. */ - hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node, + hp->happy_bursts = of_getintprop_default(sbus_dp, "burst-sizes", 0x00); - hp->happy_block = sbus_alloc_consistent(hp->happy_dev, - PAGE_SIZE, - &hp->hblock_dvma); + hp->happy_block = dma_alloc_coherent(hp->dma_dev, + PAGE_SIZE, + &hp->hblock_dvma, + GFP_ATOMIC); err = -ENOMEM; if (!hp->happy_block) { printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n"); @@ -2816,19 +2764,13 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe /* Happy Meal can do it all... */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->irq = sdev->irqs[0]; + dev->irq = op->irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - /* Hook up PCI register/dma accessors. */ + /* Hook up SBUS register/descriptor accessors. */ hp->read_desc32 = sbus_hme_read_desc32; hp->write_txd = sbus_hme_write_txd; hp->write_rxd = sbus_hme_write_rxd; - hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single; - hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single; - hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) - sbus_dma_sync_single_for_cpu; - hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) - sbus_dma_sync_single_for_device; hp->read32 = sbus_hme_read32; hp->write32 = sbus_hme_write32; #endif @@ -2843,10 +2785,10 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe if (register_netdev(hp->dev)) { printk(KERN_ERR "happymeal: Cannot register net device, " "aborting.\n"); - goto err_out_free_consistent; + goto err_out_free_coherent; } - dev_set_drvdata(&sdev->ofdev.dev, hp); + dev_set_drvdata(&op->dev, hp); if (qfe_slot != -1) printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", @@ -2859,23 +2801,23 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe return 0; -err_out_free_consistent: - sbus_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); +err_out_free_coherent: + dma_free_coherent(hp->dma_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); err_out_iounmap: if (hp->gregs) - sbus_iounmap(hp->gregs, GREG_REG_SIZE); + of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); if (hp->etxregs) - sbus_iounmap(hp->etxregs, ETX_REG_SIZE); + of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); if (hp->erxregs) - sbus_iounmap(hp->erxregs, ERX_REG_SIZE); + of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); if (hp->bigmacregs) - sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); if (hp->tcvregs) - sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); + of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); err_out_free_netdev: free_netdev(dev); @@ -3035,6 +2977,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, memset(hp, 0, sizeof(*hp)); hp->happy_dev = pdev; + hp->dma_dev = &pdev->dev; spin_lock_init(&hp->happy_lock); @@ -3121,7 +3064,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, #endif hp->happy_block = (struct hmeal_init_block *) - pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma); + dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL); err = -ENODEV; if (!hp->happy_block) { @@ -3151,16 +3094,10 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - /* Hook up PCI register/dma accessors. */ + /* Hook up PCI register/descriptor accessors. */ hp->read_desc32 = pci_hme_read_desc32; hp->write_txd = pci_hme_write_txd; hp->write_rxd = pci_hme_write_rxd; - hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single; - hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single; - hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) - pci_dma_sync_single_for_cpu; - hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) - pci_dma_sync_single_for_device; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif @@ -3231,10 +3168,8 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev) unregister_netdev(net_dev); - pci_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); + dma_free_coherent(hp->dma_dev, PAGE_SIZE, + hp->happy_block, hp->hblock_dvma); iounmap(hp->gregs); pci_release_regions(hp->happy_dev); @@ -3279,46 +3214,45 @@ static void happy_meal_pci_exit(void) #endif #ifdef CONFIG_SBUS -static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; + struct device_node *dp = op->node; const char *model = of_get_property(dp, "model", NULL); int is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; - return happy_meal_sbus_probe_one(sdev, is_qfe); + return happy_meal_sbus_probe_one(op, is_qfe); } -static int __devexit hme_sbus_remove(struct of_device *dev) +static int __devexit hme_sbus_remove(struct of_device *op) { - struct happy_meal *hp = dev_get_drvdata(&dev->dev); + struct happy_meal *hp = dev_get_drvdata(&op->dev); struct net_device *net_dev = hp->dev; unregister_netdev(net_dev); /* XXX qfe parent interrupt... */ - sbus_iounmap(hp->gregs, GREG_REG_SIZE); - sbus_iounmap(hp->etxregs, ETX_REG_SIZE); - sbus_iounmap(hp->erxregs, ERX_REG_SIZE); - sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); - sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); - sbus_free_consistent(hp->happy_dev, - PAGE_SIZE, - hp->happy_block, - hp->hblock_dvma); + of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); + of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); + of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); + of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); + of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); + dma_free_coherent(hp->dma_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id hme_sbus_match[] = { +static const struct of_device_id hme_sbus_match[] = { { .name = "SUNW,hme", }, @@ -3346,7 +3280,7 @@ static int __init happy_meal_sbus_init(void) { int err; - err = of_register_driver(&hme_sbus_driver, &sbus_bus_type); + err = of_register_driver(&hme_sbus_driver, &of_bus_type); if (!err) quattro_sbus_register_irqs(); diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index 4da5539fac7..efd2ca0fcad 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -405,14 +405,11 @@ struct happy_meal { u32 (*read_desc32)(hme32 *); void (*write_txd)(struct happy_meal_txd *, u32, u32); void (*write_rxd)(struct happy_meal_rxd *, u32, u32); - u32 (*dma_map)(void *, void *, long, int); - void (*dma_unmap)(void *, u32, long, int); - void (*dma_sync_for_cpu)(void *, u32, long, int); - void (*dma_sync_for_device)(void *, u32, long, int); #endif - /* This is either a sbus_dev or a pci_dev. */ + /* This is either an of_device or a pci_dev. */ void *happy_dev; + struct device *dma_dev; spinlock_t happy_lock; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 4e994f87469..704301a5a7f 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -91,6 +91,9 @@ static char lancestr[] = "LANCE"; #include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/io.h> @@ -98,7 +101,6 @@ static char lancestr[] = "LANCE"; #include <asm/pgtable.h> #include <asm/byteorder.h> /* Used by the checksum routines */ #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/prom.h> #include <asm/auxio.h> /* For tpe-link-test? setting */ #include <asm/irq.h> @@ -248,7 +250,7 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct sbus_dma *ledma; /* If set this points to ledma */ + struct of_device *ledma; /* If set this points to ledma */ char tpe; /* cable-selection is TPE */ char auto_select; /* cable-selection by carrier */ char burst_sizes; /* ledma SBus burst sizes */ @@ -263,7 +265,8 @@ struct lance_private { char *name; dma_addr_t init_block_dvma; struct net_device *dev; /* Backpointer */ - struct sbus_dev *sdev; + struct of_device *op; + struct of_device *lebuffer; struct timer_list multicast_timer; }; @@ -1272,27 +1275,29 @@ static void lance_set_multicast_retry(unsigned long _opaque) static void lance_free_hwresources(struct lance_private *lp) { if (lp->lregs) - sbus_iounmap(lp->lregs, LANCE_REG_SIZE); + of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE); + if (lp->dregs) { + struct of_device *ledma = lp->ledma; + + of_iounmap(&ledma->resource[0], lp->dregs, + resource_size(&ledma->resource[0])); + } if (lp->init_block_iomem) { - sbus_iounmap(lp->init_block_iomem, - sizeof(struct lance_init_block)); + of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem, + sizeof(struct lance_init_block)); } else if (lp->init_block_mem) { - sbus_free_consistent(lp->sdev, - sizeof(struct lance_init_block), - lp->init_block_mem, - lp->init_block_dvma); + dma_free_coherent(&lp->op->dev, + sizeof(struct lance_init_block), + lp->init_block_mem, + lp->init_block_dvma); } } /* Ethtool support... */ static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lance_private *lp = netdev_priv(dev); - strcpy(info->driver, "sunlance"); strcpy(info->version, "2.02"); - sprintf(info->bus_info, "SBUS:%d", - lp->sdev->slot); } static u32 sparc_lance_get_link(struct net_device *dev) @@ -1308,16 +1313,16 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = { .get_link = sparc_lance_get_link, }; -static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, - struct sbus_dma *ledma, - struct sbus_dev *lebuffer) +static int __devinit sparc_lance_probe_one(struct of_device *op, + struct of_device *ledma, + struct of_device *lebuffer) { + struct device_node *dp = op->node; static unsigned version_printed; - struct device_node *dp = sdev->ofdev.node; - struct net_device *dev; struct lance_private *lp; - int i; + struct net_device *dev; DECLARE_MAC_BUF(mac); + int i; dev = alloc_etherdev(sizeof(struct lance_private) + 8); if (!dev) @@ -1338,14 +1343,27 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, dev->dev_addr[i] = idprom->id_ethaddr[i]; /* Get the IO region */ - lp->lregs = sbus_ioremap(&sdev->resource[0], 0, - LANCE_REG_SIZE, lancestr); + lp->lregs = of_ioremap(&op->resource[0], 0, + LANCE_REG_SIZE, lancestr); if (!lp->lregs) { printk(KERN_ERR "SunLance: Cannot map registers.\n"); goto fail; } - lp->sdev = sdev; + lp->ledma = ledma; + if (lp->ledma) { + lp->dregs = of_ioremap(&ledma->resource[0], 0, + resource_size(&ledma->resource[0]), + "ledma"); + if (!lp->dregs) { + printk(KERN_ERR "SunLance: Cannot map " + "ledma registers.\n"); + goto fail; + } + } + + lp->op = op; + lp->lebuffer = lebuffer; if (lebuffer) { /* sanity check */ if (lebuffer->resource[0].start & 7) { @@ -1353,8 +1371,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, goto fail; } lp->init_block_iomem = - sbus_ioremap(&lebuffer->resource[0], 0, - sizeof(struct lance_init_block), "lebuffer"); + of_ioremap(&lebuffer->resource[0], 0, + sizeof(struct lance_init_block), "lebuffer"); if (!lp->init_block_iomem) { printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n"); goto fail; @@ -1366,9 +1384,10 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, lp->tx = lance_tx_pio; } else { lp->init_block_mem = - sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), - &lp->init_block_dvma); - if (!lp->init_block_mem || lp->init_block_dvma == 0) { + dma_alloc_coherent(&op->dev, + sizeof(struct lance_init_block), + &lp->init_block_dvma, GFP_ATOMIC); + if (!lp->init_block_mem) { printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n"); goto fail; } @@ -1383,13 +1402,13 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, LE_C3_BCON)); lp->name = lancestr; - lp->ledma = ledma; lp->burst_sizes = 0; if (lp->ledma) { - struct device_node *ledma_dp = ledma->sdev->ofdev.node; - const char *prop; + struct device_node *ledma_dp = ledma->node; + struct device_node *sbus_dp; unsigned int sbmask; + const char *prop; u32 csr; /* Find burst-size property for ledma */ @@ -1397,7 +1416,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, "burst-sizes", 0); /* ledma may be capable of fast bursts, but sbus may not. */ - sbmask = of_getintprop_default(ledma_dp, "burst-sizes", + sbus_dp = ledma_dp->parent; + sbmask = of_getintprop_default(sbus_dp, "burst-sizes", DMA_BURSTBITS); lp->burst_sizes &= sbmask; @@ -1435,8 +1455,6 @@ no_link_test: lp->tpe = 1; } - lp->dregs = ledma->regs; - /* Reset ledma */ csr = sbus_readl(lp->dregs + DMA_CSR); sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR); @@ -1446,7 +1464,7 @@ no_link_test: lp->dregs = NULL; lp->dev = dev; - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; @@ -1455,9 +1473,7 @@ no_link_test: dev->set_multicast_list = &lance_set_multicast; dev->ethtool_ops = &sparc_lance_ethtool_ops; - dev->irq = sdev->irqs[0]; - - dev->dma = 0; + dev->irq = op->irqs[0]; /* We cannot sleep if the chip is busy during a * multicast list update event, because such events @@ -1473,7 +1489,7 @@ no_link_test: goto fail; } - dev_set_drvdata(&sdev->ofdev.dev, lp); + dev_set_drvdata(&op->dev, lp); printk(KERN_INFO "%s: LANCE %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -1486,80 +1502,25 @@ fail: return -ENODEV; } -/* On 4m, find the associated dma for the lance chip */ -static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev) -{ - struct sbus_dma *p; - - for_each_dvma(p) { - if (p->sdev == sdev) - return p; - } - return NULL; -} - -#ifdef CONFIG_SUN4 - -#include <asm/sun4paddr.h> -#include <asm/machines.h> - -/* Find all the lance cards on the system and initialize them */ -static struct sbus_dev sun4_sdev; -static int __devinit sparc_lance_init(void) -{ - if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || - (idprom->id_machtype == (SM_SUN4|SM_4_470))) { - memset(&sun4_sdev, 0, sizeof(struct sbus_dev)); - sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; - sun4_sdev.irqs[0] = 6; - return sparc_lance_probe_one(&sun4_sdev, NULL, NULL); - } - return -ENODEV; -} - -static int __exit sunlance_sun4_remove(void) +static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev); - struct net_device *net_dev = lp->dev; - - unregister_netdev(net_dev); - - lance_free_hwresources(lp); - - free_netdev(net_dev); - - dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL); - - return 0; -} - -#else /* !CONFIG_SUN4 */ - -static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct of_device *parent = to_of_device(op->dev.parent); + struct device_node *parent_dp = parent->node; int err; - if (sdev->parent) { - struct of_device *parent = &sdev->parent->ofdev; - - if (!strcmp(parent->node->name, "ledma")) { - struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev)); - - err = sparc_lance_probe_one(sdev, ledma, NULL); - } else if (!strcmp(parent->node->name, "lebuffer")) { - err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev)); - } else - err = sparc_lance_probe_one(sdev, NULL, NULL); + if (!strcmp(parent_dp->name, "ledma")) { + err = sparc_lance_probe_one(op, parent, NULL); + } else if (!strcmp(parent_dp->name, "lebuffer")) { + err = sparc_lance_probe_one(op, NULL, parent); } else - err = sparc_lance_probe_one(sdev, NULL, NULL); + err = sparc_lance_probe_one(op, NULL, NULL); return err; } -static int __devexit sunlance_sbus_remove(struct of_device *dev) +static int __devexit sunlance_sbus_remove(struct of_device *op) { - struct lance_private *lp = dev_get_drvdata(&dev->dev); + struct lance_private *lp = dev_get_drvdata(&op->dev); struct net_device *net_dev = lp->dev; unregister_netdev(net_dev); @@ -1568,12 +1529,12 @@ static int __devexit sunlance_sbus_remove(struct of_device *dev) free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id sunlance_sbus_match[] = { +static const struct of_device_id sunlance_sbus_match[] = { { .name = "le", }, @@ -1593,17 +1554,12 @@ static struct of_platform_driver sunlance_sbus_driver = { /* Find all the lance cards on the system and initialize them */ static int __init sparc_lance_init(void) { - return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type); + return of_register_driver(&sunlance_sbus_driver, &of_bus_type); } -#endif /* !CONFIG_SUN4 */ static void __exit sparc_lance_exit(void) { -#ifdef CONFIG_SUN4 - sunlance_sun4_remove(); -#else of_unregister_driver(&sunlance_sbus_driver); -#endif } module_init(sparc_lance_init); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index e811331d460..f63644744ff 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -3,7 +3,7 @@ * controller out there can be most efficiently programmed * if you make it look like a LANCE. * - * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -24,13 +24,15 @@ #include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/bitops.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/io.h> #include <asm/dma.h> #include <asm/byteorder.h> #include <asm/idprom.h> -#include <asm/sbus.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/auxio.h> @@ -40,8 +42,8 @@ #include "sunqe.h" #define DRV_NAME "sunqe" -#define DRV_VERSION "4.0" -#define DRV_RELDATE "June 23, 2006" +#define DRV_VERSION "4.1" +#define DRV_RELDATE "August 27, 2008" #define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" static char version[] = @@ -690,12 +692,18 @@ static void qe_set_multicast(struct net_device *dev) /* Ethtool support... */ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + const struct linux_prom_registers *regs; struct sunqe *qep = dev->priv; + struct of_device *op; strcpy(info->driver, "sunqe"); strcpy(info->version, "3.0"); - sprintf(info->bus_info, "SBUS:%d", - qep->qe_sdev->slot); + + op = qep->op; + regs = of_get_property(op->node, "reg", NULL); + if (regs) + sprintf(info->bus_info, "SBUS:%d", regs->which_io); + } static u32 qe_get_link(struct net_device *dev) @@ -717,11 +725,11 @@ static const struct ethtool_ops qe_ethtool_ops = { }; /* This is only called once at boot time for each card probed. */ -static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) +static void qec_init_once(struct sunqec *qecp, struct of_device *op) { u8 bsizes = qecp->qec_bursts; - if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) { + if (sbus_can_burst64() && (bsizes & DMA_BURST64)) { sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL); } else if (bsizes & DMA_BURST32) { sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL); @@ -735,15 +743,15 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev) sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE); /* Set the local memsize register, divided up to one piece per QE channel. */ - sbus_writel((qsdev->reg_addrs[1].reg_size >> 2), + sbus_writel((resource_size(&op->resource[1]) >> 2), qecp->gregs + GLOB_MSIZE); /* Divide up the local QEC memory amongst the 4 QE receiver and * transmitter FIFOs. Basically it is (total / 2 / num_channels). */ - sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1, + sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1, qecp->gregs + GLOB_TSIZE); - sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1, + sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1, qecp->gregs + GLOB_RSIZE); } @@ -767,24 +775,21 @@ static u8 __devinit qec_get_burst(struct device_node *dp) return bsizes; } -static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) +static struct sunqec * __devinit get_qec(struct of_device *child) { - struct sbus_dev *qec_sdev = child_sdev->parent; + struct of_device *op = to_of_device(child->dev.parent); struct sunqec *qecp; - for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) { - if (qecp->qec_sdev == qec_sdev) - break; - } + qecp = dev_get_drvdata(&op->dev); if (!qecp) { qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL); if (qecp) { u32 ctrl; - qecp->qec_sdev = qec_sdev; - qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0, - GLOB_REG_SIZE, - "QEC Global Registers"); + qecp->op = op; + qecp->gregs = of_ioremap(&op->resource[0], 0, + GLOB_REG_SIZE, + "QEC Global Registers"); if (!qecp->gregs) goto fail; @@ -799,16 +804,18 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) if (qec_global_reset(qecp->gregs)) goto fail; - qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node); + qecp->qec_bursts = qec_get_burst(op->node); - qec_init_once(qecp, qec_sdev); + qec_init_once(qecp, op); - if (request_irq(qec_sdev->irqs[0], &qec_interrupt, + if (request_irq(op->irqs[0], &qec_interrupt, IRQF_SHARED, "qec", (void *) qecp)) { printk(KERN_ERR "qec: Can't register irq.\n"); goto fail; } + dev_set_drvdata(&op->dev, qecp); + qecp->next_module = root_qec_dev; root_qec_dev = qecp; } @@ -818,17 +825,17 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev) fail: if (qecp->gregs) - sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); + of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE); kfree(qecp); return NULL; } -static int __devinit qec_ether_init(struct sbus_dev *sdev) +static int __devinit qec_ether_init(struct of_device *op) { static unsigned version_printed; struct net_device *dev; - struct sunqe *qe; struct sunqec *qecp; + struct sunqe *qe; int i, res; if (version_printed++ == 0) @@ -842,49 +849,42 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) qe = netdev_priv(dev); - i = of_getintprop_default(sdev->ofdev.node, "channel#", -1); - if (i == -1) { - struct sbus_dev *td = sdev->parent->child; - i = 0; - while (td != sdev) { - td = td->next; - i++; - } - } + res = -ENODEV; + + i = of_getintprop_default(op->node, "channel#", -1); + if (i == -1) + goto fail; qe->channel = i; spin_lock_init(&qe->lock); - res = -ENODEV; - qecp = get_qec(sdev); + qecp = get_qec(op); if (!qecp) goto fail; qecp->qes[qe->channel] = qe; qe->dev = dev; qe->parent = qecp; - qe->qe_sdev = sdev; + qe->op = op; res = -ENOMEM; - qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, - CREG_REG_SIZE, "QEC Channel Registers"); + qe->qcregs = of_ioremap(&op->resource[0], 0, + CREG_REG_SIZE, "QEC Channel Registers"); if (!qe->qcregs) { printk(KERN_ERR "qe: Cannot map channel registers.\n"); goto fail; } - qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, - MREGS_REG_SIZE, "QE MACE Registers"); + qe->mregs = of_ioremap(&op->resource[1], 0, + MREGS_REG_SIZE, "QE MACE Registers"); if (!qe->mregs) { printk(KERN_ERR "qe: Cannot map MACE registers.\n"); goto fail; } - qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, - PAGE_SIZE, - &qe->qblock_dvma); - qe->buffers = sbus_alloc_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - &qe->buffers_dvma); + qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE, + &qe->qblock_dvma, GFP_ATOMIC); + qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers), + &qe->buffers_dvma, GFP_ATOMIC); if (qe->qe_block == NULL || qe->qblock_dvma == 0 || qe->buffers == NULL || qe->buffers_dvma == 0) goto fail; @@ -892,7 +892,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) /* Stop this QE. */ qe_stop(qe); - SET_NETDEV_DEV(dev, &sdev->ofdev.dev); + SET_NETDEV_DEV(dev, &op->dev); dev->open = qe_open; dev->stop = qe_close; @@ -900,7 +900,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) dev->set_multicast_list = qe_set_multicast; dev->tx_timeout = qe_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->irq = sdev->irqs[0]; + dev->irq = op->irqs[0]; dev->dma = 0; dev->ethtool_ops = &qe_ethtool_ops; @@ -908,7 +908,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) if (res) goto fail; - dev_set_drvdata(&sdev->ofdev.dev, qe); + dev_set_drvdata(&op->dev, qe); printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel); for (i = 0; i < 6; i++) @@ -922,58 +922,50 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev) fail: if (qe->qcregs) - sbus_iounmap(qe->qcregs, CREG_REG_SIZE); + of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE); if (qe->mregs) - sbus_iounmap(qe->mregs, MREGS_REG_SIZE); + of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE); if (qe->qe_block) - sbus_free_consistent(qe->qe_sdev, - PAGE_SIZE, - qe->qe_block, - qe->qblock_dvma); + dma_free_coherent(&op->dev, PAGE_SIZE, + qe->qe_block, qe->qblock_dvma); if (qe->buffers) - sbus_free_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - qe->buffers, - qe->buffers_dvma); + dma_free_coherent(&op->dev, + sizeof(struct sunqe_buffers), + qe->buffers, + qe->buffers_dvma); free_netdev(dev); return res; } -static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - - return qec_ether_init(sdev); + return qec_ether_init(op); } -static int __devexit qec_sbus_remove(struct of_device *dev) +static int __devexit qec_sbus_remove(struct of_device *op) { - struct sunqe *qp = dev_get_drvdata(&dev->dev); + struct sunqe *qp = dev_get_drvdata(&op->dev); struct net_device *net_dev = qp->dev; unregister_netdev(net_dev); - sbus_iounmap(qp->qcregs, CREG_REG_SIZE); - sbus_iounmap(qp->mregs, MREGS_REG_SIZE); - sbus_free_consistent(qp->qe_sdev, - PAGE_SIZE, - qp->qe_block, - qp->qblock_dvma); - sbus_free_consistent(qp->qe_sdev, - sizeof(struct sunqe_buffers), - qp->buffers, - qp->buffers_dvma); + of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE); + of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE); + dma_free_coherent(&op->dev, PAGE_SIZE, + qp->qe_block, qp->qblock_dvma); + dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers), + qp->buffers, qp->buffers_dvma); free_netdev(net_dev); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id qec_sbus_match[] = { +static const struct of_device_id qec_sbus_match[] = { { .name = "qe", }, @@ -991,7 +983,7 @@ static struct of_platform_driver qec_sbus_driver = { static int __init qec_init(void) { - return of_register_driver(&qec_sbus_driver, &sbus_bus_type); + return of_register_driver(&qec_sbus_driver, &of_bus_type); } static void __exit qec_exit(void) @@ -1000,11 +992,11 @@ static void __exit qec_exit(void) while (root_qec_dev) { struct sunqec *next = root_qec_dev->next_module; + struct of_device *op = root_qec_dev->op; - free_irq(root_qec_dev->qec_sdev->irqs[0], - (void *) root_qec_dev); - sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE); - + free_irq(op->irqs[0], (void *) root_qec_dev); + of_iounmap(&op->resource[0], root_qec_dev->gregs, + GLOB_REG_SIZE); kfree(root_qec_dev); root_qec_dev = next; diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h index 347c8ddc159..5813a7b2faa 100644 --- a/drivers/net/sunqe.h +++ b/drivers/net/sunqe.h @@ -314,7 +314,7 @@ struct sunqec { void __iomem *gregs; /* QEC Global Registers */ struct sunqe *qes[4]; /* Each child MACE */ unsigned int qec_bursts; /* Support burst sizes */ - struct sbus_dev *qec_sdev; /* QEC's SBUS device */ + struct of_device *op; /* QEC's OF device */ struct sunqec *next_module; /* List of all QECs in system */ }; @@ -342,7 +342,7 @@ struct sunqe { __u32 buffers_dvma; /* DVMA visible address. */ struct sunqec *parent; u8 mconfig; /* Base MACE mconfig value */ - struct sbus_dev *qe_sdev; /* QE's SBUS device struct */ + struct of_device *op; /* QE's OF device struct */ struct net_device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ }; diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index 6415ce15c2e..a720065553d 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1,6 +1,6 @@ /* sunvnet.c: Sun LDOM Virtual Network Driver. * - * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> */ #include <linux/module.h> @@ -1260,7 +1260,7 @@ static int vnet_port_remove(struct vio_dev *vdev) return 0; } -static struct vio_device_id vnet_port_match[] = { +static const struct vio_device_id vnet_port_match[] = { { .type = "vnet-port", }, diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 9d595aa91e4..065f229580d 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -26,6 +26,8 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/parport.h> @@ -34,7 +36,6 @@ #include <asm/io.h> #include <asm/oplib.h> /* OpenProm Library */ -#include <asm/sbus.h> #include <asm/dma.h> /* BPP uses LSI 64854 for DMA */ #include <asm/irq.h> #include <asm/sunbpp.h> @@ -285,38 +286,37 @@ static struct parport_operations parport_sunbpp_ops = .owner = THIS_MODULE, }; -static int __devinit init_one_port(struct sbus_dev *sdev) +static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match) { - struct parport *p; - /* at least in theory there may be a "we don't dma" case */ struct parport_operations *ops; - void __iomem *base; - int irq, dma, err = 0, size; struct bpp_regs __iomem *regs; + int irq, dma, err = 0, size; unsigned char value_tcr; + void __iomem *base; + struct parport *p; - irq = sdev->irqs[0]; - base = sbus_ioremap(&sdev->resource[0], 0, - sdev->reg_addrs[0].reg_size, - "sunbpp"); + irq = op->irqs[0]; + base = of_ioremap(&op->resource[0], 0, + resource_size(&op->resource[0]), + "sunbpp"); if (!base) return -ENODEV; - size = sdev->reg_addrs[0].reg_size; + size = resource_size(&op->resource[0]); dma = PARPORT_DMA_NONE; ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); if (!ops) goto out_unmap; - memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); + memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations)); dprintk(("register_port\n")); if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) goto out_free_ops; p->size = size; - p->dev = &sdev->ofdev.dev; + p->dev = &op->dev; if ((err = request_irq(p->irq, parport_irq_handler, IRQF_SHARED, p->name, p)) != 0) { @@ -333,7 +333,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev) printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); - dev_set_drvdata(&sdev->ofdev.dev, p); + dev_set_drvdata(&op->dev, p); parport_announce_port(p); @@ -346,21 +346,14 @@ out_free_ops: kfree(ops); out_unmap: - sbus_iounmap(base, size); + of_iounmap(&op->resource[0], base, size); return err; } -static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - - return init_one_port(sdev); -} - -static int __devexit bpp_remove(struct of_device *dev) +static int __devexit bpp_remove(struct of_device *op) { - struct parport *p = dev_get_drvdata(&dev->dev); + struct parport *p = dev_get_drvdata(&op->dev); struct parport_operations *ops = p->ops; parport_remove_port(p); @@ -370,16 +363,16 @@ static int __devexit bpp_remove(struct of_device *dev) free_irq(p->irq, p); } - sbus_iounmap((void __iomem *) p->base, p->size); + of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size); parport_put_port(p); kfree(ops); - dev_set_drvdata(&dev->dev, NULL); + dev_set_drvdata(&op->dev, NULL); return 0; } -static struct of_device_id bpp_match[] = { +static const struct of_device_id bpp_match[] = { { .name = "SUNW,bpp", }, @@ -397,7 +390,7 @@ static struct of_platform_driver bpp_sbus_driver = { static int __init parport_sunbpp_init(void) { - return of_register_driver(&bpp_sbus_driver, &sbus_bus_type); + return of_register_driver(&bpp_sbus_driver, &of_bus_type); } static void __exit parport_sunbpp_exit(void) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9a9755c92fa..b57fba5c6d0 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -329,7 +329,7 @@ comment "Platform RTC drivers" config RTC_DRV_CMOS tristate "PC-style 'CMOS'" - depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS + depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64 default y if X86 help Say "yes" here to get direct support for the real time clock @@ -406,14 +406,26 @@ config RTC_DRV_M48T86 will be called rtc-m48t86. config RTC_DRV_M48T59 - tristate "ST M48T59" + tristate "ST M48T59/M48T08/M48T02" help If you say Y here you will get support for the - ST M48T59 RTC chip. + ST M48T59 RTC chip and compatible ST M48T08 and M48T02. + + These chips are usually found in Sun SPARC and UltraSPARC + workstations. This driver can also be built as a module, if so, the module will be called "rtc-m48t59". +config RTC_DRV_BQ4802 + tristate "TI BQ4802" + help + If you say Y here you will get support for the TI + BQ4802 RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-bq4802. + config RTC_DRV_V3020 tristate "EM Microelectronic V3020" help @@ -583,4 +595,18 @@ config RTC_DRV_PPC the RTC. This exposes that functionality through the generic RTC class. +config RTC_DRV_SUN4V + bool "SUN4V Hypervisor RTC" + depends on SPARC64 + help + If you say Y here you will get support for the Hypervisor + based RTC on SUN4V systems. + +config RTC_DRV_STARFIRE + bool "Starfire RTC" + depends on SPARC64 + help + If you say Y here you will get support for the RTC found on + Starfire systems. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 18622ef84ca..10f41f85c38 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -38,6 +38,9 @@ obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o +obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o +obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o +obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c new file mode 100644 index 00000000000..189a018bdf3 --- /dev/null +++ b/drivers/rtc/rtc-bq4802.c @@ -0,0 +1,230 @@ +/* rtc-bq4802.c: TI BQ4802 RTC driver. + * + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/bcd.h> + +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_DESCRIPTION("TI BQ4802 RTC driver"); +MODULE_LICENSE("GPL"); + +struct bq4802 { + void __iomem *regs; + unsigned long ioport; + struct rtc_device *rtc; + spinlock_t lock; + struct resource *r; + u8 (*read)(struct bq4802 *, int); + void (*write)(struct bq4802 *, int, u8); +}; + +static u8 bq4802_read_io(struct bq4802 *p, int off) +{ + return inb(p->ioport + off); +} + +static void bq4802_write_io(struct bq4802 *p, int off, u8 val) +{ + outb(val, p->ioport + off); +} + +static u8 bq4802_read_mem(struct bq4802 *p, int off) +{ + return readb(p->regs + off); +} + +static void bq4802_write_mem(struct bq4802 *p, int off, u8 val) +{ + writeb(val, p->regs + off); +} + +static int bq4802_read_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bq4802 *p = platform_get_drvdata(pdev); + unsigned long flags; + unsigned int century; + u8 val; + + spin_lock_irqsave(&p->lock, flags); + + val = p->read(p, 0x0e); + p->write(p, 0xe, val | 0x08); + + tm->tm_sec = p->read(p, 0x00); + tm->tm_min = p->read(p, 0x02); + tm->tm_hour = p->read(p, 0x04); + tm->tm_mday = p->read(p, 0x06); + tm->tm_mon = p->read(p, 0x09); + tm->tm_year = p->read(p, 0x0a); + tm->tm_wday = p->read(p, 0x08); + century = p->read(p, 0x0f); + + p->write(p, 0x0e, val); + + spin_unlock_irqrestore(&p->lock, flags); + + BCD_TO_BIN(tm->tm_sec); + BCD_TO_BIN(tm->tm_min); + BCD_TO_BIN(tm->tm_hour); + BCD_TO_BIN(tm->tm_mday); + BCD_TO_BIN(tm->tm_mon); + BCD_TO_BIN(tm->tm_year); + BCD_TO_BIN(tm->tm_wday); + BCD_TO_BIN(century); + + tm->tm_year += (century * 100); + tm->tm_year -= 1900; + + tm->tm_mon--; + + return 0; +} + +static int bq4802_set_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bq4802 *p = platform_get_drvdata(pdev); + u8 sec, min, hrs, day, mon, yrs, century, val; + unsigned long flags; + unsigned int year; + + year = tm->tm_year + 1900; + century = year / 100; + yrs = year % 100; + + mon = tm->tm_mon + 1; /* tm_mon starts at zero */ + day = tm->tm_mday; + hrs = tm->tm_hour; + min = tm->tm_min; + sec = tm->tm_sec; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + BIN_TO_BCD(century); + + spin_lock_irqsave(&p->lock, flags); + + val = p->read(p, 0x0e); + p->write(p, 0x0e, val | 0x08); + + p->write(p, 0x00, sec); + p->write(p, 0x02, min); + p->write(p, 0x04, hrs); + p->write(p, 0x06, day); + p->write(p, 0x09, mon); + p->write(p, 0x0a, yrs); + p->write(p, 0x0f, century); + + p->write(p, 0x0e, val); + + spin_unlock_irqrestore(&p->lock, flags); + + return 0; +} + +static const struct rtc_class_ops bq4802_ops = { + .read_time = bq4802_read_time, + .set_time = bq4802_set_time, +}; + +static int __devinit bq4802_probe(struct platform_device *pdev) +{ + struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL); + int err = -ENOMEM; + + if (!p) + goto out; + + spin_lock_init(&p->lock); + + p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!p->r) { + p->r = platform_get_resource(pdev, IORESOURCE_IO, 0); + err = -EINVAL; + if (!p->r) + goto out_free; + } + if (p->r->flags & IORESOURCE_IO) { + p->ioport = p->r->start; + p->read = bq4802_read_io; + p->write = bq4802_write_io; + } else if (p->r->flags & IORESOURCE_MEM) { + p->regs = ioremap(p->r->start, resource_size(p->r)); + p->read = bq4802_read_mem; + p->write = bq4802_write_mem; + } else { + err = -EINVAL; + goto out_free; + } + + p->rtc = rtc_device_register("bq4802", &pdev->dev, + &bq4802_ops, THIS_MODULE); + if (IS_ERR(p->rtc)) { + err = PTR_ERR(p->rtc); + goto out_iounmap; + } + + platform_set_drvdata(pdev, p); + err = 0; +out: + return err; + +out_iounmap: + if (p->r->flags & IORESOURCE_MEM) + iounmap(p->regs); +out_free: + kfree(p); + goto out; +} + +static int __devexit bq4802_remove(struct platform_device *pdev) +{ + struct bq4802 *p = platform_get_drvdata(pdev); + + rtc_device_unregister(p->rtc); + if (p->r->flags & IORESOURCE_MEM) + iounmap(p->regs); + + platform_set_drvdata(pdev, NULL); + + kfree(p); + + return 0; +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:rtc-bq4802"); + +static struct platform_driver bq4802_driver = { + .driver = { + .name = "rtc-bq4802", + .owner = THIS_MODULE, + }, + .probe = bq4802_probe, + .remove = __devexit_p(bq4802_remove), +}; + +static int __init bq4802_init(void) +{ + return platform_driver_register(&bq4802_driver); +} + +static void __exit bq4802_exit(void) +{ + platform_driver_unregister(&bq4802_driver); +} + +module_init(bq4802_init); +module_exit(bq4802_exit); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index b184367637d..b23af0c2a86 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -636,7 +636,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) */ #if defined(CONFIG_ATARI) address_space = 64; -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) +#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__) address_space = 128; #else #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. @@ -699,7 +699,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) /* FIXME teach the alarm code how to handle binary mode; * <asm-generic/rtc.h> doesn't know 12-hour mode either. */ - if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) { + if (is_valid_irq(rtc_irq) && + (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) { dev_dbg(dev, "only 24-hr BCD mode supported\n"); retval = -ENXIO; goto cleanup1; diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 013e6c103b9..ce4eff6a8d5 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -24,8 +24,9 @@ #define NO_IRQ (-1) #endif -#define M48T59_READ(reg) pdata->read_byte(dev, reg) -#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val) +#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg)) +#define M48T59_WRITE(val, reg) \ + (pdata->write_byte(dev, pdata->offset + reg, val)) #define M48T59_SET_BITS(mask, reg) \ M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg)) @@ -34,7 +35,6 @@ struct m48t59_private { void __iomem *ioaddr; - unsigned int size; /* iomem size */ int irq; struct rtc_device *rtc; spinlock_t lock; /* serialize the NVRAM and RTC access */ @@ -82,7 +82,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY)); val = M48T59_READ(M48T59_WDAY); - if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { + if ((pdata->type == M48T59RTC_TYPE_M48T59) && + (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { dev_dbg(dev, "Century bit is enabled\n"); tm->tm_year += 100; /* one century */ } @@ -126,7 +127,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR); - if (tm->tm_year/100) + if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100)) val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); val |= (BIN2BCD(tm->tm_wday) & 0x07); M48T59_WRITE(val, M48T59_WDAY); @@ -310,6 +311,11 @@ static const struct rtc_class_ops m48t59_rtc_ops = { .proc = m48t59_rtc_proc, }; +static const struct rtc_class_ops m48t02_rtc_ops = { + .read_time = m48t59_rtc_read_time, + .set_time = m48t59_rtc_set_time, +}; + static ssize_t m48t59_nvram_read(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) @@ -321,7 +327,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { + for (; size > 0 && pos < pdata->offset; cnt++, size--) { spin_lock_irqsave(&m48t59->lock, flags); *buf++ = M48T59_READ(cnt); spin_unlock_irqrestore(&m48t59->lock, flags); @@ -341,7 +347,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { + for (; size > 0 && pos < pdata->offset; cnt++, size--) { spin_lock_irqsave(&m48t59->lock, flags); M48T59_WRITE(*buf++, cnt); spin_unlock_irqrestore(&m48t59->lock, flags); @@ -358,7 +364,6 @@ static struct bin_attribute m48t59_nvram_attr = { }, .read = m48t59_nvram_read, .write = m48t59_nvram_write, - .size = M48T59_NVRAM_SIZE, }; static int __devinit m48t59_rtc_probe(struct platform_device *pdev) @@ -367,6 +372,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) struct m48t59_private *m48t59 = NULL; struct resource *res; int ret = -ENOMEM; + char *name; + const struct rtc_class_ops *ops; /* This chip could be memory-mapped or I/O-mapped */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -391,6 +398,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) /* Ensure we only kmalloc platform data once */ pdev->dev.platform_data = pdata; } + if (!pdata->type) + pdata->type = M48T59RTC_TYPE_M48T59; /* Try to use the generic memory read/write ops */ if (!pdata->write_byte) @@ -403,10 +412,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) if (!m48t59) return -ENOMEM; - m48t59->size = res->end - res->start + 1; - m48t59->ioaddr = ioremap(res->start, m48t59->size); - if (!m48t59->ioaddr) - goto out; + m48t59->ioaddr = pdata->ioaddr; + + if (!m48t59->ioaddr) { + /* ioaddr not mapped externally */ + m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1); + if (!m48t59->ioaddr) + goto out; + } /* Try to get irq number. We also can work in * the mode without IRQ. @@ -421,14 +434,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) if (ret) goto out; } + switch (pdata->type) { + case M48T59RTC_TYPE_M48T59: + name = "m48t59"; + ops = &m48t59_rtc_ops; + pdata->offset = 0x1ff0; + break; + case M48T59RTC_TYPE_M48T02: + name = "m48t02"; + ops = &m48t02_rtc_ops; + pdata->offset = 0x7f0; + break; + case M48T59RTC_TYPE_M48T08: + name = "m48t08"; + ops = &m48t02_rtc_ops; + pdata->offset = 0x1ff0; + break; + default: + dev_err(&pdev->dev, "Unknown RTC type\n"); + ret = -ENODEV; + goto out; + } - m48t59->rtc = rtc_device_register("m48t59", &pdev->dev, - &m48t59_rtc_ops, THIS_MODULE); + m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); if (IS_ERR(m48t59->rtc)) { ret = PTR_ERR(m48t59->rtc); goto out; } + m48t59_nvram_attr.size = pdata->offset; + ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (ret) goto out; @@ -452,11 +487,12 @@ out: static int __devexit m48t59_rtc_remove(struct platform_device *pdev) { struct m48t59_private *m48t59 = platform_get_drvdata(pdev); + struct m48t59_plat_data *pdata = pdev->dev.platform_data; sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (!IS_ERR(m48t59->rtc)) rtc_device_unregister(m48t59->rtc); - if (m48t59->ioaddr) + if (m48t59->ioaddr && !pdata->ioaddr) iounmap(m48t59->ioaddr); if (m48t59->irq != NO_IRQ) free_irq(m48t59->irq, &pdev->dev); @@ -491,5 +527,5 @@ module_init(m48t59_rtc_init); module_exit(m48t59_rtc_exit); MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); -MODULE_DESCRIPTION("M48T59 RTC driver"); +MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c new file mode 100644 index 00000000000..7ccb0dd700a --- /dev/null +++ b/drivers/rtc/rtc-starfire.c @@ -0,0 +1,120 @@ +/* rtc-starfire.c: Starfire platform RTC driver. + * + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +#include <asm/oplib.h> + +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_DESCRIPTION("Starfire RTC driver"); +MODULE_LICENSE("GPL"); + +struct starfire_rtc { + struct rtc_device *rtc; + spinlock_t lock; +}; + +static u32 starfire_get_time(void) +{ + static char obp_gettod[32]; + static u32 unix_tod; + + sprintf(obp_gettod, "h# %08x unix-gettod", + (unsigned int) (long) &unix_tod); + prom_feval(obp_gettod); + + return unix_tod; +} + +static int starfire_read_time(struct device *dev, struct rtc_time *tm) +{ + struct starfire_rtc *p = dev_get_drvdata(dev); + unsigned long flags, secs; + + spin_lock_irqsave(&p->lock, flags); + secs = starfire_get_time(); + spin_unlock_irqrestore(&p->lock, flags); + + rtc_time_to_tm(secs, tm); + + return 0; +} + +static int starfire_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long secs; + int err; + + err = rtc_tm_to_time(tm, &secs); + if (err) + return err; + + /* Do nothing, time is set using the service processor + * console on this platform. + */ + return 0; +} + +static const struct rtc_class_ops starfire_rtc_ops = { + .read_time = starfire_read_time, + .set_time = starfire_set_time, +}; + +static int __devinit starfire_rtc_probe(struct platform_device *pdev) +{ + struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL); + + if (!p) + return -ENOMEM; + + spin_lock_init(&p->lock); + + p->rtc = rtc_device_register("starfire", &pdev->dev, + &starfire_rtc_ops, THIS_MODULE); + if (IS_ERR(p->rtc)) { + int err = PTR_ERR(p->rtc); + kfree(p); + return err; + } + platform_set_drvdata(pdev, p); + return 0; +} + +static int __devexit starfire_rtc_remove(struct platform_device *pdev) +{ + struct starfire_rtc *p = platform_get_drvdata(pdev); + + rtc_device_unregister(p->rtc); + kfree(p); + + return 0; +} + +static struct platform_driver starfire_rtc_driver = { + .driver = { + .name = "rtc-starfire", + .owner = THIS_MODULE, + }, + .probe = starfire_rtc_probe, + .remove = __devexit_p(starfire_rtc_remove), +}; + +static int __init starfire_rtc_init(void) +{ + return platform_driver_register(&starfire_rtc_driver); +} + +static void __exit starfire_rtc_exit(void) +{ + platform_driver_unregister(&starfire_rtc_driver); +} + +module_init(starfire_rtc_init); +module_exit(starfire_rtc_exit); diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c new file mode 100644 index 00000000000..2012ccbb4a5 --- /dev/null +++ b/drivers/rtc/rtc-sun4v.c @@ -0,0 +1,153 @@ +/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems. + * + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +#include <asm/hypervisor.h> + +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_DESCRIPTION("SUN4V RTC driver"); +MODULE_LICENSE("GPL"); + +struct sun4v_rtc { + struct rtc_device *rtc; + spinlock_t lock; +}; + +static unsigned long hypervisor_get_time(void) +{ + unsigned long ret, time; + int retries = 10000; + +retry: + ret = sun4v_tod_get(&time); + if (ret == HV_EOK) + return time; + if (ret == HV_EWOULDBLOCK) { + if (--retries > 0) { + udelay(100); + goto retry; + } + printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); + return 0; + } + printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); + return 0; +} + +static int sun4v_read_time(struct device *dev, struct rtc_time *tm) +{ + struct sun4v_rtc *p = dev_get_drvdata(dev); + unsigned long flags, secs; + + spin_lock_irqsave(&p->lock, flags); + secs = hypervisor_get_time(); + spin_unlock_irqrestore(&p->lock, flags); + + rtc_time_to_tm(secs, tm); + + return 0; +} + +static int hypervisor_set_time(unsigned long secs) +{ + unsigned long ret; + int retries = 10000; + +retry: + ret = sun4v_tod_set(secs); + if (ret == HV_EOK) + return 0; + if (ret == HV_EWOULDBLOCK) { + if (--retries > 0) { + udelay(100); + goto retry; + } + printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); + return -EAGAIN; + } + printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); + return -EOPNOTSUPP; +} + +static int sun4v_set_time(struct device *dev, struct rtc_time *tm) +{ + struct sun4v_rtc *p = dev_get_drvdata(dev); + unsigned long flags, secs; + int err; + + err = rtc_tm_to_time(tm, &secs); + if (err) + return err; + + spin_lock_irqsave(&p->lock, flags); + err = hypervisor_set_time(secs); + spin_unlock_irqrestore(&p->lock, flags); + + return err; +} + +static const struct rtc_class_ops sun4v_rtc_ops = { + .read_time = sun4v_read_time, + .set_time = sun4v_set_time, +}; + +static int __devinit sun4v_rtc_probe(struct platform_device *pdev) +{ + struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL); + + if (!p) + return -ENOMEM; + + spin_lock_init(&p->lock); + + p->rtc = rtc_device_register("sun4v", &pdev->dev, + &sun4v_rtc_ops, THIS_MODULE); + if (IS_ERR(p->rtc)) { + int err = PTR_ERR(p->rtc); + kfree(p); + return err; + } + platform_set_drvdata(pdev, p); + return 0; +} + +static int __devexit sun4v_rtc_remove(struct platform_device *pdev) +{ + struct sun4v_rtc *p = platform_get_drvdata(pdev); + + rtc_device_unregister(p->rtc); + kfree(p); + + return 0; +} + +static struct platform_driver sun4v_rtc_driver = { + .driver = { + .name = "rtc-sun4v", + .owner = THIS_MODULE, + }, + .probe = sun4v_rtc_probe, + .remove = __devexit_p(sun4v_rtc_remove), +}; + +static int __init sun4v_rtc_init(void) +{ + return platform_driver_register(&sun4v_rtc_driver); +} + +static void __exit sun4v_rtc_exit(void) +{ + platform_driver_unregister(&sun4v_rtc_driver); +} + +module_init(sun4v_rtc_init); +module_exit(sun4v_rtc_exit); diff --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile index 7b1d24d9530..e94dc25805f 100644 --- a/drivers/sbus/Makefile +++ b/drivers/sbus/Makefile @@ -2,8 +2,4 @@ # Makefile for the linux kernel. # -ifneq ($(ARCH),m68k) -obj-y := sbus.o dvma.o -endif - obj-$(CONFIG_SBUSCHAR) += char/ diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index 400c65bfb8c..73cde85d04d 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -13,16 +13,6 @@ config SUN_OPENPROMIO If unsure, say Y. -config SUN_MOSTEK_RTC - tristate "Mostek real time clock support" - depends on SPARC32 - help - The Mostek RTC chip is used on all known Sun computers except - some JavaStations. For a JavaStation you need to say Y both here - and to "Enhanced Real Time Clock Support". - - Say Y here unless you are building a special purpose kernel. - config OBP_FLASH tristate "OBP Flash Device support" depends on SPARC64 @@ -30,26 +20,9 @@ config OBP_FLASH The OpenBoot PROM on Ultra systems is flashable. If you want to be able to upgrade the OBP firmware, say Y here. -config SUN_BPP - tristate "Bidirectional parallel port support (OBSOLETE)" - depends on EXPERIMENTAL - help - Say Y here to support Sun's obsolete variant of IEEE1284 - bidirectional parallel port protocol as /dev/bppX. Can be built on - x86 machines. - -config SUN_VIDEOPIX - tristate "Videopix Frame Grabber (EXPERIMENTAL)" - depends on EXPERIMENTAL && (BROKEN || !64BIT) - help - Say Y here to support the Videopix Frame Grabber from Sun - Microsystems, commonly found on SPARCstations. This card, which is - based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and - SVIDEO signals. - 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 diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index 7ab060e9a5f..78b6183c986 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -7,18 +7,12 @@ # Rewritten to use lists instead of if-statements. # -vfc-objs := vfc_dev.o vfc_i2c.o bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o -obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o -obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o -obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o -obj-$(CONFIG_SUN_BPP) += bpp.o -obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o obj-$(CONFIG_BBC_I2C) += bbc.o diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 0bde26989a2..15dab96d05e 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -1,15 +1,15 @@ -/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $ - * bbc_envctrl.c: UltraSPARC-III environment control driver. +/* bbc_envctrl.c: UltraSPARC-III environment control driver. * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/kthread.h> #include <linux/delay.h> #include <linux/kmod.h> #include <linux/reboot.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/oplib.h> -#include <asm/ebus.h> #include "bbc_i2c.h" #include "max1617.h" @@ -75,43 +75,8 @@ static struct temp_limits amb_temp_limits[2] = { { 65, 55, 40, 5, -5, -10 }, }; -enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; - -struct bbc_cpu_temperature { - struct bbc_cpu_temperature *next; - - struct bbc_i2c_client *client; - int index; - - /* Current readings, and history. */ - s8 curr_cpu_temp; - s8 curr_amb_temp; - s8 prev_cpu_temp; - s8 prev_amb_temp; - s8 avg_cpu_temp; - s8 avg_amb_temp; - - int sample_tick; - - enum fan_action fan_todo[2]; -#define FAN_AMBIENT 0 -#define FAN_CPU 1 -}; - -struct bbc_cpu_temperature *all_bbc_temps; - -struct bbc_fan_control { - struct bbc_fan_control *next; - - struct bbc_i2c_client *client; - int index; - - int psupply_fan_on; - int cpu_fan_speed; - int system_fan_speed; -}; - -struct bbc_fan_control *all_bbc_fans; +static LIST_HEAD(all_temps); +static LIST_HEAD(all_fans); #define CPU_FAN_REG 0xf0 #define SYS_FAN_REG 0xf2 @@ -330,7 +295,7 @@ static enum fan_action prioritize_fan_action(int which_fan) * recommend we do, and perform that action on all the * fans. */ - for (tp = all_bbc_temps; tp; tp = tp->next) { + list_for_each_entry(tp, &all_temps, glob_list) { if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { decision = FAN_FULLBLAST; break; @@ -439,7 +404,7 @@ static void fans_full_blast(void) /* Since we will not be monitoring things anymore, put * the fans on full blast. */ - for (fp = all_bbc_fans; fp; fp = fp->next) { + list_for_each_entry(fp, &all_fans, glob_list) { fp->cpu_fan_speed = FAN_SPEED_MAX; fp->system_fan_speed = FAN_SPEED_MAX; fp->psupply_fan_on = 1; @@ -463,11 +428,11 @@ static int kenvctrld(void *__unused) if (kthread_should_stop()) break; - for (tp = all_bbc_temps; tp; tp = tp->next) { + list_for_each_entry(tp, &all_temps, glob_list) { get_current_temps(tp); analyze_temps(tp, &last_warning_jiffies); } - for (fp = all_bbc_fans; fp; fp = fp->next) + list_for_each_entry(fp, &all_fans, glob_list) maybe_new_fan_speeds(fp); } printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); @@ -477,7 +442,8 @@ static int kenvctrld(void *__unused) return 0; } -static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) +static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, + int temp_idx) { struct bbc_cpu_temperature *tp; @@ -485,20 +451,17 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) if (!tp) return; - tp->client = bbc_i2c_attach(echild); + tp->client = bbc_i2c_attach(bp, op); if (!tp->client) { kfree(tp); return; } + tp->index = temp_idx; - { - struct bbc_cpu_temperature **tpp = &all_bbc_temps; - while (*tpp) - tpp = &((*tpp)->next); - tp->next = NULL; - *tpp = tp; - } + + list_add(&tp->glob_list, &all_temps); + list_add(&tp->bp_list, &bp->temps); /* Tell it to convert once every 5 seconds, clear all cfg * bits. @@ -524,7 +487,8 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) tp->fan_todo[FAN_CPU] = FAN_SAME; } -static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) +static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, + int fan_idx) { struct bbc_fan_control *fp; @@ -532,7 +496,7 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) if (!fp) return; - fp->client = bbc_i2c_attach(echild); + fp->client = bbc_i2c_attach(bp, op); if (!fp->client) { kfree(fp); return; @@ -540,13 +504,8 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) fp->index = fan_idx; - { - struct bbc_fan_control **fpp = &all_bbc_fans; - while (*fpp) - fpp = &((*fpp)->next); - fp->next = NULL; - *fpp = fp; - } + list_add(&fp->glob_list, &all_fans); + list_add(&fp->bp_list, &bp->fans); /* The i2c device controlling the fans is write-only. * So the only way to keep track of the current power @@ -563,18 +522,18 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) set_fan_speeds(fp); } -int bbc_envctrl_init(void) +int bbc_envctrl_init(struct bbc_i2c_bus *bp) { - struct linux_ebus_child *echild; + struct of_device *op; int temp_index = 0; int fan_index = 0; int devidx = 0; - while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { - if (!strcmp(echild->prom_node->name, "temperature")) - attach_one_temp(echild, temp_index++); - if (!strcmp(echild->prom_node->name, "fan-control")) - attach_one_fan(echild, fan_index++); + while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) { + if (!strcmp(op->node->name, "temperature")) + attach_one_temp(bp, op, temp_index++); + if (!strcmp(op->node->name, "fan-control")) + attach_one_fan(bp, op, fan_index++); } if (temp_index != 0 && fan_index != 0) { kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -597,26 +556,22 @@ static void destroy_one_fan(struct bbc_fan_control *fp) kfree(fp); } -void bbc_envctrl_cleanup(void) +void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp) { - struct bbc_cpu_temperature *tp; - struct bbc_fan_control *fp; + struct bbc_cpu_temperature *tp, *tpos; + struct bbc_fan_control *fp, *fpos; kthread_stop(kenvctrld_task); - tp = all_bbc_temps; - while (tp != NULL) { - struct bbc_cpu_temperature *next = tp->next; + list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) { + list_del(&tp->bp_list); + list_del(&tp->glob_list); destroy_one_temp(tp); - tp = next; } - all_bbc_temps = NULL; - fp = all_bbc_fans; - while (fp != NULL) { - struct bbc_fan_control *next = fp->next; + list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) { + list_del(&fp->bp_list); + list_del(&fp->glob_list); destroy_one_fan(fp); - fp = next; } - all_bbc_fans = NULL; } diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index ac8ef2ce07f..f08e169ba1b 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -1,8 +1,7 @@ -/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $ - * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III +/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III * platforms. * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -14,9 +13,8 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <asm/oplib.h> -#include <asm/ebus.h> -#include <asm/spitfire.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/bbc.h> #include <asm/io.h> @@ -53,54 +51,12 @@ * The second controller also connects to the smartcard reader, if present. */ -#define NUM_CHILDREN 8 -struct bbc_i2c_bus { - struct bbc_i2c_bus *next; - int index; - spinlock_t lock; - void __iomem *i2c_bussel_reg; - void __iomem *i2c_control_regs; - unsigned char own, clock; - - wait_queue_head_t wq; - volatile int waiting; - - struct linux_ebus_device *bus_edev; - struct { - struct linux_ebus_child *device; - int client_claimed; - } devs[NUM_CHILDREN]; -}; - -static struct bbc_i2c_bus *all_bbc_i2c; - -struct bbc_i2c_client { - struct bbc_i2c_bus *bp; - struct linux_ebus_child *echild; - int bus; - int address; -}; - -static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild) +static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val) { int i; for (i = 0; i < NUM_CHILDREN; i++) { - if (bp->devs[i].device == echild) { - if (bp->devs[i].client_claimed) - return 0; - return 1; - } - } - return 0; -} - -static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val) -{ - int i; - - for (i = 0; i < NUM_CHILDREN; i++) { - if (bp->devs[i].device == echild) { + if (bp->devs[i].device == op) { bp->devs[i].client_claimed = val; return; } @@ -110,61 +66,47 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child #define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) #define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) -static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild) +struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) { - struct bbc_i2c_bus *bp = all_bbc_i2c; + struct of_device *op = NULL; + int curidx = 0, i; - while (bp != NULL) { - if (find_device(bp, echild) != 0) + for (i = 0; i < NUM_CHILDREN; i++) { + if (!(op = bp->devs[i].device)) break; - bp = bp->next; + if (curidx == index) + goto out; + op = NULL; + curidx++; } - return bp; -} - -struct linux_ebus_child *bbc_i2c_getdev(int index) -{ - struct bbc_i2c_bus *bp = all_bbc_i2c; - struct linux_ebus_child *echild = NULL; - int curidx = 0; - - while (bp != NULL) { - struct bbc_i2c_bus *next = bp->next; - int i; - - for (i = 0; i < NUM_CHILDREN; i++) { - if (!(echild = bp->devs[i].device)) - break; - if (curidx == index) - goto out; - echild = NULL; - curidx++; - } - bp = next; - } out: if (curidx == index) - return echild; + return op; return NULL; } -struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) +struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op) { - struct bbc_i2c_bus *bp = find_bus_for_device(echild); struct bbc_i2c_client *client; + const u32 *reg; - if (!bp) - return NULL; client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) return NULL; client->bp = bp; - client->echild = echild; - client->bus = echild->resource[0].start; - client->address = echild->resource[1].start; + client->op = op; + + reg = of_get_property(op->node, "reg", NULL); + if (!reg) { + kfree(client); + return NULL; + } - claim_device(bp, echild); + client->bus = reg[0]; + client->address = reg[1]; + + claim_device(bp, op); return client; } @@ -172,9 +114,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) void bbc_i2c_detach(struct bbc_i2c_client *client) { struct bbc_i2c_bus *bp = client->bp; - struct linux_ebus_child *echild = client->echild; + struct of_device *op = client->op; - release_device(bp, echild); + release_device(bp, op); kfree(client); } @@ -355,44 +297,43 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp) writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); } -static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) +static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index) { struct bbc_i2c_bus *bp; - struct linux_ebus_child *echild; + struct device_node *dp; int entry; bp = kzalloc(sizeof(*bp), GFP_KERNEL); if (!bp) - return -ENOMEM; + return NULL; - bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2); + bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); if (!bp->i2c_control_regs) goto fail; - if (edev->num_addrs == 2) { - bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1); - if (!bp->i2c_bussel_reg) - goto fail; - } + bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); + if (!bp->i2c_bussel_reg) + goto fail; bp->waiting = 0; init_waitqueue_head(&bp->wq); - if (request_irq(edev->irqs[0], bbc_i2c_interrupt, + if (request_irq(op->irqs[0], bbc_i2c_interrupt, IRQF_SHARED, "bbc_i2c", bp)) goto fail; bp->index = index; - bp->bus_edev = edev; + bp->op = op; spin_lock_init(&bp->lock); - bp->next = all_bbc_i2c; - all_bbc_i2c = bp; entry = 0; - for (echild = edev->children; - echild && entry < 8; - echild = echild->next, entry++) { - bp->devs[entry].device = echild; + for (dp = op->node->child; + dp && entry < 8; + dp = dp->sibling, entry++) { + struct of_device *child_op; + + child_op = of_find_device_by_node(dp); + bp->devs[entry].device = child_op; bp->devs[entry].client_claimed = 0; } @@ -406,86 +347,90 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) reset_one_i2c(bp); - return 0; + return bp; fail: if (bp->i2c_bussel_reg) - iounmap(bp->i2c_bussel_reg); + of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); if (bp->i2c_control_regs) - iounmap(bp->i2c_control_regs); + of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); kfree(bp); - return -EINVAL; -} - -static int __init bbc_present(void) -{ - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "bbc")) - return 1; - } - } - return 0; + return NULL; } -extern int bbc_envctrl_init(void); -extern void bbc_envctrl_cleanup(void); -static void bbc_i2c_cleanup(void); +extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); +extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); -static int __init bbc_i2c_init(void) +static int __devinit bbc_i2c_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; + struct bbc_i2c_bus *bp; int err, index = 0; - if ((tlb_type != cheetah && tlb_type != cheetah_plus) || - !bbc_present()) - return -ENODEV; + bp = attach_one_i2c(op, index); + if (!bp) + return -EINVAL; - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "i2c")) { - if (!attach_one_i2c(edev, index)) - index++; - } - } + err = bbc_envctrl_init(bp); + if (err) { + free_irq(op->irqs[0], bp); + if (bp->i2c_bussel_reg) + of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); + if (bp->i2c_control_regs) + of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); + kfree(bp); + } else { + dev_set_drvdata(&op->dev, bp); } - if (!index) - return -ENODEV; - - err = bbc_envctrl_init(); - if (err) - bbc_i2c_cleanup(); return err; } -static void bbc_i2c_cleanup(void) +static int __devexit bbc_i2c_remove(struct of_device *op) { - struct bbc_i2c_bus *bp = all_bbc_i2c; + struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); + + bbc_envctrl_cleanup(bp); + + free_irq(op->irqs[0], bp); - bbc_envctrl_cleanup(); + if (bp->i2c_bussel_reg) + of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); + if (bp->i2c_control_regs) + of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); - while (bp != NULL) { - struct bbc_i2c_bus *next = bp->next; + kfree(bp); - free_irq(bp->bus_edev->irqs[0], bp); + return 0; +} - if (bp->i2c_bussel_reg) - iounmap(bp->i2c_bussel_reg); - if (bp->i2c_control_regs) - iounmap(bp->i2c_control_regs); +static const struct of_device_id bbc_i2c_match[] = { + { + .name = "i2c", + .compatible = "SUNW,bbc-i2c", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, bbc_i2c_match); - kfree(bp); +static struct of_platform_driver bbc_i2c_driver = { + .name = "bbc_i2c", + .match_table = bbc_i2c_match, + .probe = bbc_i2c_probe, + .remove = __devexit_p(bbc_i2c_remove), +}; - bp = next; - } - all_bbc_i2c = NULL; +static int __init bbc_i2c_init(void) +{ + return of_register_driver(&bbc_i2c_driver, &of_bus_type); +} + +static void __exit bbc_i2c_exit(void) +{ + of_unregister_driver(&bbc_i2c_driver); } module_init(bbc_i2c_init); -module_exit(bbc_i2c_cleanup); +module_exit(bbc_i2c_exit); + MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h index fb01bd17704..83c4811b7b5 100644 --- a/drivers/sbus/char/bbc_i2c.h +++ b/drivers/sbus/char/bbc_i2c.h @@ -1,14 +1,79 @@ -/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */ #ifndef _BBC_I2C_H #define _BBC_I2C_H -#include <asm/ebus.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/list.h> -struct bbc_i2c_client; +struct bbc_i2c_client { + struct bbc_i2c_bus *bp; + struct of_device *op; + int bus; + int address; +}; + +enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; + +struct bbc_cpu_temperature { + struct list_head bp_list; + struct list_head glob_list; + + struct bbc_i2c_client *client; + int index; + + /* Current readings, and history. */ + s8 curr_cpu_temp; + s8 curr_amb_temp; + s8 prev_cpu_temp; + s8 prev_amb_temp; + s8 avg_cpu_temp; + s8 avg_amb_temp; + + int sample_tick; + + enum fan_action fan_todo[2]; +#define FAN_AMBIENT 0 +#define FAN_CPU 1 +}; + +struct bbc_fan_control { + struct list_head bp_list; + struct list_head glob_list; + + struct bbc_i2c_client *client; + int index; + + int psupply_fan_on; + int cpu_fan_speed; + int system_fan_speed; +}; + +#define NUM_CHILDREN 8 + +struct bbc_i2c_bus { + struct bbc_i2c_bus *next; + int index; + spinlock_t lock; + void __iomem *i2c_bussel_reg; + void __iomem *i2c_control_regs; + unsigned char own, clock; + + wait_queue_head_t wq; + volatile int waiting; + + struct list_head temps; + struct list_head fans; + + struct of_device *op; + struct { + struct of_device *device; + int client_claimed; + } devs[NUM_CHILDREN]; +}; /* Probing and attachment. */ -extern struct linux_ebus_child *bbc_i2c_getdev(int); -extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *); +extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int); +extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *); extern void bbc_i2c_detach(struct bbc_i2c_client *); /* Register read/write. NOTE: Blocking! */ diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c deleted file mode 100644 index bba21e053a1..00000000000 --- a/drivers/sbus/char/bpp.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * drivers/sbus/char/bpp.c - * - * Copyright (c) 1995 Picture Elements - * Stephen Williams (steve@icarus.com) - * Gus Baldauf (gbaldauf@ix.netcom.com) - * - * Linux/SPARC port by Peter Zaitcev. - * Integration into SPARC tree by Tom Dyas. - */ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/major.h> -#include <linux/smp_lock.h> - -#include <asm/uaccess.h> -#include <asm/io.h> - -#if defined(__i386__) -# include <asm/system.h> -#endif - -#if defined(__sparc__) -# include <linux/init.h> -# include <linux/delay.h> /* udelay() */ - -# include <asm/oplib.h> /* OpenProm Library */ -# include <asm/sbus.h> -#endif - -#include <asm/bpp.h> - -#define BPP_PROBE_CODE 0x55 -#define BPP_DELAY 100 - -static const unsigned BPP_MAJOR = LP_MAJOR; -static const char *bpp_dev_name = "bpp"; - -/* When switching from compatibility to a mode where I can read, try - the following mode first. */ - -/* const unsigned char DEFAULT_ECP = 0x10; */ -static const unsigned char DEFAULT_ECP = 0x30; -static const unsigned char DEFAULT_NIBBLE = 0x00; - -/* - * These are 1284 time constraints, in units of jiffies. - */ - -static const unsigned long TIME_PSetup = 1; -static const unsigned long TIME_PResponse = 6; -static const unsigned long TIME_IDLE_LIMIT = 2000; - -/* - * One instance per supported subdevice... - */ -# define BPP_NO 3 - -enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP }; - -struct inst { - unsigned present : 1; /* True if the hardware exists */ - unsigned enhanced : 1; /* True if the hardware in "enhanced" */ - unsigned opened : 1; /* True if the device is opened already */ - unsigned run_flag : 1; /* True if waiting for a repeate byte */ - - unsigned char direction; /* 0 --> out, 0x20 --> IN */ - unsigned char pp_state; /* State of host controlled pins. */ - enum IEEE_Mode mode; - - unsigned char run_length; - unsigned char repeat_byte; -}; - -static struct inst instances[BPP_NO]; - -#if defined(__i386__) - -static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc }; - -/* - * These are for data access. - * Control lines accesses are hidden in set_bits() and get_bits(). - * The exception is the probe procedure, which is system-dependent. - */ -#define bpp_outb_p(data, base) outb_p((data), (base)) -#define bpp_inb(base) inb(base) -#define bpp_inb_p(base) inb_p(base) - -/* - * This method takes the pin values mask and sets the hardware pins to - * the requested value: 1 == high voltage, 0 == low voltage. This - * burries the annoying PC bit inversion and preserves the direction - * flag. - */ -static void set_pins(unsigned short pins, unsigned minor) -{ - unsigned char bits = instances[minor].direction; /* == 0x20 */ - - if (! (pins & BPP_PP_nStrobe)) bits |= 1; - if (! (pins & BPP_PP_nAutoFd)) bits |= 2; - if ( pins & BPP_PP_nInit) bits |= 4; - if (! (pins & BPP_PP_nSelectIn)) bits |= 8; - - instances[minor].pp_state = bits; - - outb_p(bits, base_addrs[minor]+2); -} - -static unsigned short get_pins(unsigned minor) -{ - unsigned short bits = 0; - - unsigned value = instances[minor].pp_state; - if (! (value & 0x01)) bits |= BPP_PP_nStrobe; - if (! (value & 0x02)) bits |= BPP_PP_nAutoFd; - if (value & 0x04) bits |= BPP_PP_nInit; - if (! (value & 0x08)) bits |= BPP_PP_nSelectIn; - - value = inb_p(base_addrs[minor]+1); - if (value & 0x08) bits |= BPP_GP_nFault; - if (value & 0x10) bits |= BPP_GP_Select; - if (value & 0x20) bits |= BPP_GP_PError; - if (value & 0x40) bits |= BPP_GP_nAck; - if (! (value & 0x80)) bits |= BPP_GP_Busy; - - return bits; -} - -#endif /* __i386__ */ - -#if defined(__sparc__) - -/* - * Register block - */ - /* DMA registers */ -#define BPP_CSR 0x00 -#define BPP_ADDR 0x04 -#define BPP_BCNT 0x08 -#define BPP_TST_CSR 0x0C - /* Parallel Port registers */ -#define BPP_HCR 0x10 -#define BPP_OCR 0x12 -#define BPP_DR 0x14 -#define BPP_TCR 0x15 -#define BPP_OR 0x16 -#define BPP_IR 0x17 -#define BPP_ICR 0x18 -#define BPP_SIZE 0x1A - -/* BPP_CSR. Bits of type RW1 are cleared with writing '1'. */ -#define P_DEV_ID_MASK 0xf0000000 /* R */ -#define P_DEV_ID_ZEBRA 0x40000000 -#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */ -#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */ -#define P_A_LOADED 0x04000000 /* R */ -#define P_DMA_ON 0x02000000 /* R DMA is not disabled */ -#define P_EN_NEXT 0x01000000 /* RW */ -#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */ -#define P_DIAG 0x00100000 /* RW Disables draining and resetting - of P-FIFO on loading of P_ADDR*/ -#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */ -#define P_BURST_8 0x00000000 -#define P_BURST_4 0x00040000 -#define P_BURST_1 0x00080000 /* "No burst" write */ -#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when - P_EN_NEXT=1 */ -#define P_EN_CNT 0x00002000 /* RW */ -#define P_EN_DMA 0x00000200 /* RW */ -#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */ -#define P_RESET 0x00000080 /* RW */ -#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */ -#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */ -#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */ -#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */ -#define P_ERR_PEND 0x00000002 /* R */ -#define P_INT_PEND 0x00000001 /* R */ - -/* BPP_HCR. Time is in increments of SBus clock. */ -#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */ -#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */ -#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */ - -/* BPP_OCR. */ -#define P_OCR_MEM_CLR 0x8000 -#define P_OCR_DATA_SRC 0x4000 /* ) */ -#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */ -#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */ -#define P_OCR_ACK_DSEL 0x0800 /* ) */ -#define P_OCR_EN_DIAG 0x0400 -#define P_OCR_BUSY_OP 0x0200 /* Busy operation */ -#define P_OCR_ACK_OP 0x0100 /* Ack operation */ -#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */ -#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */ -#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */ -#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */ - -/* BPP_TCR */ -#define P_TCR_DIR 0x08 -#define P_TCR_BUSY 0x04 -#define P_TCR_ACK 0x02 -#define P_TCR_DS 0x01 /* Strobe */ - -/* BPP_OR */ -#define P_OR_V3 0x20 /* ) */ -#define P_OR_V2 0x10 /* ) on Zebra only */ -#define P_OR_V1 0x08 /* ) */ -#define P_OR_INIT 0x04 -#define P_OR_AFXN 0x02 /* Auto Feed */ -#define P_OR_SLCT_IN 0x01 - -/* BPP_IR */ -#define P_IR_PE 0x04 -#define P_IR_SLCT 0x02 -#define P_IR_ERR 0x01 - -/* BPP_ICR */ -#define P_DS_IRQ 0x8000 /* RW1 */ -#define P_ACK_IRQ 0x4000 /* RW1 */ -#define P_BUSY_IRQ 0x2000 /* RW1 */ -#define P_PE_IRQ 0x1000 /* RW1 */ -#define P_SLCT_IRQ 0x0800 /* RW1 */ -#define P_ERR_IRQ 0x0400 /* RW1 */ -#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */ -#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */ -#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */ -#define P_BUSY_IRQ_EN 0x0040 /* RW */ -#define P_PE_IRP 0x0020 /* RW 1= rising edge */ -#define P_PE_IRQ_EN 0x0010 /* RW */ -#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */ -#define P_SLCT_IRQ_EN 0x0004 /* RW */ -#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */ -#define P_ERR_IRQ_EN 0x0001 /* RW */ - -static void __iomem *base_addrs[BPP_NO]; - -#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR) -#define bpp_inb_p(base) sbus_readb((base) + BPP_DR) -#define bpp_inb(base) sbus_readb((base) + BPP_DR) - -static void set_pins(unsigned short pins, unsigned minor) -{ - void __iomem *base = base_addrs[minor]; - unsigned char bits_tcr = 0, bits_or = 0; - - if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR; - if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS; - - if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN; - if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT; - if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN; - - sbus_writeb(bits_or, base + BPP_OR); - sbus_writeb(bits_tcr, base + BPP_TCR); -} - -/* - * i386 people read output pins from a software image. - * We may get them back from hardware. - * Again, inversion of pins must he buried here. - */ -static unsigned short get_pins(unsigned minor) -{ - void __iomem *base = base_addrs[minor]; - unsigned short bits = 0; - unsigned value_tcr = sbus_readb(base + BPP_TCR); - unsigned value_ir = sbus_readb(base + BPP_IR); - unsigned value_or = sbus_readb(base + BPP_OR); - - if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe; - if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd; - if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit; - if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn; - - if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault; - if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select; - if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError; - if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck; - if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy; - - return bits; -} - -#endif /* __sparc__ */ - -static void snooze(unsigned long snooze_time, unsigned minor) -{ - schedule_timeout_uninterruptible(snooze_time + 1); -} - -static int wait_for(unsigned short set, unsigned short clr, - unsigned long delay, unsigned minor) -{ - unsigned short pins = get_pins(minor); - - unsigned long extime = 0; - - /* - * Try a real fast scan for the first jiffy, in case the device - * responds real good. The first while loop guesses an expire - * time accounting for possible wraparound of jiffies. - */ - while (time_after_eq(jiffies, extime)) extime = jiffies + 1; - while ( (time_before(jiffies, extime)) - && (((pins & set) != set) || ((pins & clr) != 0)) ) { - pins = get_pins(minor); - } - - delay -= 1; - - /* - * If my delay expired or the pins are still not where I want - * them, then resort to using the timer and greatly reduce my - * sample rate. If the peripheral is going to be slow, this will - * give the CPU up to some more worthy process. - */ - while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) { - - snooze(1, minor); - pins = get_pins(minor); - delay -= 1; - } - - if (delay == 0) return -1; - else return pins; -} - -/* - * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An - * errno means something broke, and I do not yet know how to fix it. - */ -static int negotiate(unsigned char mode, unsigned minor) -{ - int rc; - unsigned short pins = get_pins(minor); - if (pins & BPP_PP_nSelectIn) return -EIO; - - - /* Event 0: Write the mode to the data lines */ - bpp_outb_p(mode, base_addrs[minor]); - - snooze(TIME_PSetup, minor); - - /* Event 1: Strobe the mode code into the peripheral */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Wait for Event 2: Peripheral responds as a 1284 device. */ - rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault, - BPP_GP_nAck, - TIME_PResponse, - minor); - - if (rc == -1) return -ETIMEDOUT; - - /* Event 3: latch extensibility request */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor); - - /* ... quick nap while peripheral ponders the byte i'm sending...*/ - snooze(1, minor); - - /* Event 4: restore strobe, to ACK peripheral's response. */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Wait for Event 6: Peripheral latches response bits */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor); - if (rc == -1) return -EIO; - - /* A 1284 device cannot refuse nibble mode */ - if (mode == DEFAULT_NIBBLE) return 0; - - if (pins & BPP_GP_Select) return 0; - - return -EPROTONOSUPPORT; -} - -static int terminate(unsigned minor) -{ - int rc; - - /* Event 22: Request termination of 1284 mode */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Wait for Events 23 and 24: ACK termination request. */ - rc = wait_for(BPP_GP_Busy|BPP_GP_nFault, - BPP_GP_nAck, - TIME_PSetup+TIME_PResponse, - minor); - - instances[minor].direction = 0; - instances[minor].mode = COMPATIBILITY; - - if (rc == -1) { - return -EIO; - } - - /* Event 25: Handshake by lowering nAutoFd */ - set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Event 26: Peripheral wiggles lines... */ - - /* Event 27: Peripheral sets nAck HIGH to ack handshake */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - if (rc == -1) { - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - return -EIO; - } - - /* Event 28: Finish phase by raising nAutoFd */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - return 0; -} - -static DEFINE_SPINLOCK(bpp_open_lock); - -/* - * Allow only one process to open the device at a time. - */ -static int bpp_open(struct inode *inode, struct file *f) -{ - unsigned minor = iminor(inode); - int ret; - - lock_kernel(); - spin_lock(&bpp_open_lock); - ret = 0; - if (minor >= BPP_NO) { - ret = -ENODEV; - } else { - if (! instances[minor].present) { - ret = -ENODEV; - } else { - if (instances[minor].opened) - ret = -EBUSY; - else - instances[minor].opened = 1; - } - } - spin_unlock(&bpp_open_lock); - unlock_kernel(); - - return ret; -} - -/* - * When the process closes the device, this method is called to clean - * up and reset the hardware. Always leave the device in compatibility - * mode as this is a reasonable place to clean up from messes made by - * ioctls, or other mayhem. - */ -static int bpp_release(struct inode *inode, struct file *f) -{ - unsigned minor = iminor(inode); - - spin_lock(&bpp_open_lock); - instances[minor].opened = 0; - - if (instances[minor].mode != COMPATIBILITY) - terminate(minor); - - spin_unlock(&bpp_open_lock); - - return 0; -} - -static long read_nibble(unsigned minor, char __user *c, unsigned long cnt) -{ - unsigned long remaining = cnt; - long rc; - - while (remaining > 0) { - unsigned char byte = 0; - int pins; - - /* Event 7: request nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); - - /* Wait for event 9: Peripher strobes first nibble */ - pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); - if (pins == -1) return -ETIMEDOUT; - - /* Event 10: I handshake nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); - if (pins & BPP_GP_nFault) byte |= 0x01; - if (pins & BPP_GP_Select) byte |= 0x02; - if (pins & BPP_GP_PError) byte |= 0x04; - if (pins & BPP_GP_Busy) byte |= 0x08; - - /* Wait for event 11: Peripheral handshakes nibble */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - - /* Event 7: request nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); - - /* Wait for event 9: Peripher strobes first nibble */ - pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - /* Event 10: I handshake nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); - if (pins & BPP_GP_nFault) byte |= 0x10; - if (pins & BPP_GP_Select) byte |= 0x20; - if (pins & BPP_GP_PError) byte |= 0x40; - if (pins & BPP_GP_Busy) byte |= 0x80; - - if (put_user(byte, c)) - return -EFAULT; - c += 1; - remaining -= 1; - - /* Wait for event 11: Peripheral handshakes nibble */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - if (rc == -1) return -EIO; - } - - return cnt - remaining; -} - -static long read_ecp(unsigned minor, char __user *c, unsigned long cnt) -{ - unsigned long remaining; - long rc; - - /* Turn ECP mode from forward to reverse if needed. */ - if (! instances[minor].direction) { - unsigned short pins = get_pins(minor); - - /* Event 38: Turn the bus around */ - instances[minor].direction = 0x20; - pins &= ~BPP_PP_nAutoFd; - set_pins(pins, minor); - - /* Event 39: Set pins for reverse mode. */ - snooze(TIME_PSetup, minor); - set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); - - /* Wait for event 40: Peripheral ready to be strobed */ - rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - } - - remaining = cnt; - - while (remaining > 0) { - - /* If there is a run length for a repeated byte, repeat */ - /* that byte a few times. */ - if (instances[minor].run_length && !instances[minor].run_flag) { - - char buffer[128]; - unsigned idx; - unsigned repeat = remaining < instances[minor].run_length - ? remaining - : instances[minor].run_length; - - for (idx = 0 ; idx < repeat ; idx += 1) - buffer[idx] = instances[minor].repeat_byte; - - if (copy_to_user(c, buffer, repeat)) - return -EFAULT; - remaining -= repeat; - c += repeat; - instances[minor].run_length -= repeat; - } - - if (remaining == 0) break; - - - /* Wait for Event 43: Data active on the bus. */ - rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); - if (rc == -1) break; - - if (rc & BPP_GP_Busy) { - /* OK, this is data. read it in. */ - unsigned char byte = bpp_inb(base_addrs[minor]); - if (put_user(byte, c)) - return -EFAULT; - c += 1; - remaining -= 1; - - if (instances[minor].run_flag) { - instances[minor].repeat_byte = byte; - instances[minor].run_flag = 0; - } - - } else { - unsigned char byte = bpp_inb(base_addrs[minor]); - if (byte & 0x80) { - printk("bpp%d: " - "Ignoring ECP channel %u from device.\n", - minor, byte & 0x7f); - } else { - instances[minor].run_length = byte; - instances[minor].run_flag = 1; - } - } - - /* Event 44: I got it. */ - set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor); - - /* Wait for event 45: peripheral handshake */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - /* Event 46: Finish handshake */ - set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); - - } - - - return cnt - remaining; -} - -static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos) -{ - long rc; - unsigned minor = iminor(f->f_path.dentry->d_inode); - if (minor >= BPP_NO) return -ENODEV; - if (!instances[minor].present) return -ENODEV; - - switch (instances[minor].mode) { - - default: - if (instances[minor].mode != COMPATIBILITY) - terminate(minor); - - if (instances[minor].enhanced) { - /* For now, do all reads with ECP-RLE mode */ - unsigned short pins; - - rc = negotiate(DEFAULT_ECP, minor); - if (rc < 0) break; - - instances[minor].mode = ECP_RLE; - - /* Event 30: set nAutoFd low to setup for ECP mode */ - pins = get_pins(minor); - pins &= ~BPP_PP_nAutoFd; - set_pins(pins, minor); - - /* Wait for Event 31: peripheral ready */ - rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - rc = read_ecp(minor, c, cnt); - - } else { - rc = negotiate(DEFAULT_NIBBLE, minor); - if (rc < 0) break; - - instances[minor].mode = NIBBLE; - - rc = read_nibble(minor, c, cnt); - } - break; - - case NIBBLE: - rc = read_nibble(minor, c, cnt); - break; - - case ECP: - case ECP_RLE: - rc = read_ecp(minor, c, cnt); - break; - - } - - - return rc; -} - -/* - * Compatibility mode handshaking is a matter of writing data, - * strobing it, and waiting for the printer to stop being busy. - */ -static long write_compat(unsigned minor, const char __user *c, unsigned long cnt) -{ - long rc; - unsigned short pins = get_pins(minor); - - unsigned long remaining = cnt; - - - while (remaining > 0) { - unsigned char byte; - - if (get_user(byte, c)) - return -EFAULT; - c += 1; - - rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); - if (rc == -1) return -ETIMEDOUT; - - bpp_outb_p(byte, base_addrs[minor]); - remaining -= 1; - /* snooze(1, minor); */ - - pins &= ~BPP_PP_nStrobe; - set_pins(pins, minor); - - rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); - - pins |= BPP_PP_nStrobe; - set_pins(pins, minor); - } - - return cnt - remaining; -} - -/* - * Write data using ECP mode. Watch out that the port may be set up - * for reading. If so, turn the port around. - */ -static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt) -{ - unsigned short pins = get_pins(minor); - unsigned long remaining = cnt; - - if (instances[minor].direction) { - int rc; - - /* Event 47 Request bus be turned around */ - pins |= BPP_PP_nInit; - set_pins(pins, minor); - - /* Wait for Event 49: Peripheral relinquished bus */ - rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); - - pins |= BPP_PP_nAutoFd; - instances[minor].direction = 0; - set_pins(pins, minor); - } - - while (remaining > 0) { - unsigned char byte; - int rc; - - if (get_user(byte, c)) - return -EFAULT; - - rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - c += 1; - - bpp_outb_p(byte, base_addrs[minor]); - - pins &= ~BPP_PP_nStrobe; - set_pins(pins, minor); - - pins |= BPP_PP_nStrobe; - rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); - if (rc == -1) return -EIO; - - set_pins(pins, minor); - } - - return cnt - remaining; -} - -/* - * Write to the peripheral. Be sensitive of the current mode. If I'm - * in a mode that can be turned around (ECP) then just do - * that. Otherwise, terminate and do my writing in compat mode. This - * is the safest course as any device can handle it. - */ -static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos) -{ - long errno = 0; - unsigned minor = iminor(f->f_path.dentry->d_inode); - if (minor >= BPP_NO) return -ENODEV; - if (!instances[minor].present) return -ENODEV; - - switch (instances[minor].mode) { - - case ECP: - case ECP_RLE: - errno = write_ecp(minor, c, cnt); - break; - case COMPATIBILITY: - errno = write_compat(minor, c, cnt); - break; - default: - terminate(minor); - errno = write_compat(minor, c, cnt); - } - - return errno; -} - -static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, - unsigned long arg) -{ - int errno = 0; - - unsigned minor = iminor(inode); - if (minor >= BPP_NO) return -ENODEV; - if (!instances[minor].present) return -ENODEV; - - - switch (cmd) { - - case BPP_PUT_PINS: - set_pins(arg, minor); - break; - - case BPP_GET_PINS: - errno = get_pins(minor); - break; - - case BPP_PUT_DATA: - bpp_outb_p(arg, base_addrs[minor]); - break; - - case BPP_GET_DATA: - errno = bpp_inb_p(base_addrs[minor]); - break; - - case BPP_SET_INPUT: - if (arg) - if (instances[minor].enhanced) { - unsigned short bits = get_pins(minor); - instances[minor].direction = 0x20; - set_pins(bits, minor); - } else { - errno = -ENOTTY; - } - else { - unsigned short bits = get_pins(minor); - instances[minor].direction = 0x00; - set_pins(bits, minor); - } - break; - - default: - errno = -EINVAL; - } - - return errno; -} - -static const struct file_operations bpp_fops = { - .owner = THIS_MODULE, - .read = bpp_read, - .write = bpp_write, - .ioctl = bpp_ioctl, - .open = bpp_open, - .release = bpp_release, -}; - -#if defined(__i386__) - -#define collectLptPorts() {} - -static void probeLptPort(unsigned idx) -{ - unsigned int testvalue; - const unsigned short lpAddr = base_addrs[idx]; - - instances[idx].present = 0; - instances[idx].enhanced = 0; - instances[idx].direction = 0; - instances[idx].mode = COMPATIBILITY; - instances[idx].run_length = 0; - instances[idx].run_flag = 0; - if (!request_region(lpAddr,3, bpp_dev_name)) return; - - /* - * First, make sure the instance exists. Do this by writing to - * the data latch and reading the value back. If the port *is* - * present, test to see if it supports extended-mode - * operation. This will be required for IEEE1284 reverse - * transfers. - */ - - outb_p(BPP_PROBE_CODE, lpAddr); - for (testvalue=0; testvalue<BPP_DELAY; testvalue++) - ; - testvalue = inb_p(lpAddr); - if (testvalue == BPP_PROBE_CODE) { - unsigned save; - instances[idx].present = 1; - - save = inb_p(lpAddr+2); - for (testvalue=0; testvalue<BPP_DELAY; testvalue++) - ; - outb_p(save|0x20, lpAddr+2); - for (testvalue=0; testvalue<BPP_DELAY; testvalue++) - ; - outb_p(~BPP_PROBE_CODE, lpAddr); - for (testvalue=0; testvalue<BPP_DELAY; testvalue++) - ; - testvalue = inb_p(lpAddr); - if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE)) - instances[idx].enhanced = 0; - else - instances[idx].enhanced = 1; - outb_p(save, lpAddr+2); - } - else { - release_region(lpAddr,3); - } - /* - * Leave the port in compat idle mode. - */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); - - printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx], - instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE"); -} - -static inline void freeLptPort(int idx) -{ - release_region(base_addrs[idx], 3); -} - -#endif - -#if defined(__sparc__) - -static void __iomem *map_bpp(struct sbus_dev *dev, int idx) -{ - return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp"); -} - -static int collectLptPorts(void) -{ - struct sbus_bus *bus; - struct sbus_dev *dev; - int count; - - count = 0; - for_all_sbusdev(dev, bus) { - if (strcmp(dev->prom_name, "SUNW,bpp") == 0) { - if (count >= BPP_NO) { - printk(KERN_NOTICE - "bpp: More than %d bpp ports," - " rest is ignored\n", BPP_NO); - return count; - } - base_addrs[count] = map_bpp(dev, count); - count++; - } - } - return count; -} - -static void probeLptPort(unsigned idx) -{ - void __iomem *rp = base_addrs[idx]; - __u32 csr; - char *brand; - - instances[idx].present = 0; - instances[idx].enhanced = 0; - instances[idx].direction = 0; - instances[idx].mode = COMPATIBILITY; - instances[idx].run_length = 0; - instances[idx].run_flag = 0; - - if (!rp) return; - - instances[idx].present = 1; - instances[idx].enhanced = 1; /* Sure */ - - csr = sbus_readl(rp + BPP_CSR); - if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { - udelay(20); - csr = sbus_readl(rp + BPP_CSR); - if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { - printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr); - } - } - printk("bpp%d: reset with 0x%08x ..", idx, csr); - sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR); - udelay(500); - sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR); - csr = sbus_readl(rp + BPP_CSR); - printk(" done with csr=0x%08x ocr=0x%04x\n", - csr, sbus_readw(rp + BPP_OCR)); - - switch (csr & P_DEV_ID_MASK) { - case P_DEV_ID_ZEBRA: - brand = "Zebra"; - break; - case P_DEV_ID_L64854: - brand = "DMA2"; - break; - default: - brand = "Unknown"; - } - printk("bpp%d: %s at %p\n", idx, brand, rp); - - /* - * Leave the port in compat idle mode. - */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); - - return; -} - -static inline void freeLptPort(int idx) -{ - sbus_iounmap(base_addrs[idx], BPP_SIZE); -} - -#endif - -static int __init bpp_init(void) -{ - int rc; - unsigned idx; - - rc = collectLptPorts(); - if (rc == 0) - return -ENODEV; - - rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops); - if (rc < 0) - return rc; - - for (idx = 0; idx < BPP_NO; idx++) { - instances[idx].opened = 0; - probeLptPort(idx); - } - - return 0; -} - -static void __exit bpp_cleanup(void) -{ - unsigned idx; - - unregister_chrdev(BPP_MAJOR, bpp_dev_name); - - for (idx = 0; idx < BPP_NO; idx++) { - if (instances[idx].present) - freeLptPort(idx); - } -} - -module_init(bpp_init); -module_exit(bpp_cleanup); - -MODULE_LICENSE("GPL"); - diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c deleted file mode 100644 index 23abfdfb44f..00000000000 --- a/drivers/sbus/char/cpwatchdog.c +++ /dev/null @@ -1,858 +0,0 @@ -/* cpwatchdog.c - driver implementation for hardware watchdog - * timers found on Sun Microsystems CP1400 and CP1500 boards. - * - * This device supports both the generic Linux watchdog - * interface and Solaris-compatible ioctls as best it is - * able. - * - * NOTE: CP1400 systems appear to have a defective intr_mask - * register on the PLD, preventing the disabling of - * timer interrupts. We use a timer to periodically - * reset 'stopped' watchdogs on affected platforms. - * - * Copyright (c) 2000 Eric Brower (ebrower@usa.net) - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/errno.h> -#include <linux/major.h> -#include <linux/init.h> -#include <linux/miscdevice.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timer.h> -#include <linux/smp_lock.h> -#include <linux/io.h> -#include <asm/irq.h> -#include <asm/ebus.h> -#include <asm/oplib.h> -#include <asm/uaccess.h> - -#include <asm/watchdog.h> - -#define WD_OBPNAME "watchdog" -#define WD_BADMODEL "SUNW,501-5336" -#define WD_BTIMEOUT (jiffies + (HZ * 1000)) -#define WD_BLIMIT 0xFFFF - -#define WD0_DEVNAME "watchdog0" -#define WD1_DEVNAME "watchdog1" -#define WD2_DEVNAME "watchdog2" - -#define WD0_MINOR 212 -#define WD1_MINOR 213 -#define WD2_MINOR 214 - - -/* Internal driver definitions - */ -#define WD0_ID 0 /* Watchdog0 */ -#define WD1_ID 1 /* Watchdog1 */ -#define WD2_ID 2 /* Watchdog2 */ -#define WD_NUMDEVS 3 /* Device contains 3 timers */ - -#define WD_INTR_OFF 0 /* Interrupt disable value */ -#define WD_INTR_ON 1 /* Interrupt enable value */ - -#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ -#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ -#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ - -/* Register value definitions - */ -#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ -#define WD1_INTR_MASK 0x02 -#define WD2_INTR_MASK 0x04 - -#define WD_S_RUNNING 0x01 /* Watchdog device status running */ -#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ - -/* Sun uses Altera PLD EPF8820ATC144-4 - * providing three hardware watchdogs: - * - * 1) RIC - sends an interrupt when triggered - * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU - * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board - * - *** Timer register block definition (struct wd_timer_regblk) - * - * dcntr and limit registers (halfword access): - * ------------------- - * | 15 | ...| 1 | 0 | - * ------------------- - * |- counter val -| - * ------------------- - * dcntr - Current 16-bit downcounter value. - * When downcounter reaches '0' watchdog expires. - * Reading this register resets downcounter with 'limit' value. - * limit - 16-bit countdown value in 1/10th second increments. - * Writing this register begins countdown with input value. - * Reading from this register does not affect counter. - * NOTES: After watchdog reset, dcntr and limit contain '1' - * - * status register (byte access): - * --------------------------- - * | 7 | ... | 2 | 1 | 0 | - * --------------+------------ - * |- UNUSED -| EXP | RUN | - * --------------------------- - * status- Bit 0 - Watchdog is running - * Bit 1 - Watchdog has expired - * - *** PLD register block definition (struct wd_pld_regblk) - * - * intr_mask register (byte access): - * --------------------------------- - * | 7 | ... | 3 | 2 | 1 | 0 | - * +-------------+------------------ - * |- UNUSED -| WD3 | WD2 | WD1 | - * --------------------------------- - * WD3 - 1 == Interrupt disabled for watchdog 3 - * WD2 - 1 == Interrupt disabled for watchdog 2 - * WD1 - 1 == Interrupt disabled for watchdog 1 - * - * pld_status register (byte access): - * UNKNOWN, MAGICAL MYSTERY REGISTER - * - */ -#define WD_TIMER_REGSZ 16 -#define WD0_OFF 0 -#define WD1_OFF (WD_TIMER_REGSZ * 1) -#define WD2_OFF (WD_TIMER_REGSZ * 2) -#define PLD_OFF (WD_TIMER_REGSZ * 3) - -#define WD_DCNTR 0x00 -#define WD_LIMIT 0x04 -#define WD_STATUS 0x08 - -#define PLD_IMASK (PLD_OFF + 0x00) -#define PLD_STATUS (PLD_OFF + 0x04) - -/* Individual timer structure - */ -struct wd_timer { - __u16 timeout; - __u8 intr_mask; - unsigned char runstatus; - void __iomem *regs; -}; - -/* Device structure - */ -struct wd_device { - int irq; - spinlock_t lock; - unsigned char isbaddoggie; /* defective PLD */ - unsigned char opt_enable; - unsigned char opt_reboot; - unsigned short opt_timeout; - unsigned char initialized; - struct wd_timer watchdog[WD_NUMDEVS]; - void __iomem *regs; -}; - -static struct wd_device wd_dev = { - 0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0, -}; - -static struct timer_list wd_timer; - -static int wd0_timeout = 0; -static int wd1_timeout = 0; -static int wd2_timeout = 0; - -#ifdef MODULE -module_param (wd0_timeout, int, 0); -MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); -module_param (wd1_timeout, int, 0); -MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); -module_param (wd2_timeout, int, 0); -MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); - -MODULE_AUTHOR - ("Eric Brower <ebrower@usa.net>"); -MODULE_DESCRIPTION - ("Hardware watchdog driver for Sun Microsystems CP1400/1500"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE - ("watchdog"); -#endif /* ifdef MODULE */ - -/* Forward declarations of internal methods - */ -#ifdef WD_DEBUG -static void wd_dumpregs(void); -#endif -static irqreturn_t wd_interrupt(int irq, void *dev_id); -static void wd_toggleintr(struct wd_timer* pTimer, int enable); -static void wd_pingtimer(struct wd_timer* pTimer); -static void wd_starttimer(struct wd_timer* pTimer); -static void wd_resetbrokentimer(struct wd_timer* pTimer); -static void wd_stoptimer(struct wd_timer* pTimer); -static void wd_brokentimer(unsigned long data); -static int wd_getstatus(struct wd_timer* pTimer); - -/* PLD expects words to be written in LSB format, - * so we must flip all words prior to writing them to regs - */ -static inline unsigned short flip_word(unsigned short word) -{ - return ((word & 0xff) << 8) | ((word >> 8) & 0xff); -} - -#define wd_writew(val, addr) (writew(flip_word(val), addr)) -#define wd_readw(addr) (flip_word(readw(addr))) -#define wd_writeb(val, addr) (writeb(val, addr)) -#define wd_readb(addr) (readb(addr)) - - -/* CP1400s seem to have broken PLD implementations-- - * the interrupt_mask register cannot be written, so - * no timer interrupts can be masked within the PLD. - */ -static inline int wd_isbroken(void) -{ - /* we could test this by read/write/read/restore - * on the interrupt mask register only if OBP - * 'watchdog-enable?' == FALSE, but it seems - * ubiquitous on CP1400s - */ - char val[32]; - prom_getproperty(prom_root_node, "model", val, sizeof(val)); - return((!strcmp(val, WD_BADMODEL)) ? 1 : 0); -} - -/* Retrieve watchdog-enable? option from OBP - * Returns 0 if false, 1 if true - */ -static inline int wd_opt_enable(void) -{ - int opt_node; - - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1); -} - -/* Retrieve watchdog-reboot? option from OBP - * Returns 0 if false, 1 if true - */ -static inline int wd_opt_reboot(void) -{ - int opt_node; - - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1); -} - -/* Retrieve watchdog-timeout option from OBP - * Returns OBP value, or 0 if not located - */ -static inline int wd_opt_timeout(void) -{ - int opt_node; - char value[32]; - char *p = value; - - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - opt_node = prom_getproperty(opt_node, - "watchdog-timeout", - value, - sizeof(value)); - if(-1 != opt_node) { - /* atoi implementation */ - for(opt_node = 0; /* nop */; p++) { - if(*p >= '0' && *p <= '9') { - opt_node = (10*opt_node)+(*p-'0'); - } - else { - break; - } - } - } - return((-1 == opt_node) ? (0) : (opt_node)); -} - -static int wd_open(struct inode *inode, struct file *f) -{ - lock_kernel(); - switch(iminor(inode)) - { - case WD0_MINOR: - f->private_data = &wd_dev.watchdog[WD0_ID]; - break; - case WD1_MINOR: - f->private_data = &wd_dev.watchdog[WD1_ID]; - break; - case WD2_MINOR: - f->private_data = &wd_dev.watchdog[WD2_ID]; - break; - default: - unlock_kernel(); - return(-ENODEV); - } - - /* Register IRQ on first open of device */ - if(0 == wd_dev.initialized) - { - if (request_irq(wd_dev.irq, - &wd_interrupt, - IRQF_SHARED, - WD_OBPNAME, - (void *)wd_dev.regs)) { - printk("%s: Cannot register IRQ %d\n", - WD_OBPNAME, wd_dev.irq); - unlock_kernel(); - return(-EBUSY); - } - wd_dev.initialized = 1; - } - - unlock_kernel(); - return(nonseekable_open(inode, f)); -} - -static int wd_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static int wd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int setopt = 0; - struct wd_timer* pTimer = (struct wd_timer*)file->private_data; - void __user *argp = (void __user *)arg; - struct watchdog_info info = { - 0, - 0, - "Altera EPF8820ATC144-4" - }; - - if(NULL == pTimer) { - return(-EINVAL); - } - - switch(cmd) - { - /* Generic Linux IOCTLs */ - case WDIOC_GETSUPPORT: - if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) { - return(-EFAULT); - } - break; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int __user *)argp)) - return -EFAULT; - break; - case WDIOC_KEEPALIVE: - wd_pingtimer(pTimer); - break; - case WDIOC_SETOPTIONS: - if(copy_from_user(&setopt, argp, sizeof(unsigned int))) { - return -EFAULT; - } - if(setopt & WDIOS_DISABLECARD) { - if(wd_dev.opt_enable) { - printk( - "%s: cannot disable watchdog in ENABLED mode\n", - WD_OBPNAME); - return(-EINVAL); - } - wd_stoptimer(pTimer); - } - else if(setopt & WDIOS_ENABLECARD) { - wd_starttimer(pTimer); - } - else { - return(-EINVAL); - } - break; - /* Solaris-compatible IOCTLs */ - case WIOCGSTAT: - setopt = wd_getstatus(pTimer); - if(copy_to_user(argp, &setopt, sizeof(unsigned int))) { - return(-EFAULT); - } - break; - case WIOCSTART: - wd_starttimer(pTimer); - break; - case WIOCSTOP: - if(wd_dev.opt_enable) { - printk("%s: cannot disable watchdog in ENABLED mode\n", - WD_OBPNAME); - return(-EINVAL); - } - wd_stoptimer(pTimer); - break; - default: - return(-EINVAL); - } - return(0); -} - -static long wd_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int rval = -ENOIOCTLCMD; - - switch (cmd) { - /* solaris ioctls are specific to this driver */ - case WIOCSTART: - case WIOCSTOP: - case WIOCGSTAT: - lock_kernel(); - rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); - unlock_kernel(); - break; - /* everything else is handled by the generic compat layer */ - default: - break; - } - - return rval; -} - -static ssize_t wd_write(struct file *file, - const char __user *buf, - size_t count, - loff_t *ppos) -{ - struct wd_timer* pTimer = (struct wd_timer*)file->private_data; - - if(NULL == pTimer) { - return(-EINVAL); - } - - if (count) { - wd_pingtimer(pTimer); - return 1; - } - return 0; -} - -static ssize_t wd_read(struct file * file, char __user *buffer, - size_t count, loff_t *ppos) -{ -#ifdef WD_DEBUG - wd_dumpregs(); - return(0); -#else - return(-EINVAL); -#endif /* ifdef WD_DEBUG */ -} - -static irqreturn_t wd_interrupt(int irq, void *dev_id) -{ - /* Only WD0 will interrupt-- others are NMI and we won't - * see them here.... - */ - spin_lock_irq(&wd_dev.lock); - if((unsigned long)wd_dev.regs == (unsigned long)dev_id) - { - wd_stoptimer(&wd_dev.watchdog[WD0_ID]); - wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD; - } - spin_unlock_irq(&wd_dev.lock); - return IRQ_HANDLED; -} - -static const struct file_operations wd_fops = { - .owner = THIS_MODULE, - .ioctl = wd_ioctl, - .compat_ioctl = wd_compat_ioctl, - .open = wd_open, - .write = wd_write, - .read = wd_read, - .release = wd_release, -}; - -static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops }; -static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; -static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; - -#ifdef WD_DEBUG -static void wd_dumpregs(void) -{ - /* Reading from downcounters initiates watchdog countdown-- - * Example is included below for illustration purposes. - */ - int i; - printk("%s: dumping register values\n", WD_OBPNAME); - for(i = WD0_ID; i < WD_NUMDEVS; ++i) { - /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n", - * WD_OBPNAME, - * i, - * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), - * readw(&wd_dev.watchdog[i].regs->dcntr)); - */ - printk("\t%s%i: limit at 0x%lx: 0x%x\n", - WD_OBPNAME, - i, - (unsigned long)(&wd_dev.watchdog[i].regs->limit), - readw(&wd_dev.watchdog[i].regs->limit)); - printk("\t%s%i: status at 0x%lx: 0x%x\n", - WD_OBPNAME, - i, - (unsigned long)(&wd_dev.watchdog[i].regs->status), - readb(&wd_dev.watchdog[i].regs->status)); - printk("\t%s%i: driver status: 0x%x\n", - WD_OBPNAME, - i, - wd_getstatus(&wd_dev.watchdog[i])); - } - printk("\tintr_mask at %p: 0x%x\n", - wd_dev.regs + PLD_IMASK, - readb(wd_dev.regs + PLD_IMASK)); - printk("\tpld_status at %p: 0x%x\n", - wd_dev.regs + PLD_STATUS, - readb(wd_dev.regs + PLD_STATUS)); -} -#endif - -/* Enable or disable watchdog interrupts - * Because of the CP1400 defect this should only be - * called during initialzation or by wd_[start|stop]timer() - * - * pTimer - pointer to timer device, or NULL to indicate all timers - * enable - non-zero to enable interrupts, zero to disable - */ -static void wd_toggleintr(struct wd_timer* pTimer, int enable) -{ - unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); - unsigned char setregs = - (NULL == pTimer) ? - (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : - (pTimer->intr_mask); - - (WD_INTR_ON == enable) ? - (curregs &= ~setregs): - (curregs |= setregs); - - wd_writeb(curregs, wd_dev.regs + PLD_IMASK); - return; -} - -/* Reset countdown timer with 'limit' value and continue countdown. - * This will not start a stopped timer. - * - * pTimer - pointer to timer device - */ -static void wd_pingtimer(struct wd_timer* pTimer) -{ - if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { - wd_readw(pTimer->regs + WD_DCNTR); - } -} - -/* Stop a running watchdog timer-- the timer actually keeps - * running, but the interrupt is masked so that no action is - * taken upon expiration. - * - * pTimer - pointer to timer device - */ -static void wd_stoptimer(struct wd_timer* pTimer) -{ - if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { - wd_toggleintr(pTimer, WD_INTR_OFF); - - if(wd_dev.isbaddoggie) { - pTimer->runstatus |= WD_STAT_BSTOP; - wd_brokentimer((unsigned long)&wd_dev); - } - } -} - -/* Start a watchdog timer with the specified limit value - * If the watchdog is running, it will be restarted with - * the provided limit value. - * - * This function will enable interrupts on the specified - * watchdog. - * - * pTimer - pointer to timer device - * limit - limit (countdown) value in 1/10th seconds - */ -static void wd_starttimer(struct wd_timer* pTimer) -{ - if(wd_dev.isbaddoggie) { - pTimer->runstatus &= ~WD_STAT_BSTOP; - } - pTimer->runstatus &= ~WD_STAT_SVCD; - - wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); - wd_toggleintr(pTimer, WD_INTR_ON); -} - -/* Restarts timer with maximum limit value and - * does not unset 'brokenstop' value. - */ -static void wd_resetbrokentimer(struct wd_timer* pTimer) -{ - wd_toggleintr(pTimer, WD_INTR_ON); - wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); -} - -/* Timer device initialization helper. - * Returns 0 on success, other on failure - */ -static int wd_inittimer(int whichdog) -{ - struct miscdevice *whichmisc; - void __iomem *whichregs; - char whichident[8]; - int whichmask; - __u16 whichlimit; - - switch(whichdog) - { - case WD0_ID: - whichmisc = &wd0_miscdev; - strcpy(whichident, "RIC"); - whichregs = wd_dev.regs + WD0_OFF; - whichmask = WD0_INTR_MASK; - whichlimit= (0 == wd0_timeout) ? - (wd_dev.opt_timeout): - (wd0_timeout); - break; - case WD1_ID: - whichmisc = &wd1_miscdev; - strcpy(whichident, "XIR"); - whichregs = wd_dev.regs + WD1_OFF; - whichmask = WD1_INTR_MASK; - whichlimit= (0 == wd1_timeout) ? - (wd_dev.opt_timeout): - (wd1_timeout); - break; - case WD2_ID: - whichmisc = &wd2_miscdev; - strcpy(whichident, "POR"); - whichregs = wd_dev.regs + WD2_OFF; - whichmask = WD2_INTR_MASK; - whichlimit= (0 == wd2_timeout) ? - (wd_dev.opt_timeout): - (wd2_timeout); - break; - default: - printk("%s: %s: invalid watchdog id: %i\n", - WD_OBPNAME, __func__, whichdog); - return(1); - } - if(0 != misc_register(whichmisc)) - { - return(1); - } - wd_dev.watchdog[whichdog].regs = whichregs; - wd_dev.watchdog[whichdog].timeout = whichlimit; - wd_dev.watchdog[whichdog].intr_mask = whichmask; - wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP; - wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT; - - printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", - WD_OBPNAME, - whichdog, - whichident, - wd_dev.watchdog[whichdog].timeout / 10, - wd_dev.watchdog[whichdog].timeout % 10, - (0 != wd_dev.opt_enable) ? "in ENABLED mode" : ""); - return(0); -} - -/* Timer method called to reset stopped watchdogs-- - * because of the PLD bug on CP1400, we cannot mask - * interrupts within the PLD so me must continually - * reset the timers ad infinitum. - */ -static void wd_brokentimer(unsigned long data) -{ - struct wd_device* pDev = (struct wd_device*)data; - int id, tripped = 0; - - /* kill a running timer instance, in case we - * were called directly instead of by kernel timer - */ - if(timer_pending(&wd_timer)) { - del_timer(&wd_timer); - } - - for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) { - ++tripped; - wd_resetbrokentimer(&pDev->watchdog[id]); - } - } - - if(tripped) { - /* there is at least one timer brokenstopped-- reschedule */ - init_timer(&wd_timer); - wd_timer.expires = WD_BTIMEOUT; - add_timer(&wd_timer); - } -} - -static int wd_getstatus(struct wd_timer* pTimer) -{ - unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); - unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); - unsigned char ret = WD_STOPPED; - - /* determine STOPPED */ - if(0 == stat ) { - return(ret); - } - /* determine EXPIRED vs FREERUN vs RUNNING */ - else if(WD_S_EXPIRED & stat) { - ret = WD_EXPIRED; - } - else if(WD_S_RUNNING & stat) { - if(intr & pTimer->intr_mask) { - ret = WD_FREERUN; - } - else { - /* Fudge WD_EXPIRED status for defective CP1400-- - * IF timer is running - * AND brokenstop is set - * AND an interrupt has been serviced - * we are WD_EXPIRED. - * - * IF timer is running - * AND brokenstop is set - * AND no interrupt has been serviced - * we are WD_FREERUN. - */ - if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) { - if(pTimer->runstatus & WD_STAT_SVCD) { - ret = WD_EXPIRED; - } - else { - /* we could as well pretend we are expired */ - ret = WD_FREERUN; - } - } - else { - ret = WD_RUNNING; - } - } - } - - /* determine SERVICED */ - if(pTimer->runstatus & WD_STAT_SVCD) { - ret |= WD_SERVICED; - } - - return(ret); -} - -static int __init wd_init(void) -{ - int id; - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) - goto ebus_done; - } - } - -ebus_done: - if(!edev) { - printk("%s: unable to locate device\n", WD_OBPNAME); - return -ENODEV; - } - - wd_dev.regs = - ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */ - - if(NULL == wd_dev.regs) { - printk("%s: unable to map registers\n", WD_OBPNAME); - return(-ENODEV); - } - - /* initialize device structure from OBP parameters */ - wd_dev.irq = edev->irqs[0]; - wd_dev.opt_enable = wd_opt_enable(); - wd_dev.opt_reboot = wd_opt_reboot(); - wd_dev.opt_timeout = wd_opt_timeout(); - wd_dev.isbaddoggie = wd_isbroken(); - - /* disable all interrupts unless watchdog-enabled? == true */ - if(! wd_dev.opt_enable) { - wd_toggleintr(NULL, WD_INTR_OFF); - } - - /* register miscellaneous devices */ - for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(0 != wd_inittimer(id)) { - printk("%s%i: unable to initialize\n", WD_OBPNAME, id); - } - } - - /* warn about possible defective PLD */ - if(wd_dev.isbaddoggie) { - init_timer(&wd_timer); - wd_timer.function = wd_brokentimer; - wd_timer.data = (unsigned long)&wd_dev; - wd_timer.expires = WD_BTIMEOUT; - - printk("%s: PLD defect workaround enabled for model %s\n", - WD_OBPNAME, WD_BADMODEL); - } - return(0); -} - -static void __exit wd_cleanup(void) -{ - int id; - - /* if 'watchdog-enable?' == TRUE, timers are not stopped - * when module is unloaded. All brokenstopped timers will - * also now eventually trip. - */ - for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { - if(wd_dev.opt_enable) { - printk(KERN_WARNING "%s%i: timer not stopped at release\n", - WD_OBPNAME, id); - } - else { - wd_stoptimer(&wd_dev.watchdog[id]); - if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) { - wd_resetbrokentimer(&wd_dev.watchdog[id]); - printk(KERN_WARNING - "%s%i: defect workaround disabled at release, "\ - "timer expires in ~%01i sec\n", - WD_OBPNAME, id, - wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); - } - } - } - } - - if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) { - del_timer(&wd_timer); - } - if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) { - misc_deregister(&wd0_miscdev); - } - if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) { - misc_deregister(&wd1_miscdev); - } - if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) { - misc_deregister(&wd2_miscdev); - } - if(0 != wd_dev.initialized) { - free_irq(wd_dev.irq, (void *)wd_dev.regs); - } - iounmap(wd_dev.regs); -} - -module_init(wd_init); -module_exit(wd_cleanup); diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index d8f5c0ca236..2550af4ae43 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 const 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); diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index a408402426f..58e583b61e6 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1,5 +1,4 @@ -/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $ - * envctrl.c: Temperature and Fan monitoring on Machines providing it. +/* envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) @@ -28,12 +27,16 @@ #include <linux/kmod.h> #include <linux/reboot.h> #include <linux/smp_lock.h> +#include <linux/of.h> +#include <linux/of_device.h> -#include <asm/ebus.h> #include <asm/uaccess.h> #include <asm/envctrl.h> #include <asm/io.h> +#define DRIVER_NAME "envctrl" +#define PFX DRIVER_NAME ": " + #define ENVCTRL_MINOR 162 #define PCF8584_ADDRESS 0x55 @@ -193,7 +196,7 @@ static void envtrl_i2c_test_pin(void) } if (limit <= 0) - printk(KERN_INFO "envctrl: Pin status will not clear.\n"); + printk(KERN_INFO PFX "Pin status will not clear.\n"); } /* Function Description: Test busy bit. @@ -211,7 +214,7 @@ static void envctrl_i2c_test_bb(void) } if (limit <= 0) - printk(KERN_INFO "envctrl: Busy bit will not clear.\n"); + printk(KERN_INFO PFX "Busy bit will not clear.\n"); } /* Function Description: Send the address for a read access. @@ -858,11 +861,10 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) /* Function Description: Initialize i2c child device. * Return: None. */ -static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, +static void envctrl_init_i2c_child(struct device_node *dp, struct i2c_child_t *pchild) { int len, i, tbls_size = 0; - struct device_node *dp = edev_child->prom_node; const void *pval; /* Get device address. */ @@ -882,12 +884,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, pchild->tables = kmalloc(tbls_size, GFP_KERNEL); if (pchild->tables == NULL){ - printk("envctrl: Failed to allocate table.\n"); + printk(KERN_ERR PFX "Failed to allocate table.\n"); return; } pval = of_get_property(dp, "tables", &len); if (!pval || len <= 0) { - printk("envctrl: Failed to get table.\n"); + printk(KERN_ERR PFX "Failed to get table.\n"); return; } memcpy(pchild->tables, pval, len); @@ -993,14 +995,14 @@ static int kenvctrld(void *__unused) struct i2c_child_t *cputemp; if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) { - printk(KERN_ERR - "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n"); + printk(KERN_ERR PFX + "kenvctrld unable to monitor CPU temp-- exiting\n"); return -ENODEV; } poll_interval = 5000; /* TODO env_mon_interval */ - printk(KERN_INFO "envctrl: %s starting...\n", current->comm); + printk(KERN_INFO PFX "%s starting...\n", current->comm); for (;;) { msleep_interruptible(poll_interval); @@ -1022,54 +1024,35 @@ static int kenvctrld(void *__unused) } } } - printk(KERN_INFO "envctrl: %s exiting...\n", current->comm); + printk(KERN_INFO PFX "%s exiting...\n", current->comm); return 0; } -static int __init envctrl_init(void) +static int __devinit envctrl_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - struct linux_ebus_child *edev_child = NULL; - int err, i = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "bbc")) { - /* If we find a boot-bus controller node, - * then this envctrl driver is not for us. - */ - return -ENODEV; - } - } - } + struct device_node *dp; + int index, err; - /* Traverse through ebus and ebus device list for i2c device and - * adc and gpio nodes. - */ - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "i2c")) { - i2c = ioremap(edev->resource[0].start, 0x2); - for_each_edevchild(edev, edev_child) { - if (!strcmp("gpio", edev_child->prom_node->name)) { - i2c_childlist[i].i2ctype = I2C_GPIO; - envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); - } - if (!strcmp("adc", edev_child->prom_node->name)) { - i2c_childlist[i].i2ctype = I2C_ADC; - envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); - } - } - goto done; - } + if (i2c) + return -EINVAL; + + i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME); + if (!i2c) + return -ENOMEM; + + index = 0; + dp = op->node->child; + while (dp) { + if (!strcmp(dp->name, "gpio")) { + i2c_childlist[index].i2ctype = I2C_GPIO; + envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); + } else if (!strcmp(dp->name, "adc")) { + i2c_childlist[index].i2ctype = I2C_ADC; + envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); } - } -done: - if (!edev) { - printk("envctrl: I2C device not found.\n"); - return -ENODEV; + dp = dp->sibling; } /* Set device address. */ @@ -1087,7 +1070,7 @@ done: /* Register the device as a minor miscellaneous device. */ err = misc_register(&envctrl_dev); if (err) { - printk("envctrl: Unable to get misc minor %d\n", + printk(KERN_ERR PFX "Unable to get misc minor %d\n", envctrl_dev.minor); goto out_iounmap; } @@ -1096,12 +1079,12 @@ done: * a next child device, so we decrement before reverse-traversal of * child devices. */ - printk("envctrl: initialized "); - for (--i; i >= 0; --i) { + printk(KERN_INFO PFX "Initialized "); + for (--index; index >= 0; --index) { printk("[%s 0x%lx]%s", - (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : - ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), - i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); + (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : + ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), + i2c_childlist[index].addr, (0 == index) ? "\n" : " "); } kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -1115,26 +1098,54 @@ done: out_deregister: misc_deregister(&envctrl_dev); out_iounmap: - iounmap(i2c); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) - kfree(i2c_childlist[i].tables); + of_iounmap(&op->resource[0], i2c, 0x2); + for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) + kfree(i2c_childlist[index].tables); return err; } -static void __exit envctrl_cleanup(void) +static int __devexit envctrl_remove(struct of_device *op) { - int i; + int index; kthread_stop(kenvctrld_task); - iounmap(i2c); + of_iounmap(&op->resource[0], i2c, 0x2); misc_deregister(&envctrl_dev); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) - kfree(i2c_childlist[i].tables); + for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) + kfree(i2c_childlist[index].tables); + + return 0; +} + +static const struct of_device_id envctrl_match[] = { + { + .name = "i2c", + .compatible = "i2cpcf,8584", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, envctrl_match); + +static struct of_platform_driver envctrl_driver = { + .name = DRIVER_NAME, + .match_table = envctrl_match, + .probe = envctrl_probe, + .remove = __devexit_p(envctrl_remove), +}; + +static int __init envctrl_init(void) +{ + return of_register_driver(&envctrl_driver, &of_bus_type); +} + +static void __exit envctrl_exit(void) +{ + of_unregister_driver(&envctrl_driver); } module_init(envctrl_init); -module_exit(envctrl_cleanup); +module_exit(envctrl_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 7d95e151513..41083472ff4 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -1,5 +1,4 @@ -/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $ - * flash.c: Allow mmap access to the OBP Flash, for OBP updates. +/* flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ @@ -15,13 +14,13 @@ #include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/mm.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/ebus.h> #include <asm/upa.h> static DEFINE_SPINLOCK(flash_lock); @@ -161,97 +160,68 @@ static const struct file_operations flash_fops = { static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; -static int __init flash_init(void) +static int __devinit flash_probe(struct of_device *op, + const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev = NULL; -#ifdef CONFIG_PCI - struct linux_ebus *ebus; - struct linux_ebus_device *edev = NULL; - struct linux_prom_registers regs[2]; - int len, nregs; -#endif - int err; - - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "flashprom")) { - if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) { - flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | - (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); - flash.read_size = sdev->reg_addrs[0].reg_size; - flash.write_base = flash.read_base; - flash.write_size = flash.read_size; - } else { - flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | - (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); - flash.read_size = sdev->reg_addrs[0].reg_size; - flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) | - (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL); - flash.write_size = sdev->reg_addrs[1].reg_size; - } - flash.busy = 0; - break; - } - } - if (!sdev) { -#ifdef CONFIG_PCI - const struct linux_prom_registers *ebus_regs; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "flashprom")) - goto ebus_done; - } - } - ebus_done: - if (!edev) - return -ENODEV; - - ebus_regs = of_get_property(edev->prom_node, "reg", &len); - if (!ebus_regs || (len % sizeof(regs[0])) != 0) { - printk("flash: Strange reg property size %d\n", len); - return -ENODEV; - } - - nregs = len / sizeof(ebus_regs[0]); + struct device_node *dp = op->node; + struct device_node *parent; - flash.read_base = edev->resource[0].start; - flash.read_size = ebus_regs[0].reg_size; + parent = dp->parent; - if (nregs == 1) { - flash.write_base = edev->resource[0].start; - flash.write_size = ebus_regs[0].reg_size; - } else if (nregs == 2) { - flash.write_base = edev->resource[1].start; - flash.write_size = ebus_regs[1].reg_size; - } else { - printk("flash: Strange number of regs %d\n", nregs); - return -ENODEV; - } - - flash.busy = 0; - -#else + if (strcmp(parent->name, "sbus") && + strcmp(parent->name, "sbi") && + strcmp(parent->name, "ebus")) return -ENODEV; -#endif + + flash.read_base = op->resource[0].start; + flash.read_size = resource_size(&op->resource[0]); + if (op->resource[1].flags) { + flash.write_base = op->resource[1].start; + flash.write_size = resource_size(&op->resource[1]); + } else { + flash.write_base = op->resource[0].start; + flash.write_size = resource_size(&op->resource[0]); } + flash.busy = 0; - printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n", + printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n", + op->node->full_name, flash.read_base, flash.read_size, flash.write_base, flash.write_size); - err = misc_register(&flash_dev); - if (err) { - printk(KERN_ERR "flash: unable to get misc minor\n"); - return err; - } + return misc_register(&flash_dev); +} + +static int __devexit flash_remove(struct of_device *op) +{ + misc_deregister(&flash_dev); return 0; } +static const struct of_device_id flash_match[] = { + { + .name = "flashprom", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, flash_match); + +static struct of_platform_driver flash_driver = { + .name = "flash", + .match_table = flash_match, + .probe = flash_probe, + .remove = __devexit_p(flash_remove), +}; + +static int __init flash_init(void) +{ + return of_register_driver(&flash_driver, &of_bus_type); +} + static void __exit flash_cleanup(void) { - misc_deregister(&flash_dev); + of_unregister_driver(&flash_driver); } module_init(flash_init); diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c deleted file mode 100644 index b0429917154..00000000000 --- a/drivers/sbus/char/rtc.c +++ /dev/null @@ -1,275 +0,0 @@ -/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $ - * - * Linux/SPARC Real Time Clock Driver - * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) - * - * This is a little driver that lets a user-level program access - * the SPARC Mostek real time clock chip. It is no use unless you - * use the modified clock utility. - * - * Get the modified clock utility from: - * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c - */ - -#include <linux/module.h> -#include <linux/smp_lock.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/miscdevice.h> -#include <linux/slab.h> -#include <linux/fcntl.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <asm/io.h> -#include <asm/mostek.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/rtc.h> - -static int rtc_busy = 0; - -/* This is the structure layout used by drivers/char/rtc.c, we - * support that driver's ioctls so that things are less messy in - * userspace. - */ -struct rtc_time_generic { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; -#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ -#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ -#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ -#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ -#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ -#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ -#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time */ -#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ -#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ -#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ -#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ -#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ -#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ -#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ -#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ - -/* Retrieve the current date and time from the real time clock. */ -static void get_rtc_time(struct rtc_time *t) -{ - void __iomem *regs = mstk48t02_regs; - u8 tmp; - - spin_lock_irq(&mostek_lock); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp |= MSTK_CREG_READ; - mostek_write(regs + MOSTEK_CREG, tmp); - - t->sec = MSTK_REG_SEC(regs); - t->min = MSTK_REG_MIN(regs); - t->hour = MSTK_REG_HOUR(regs); - t->dow = MSTK_REG_DOW(regs); - t->dom = MSTK_REG_DOM(regs); - t->month = MSTK_REG_MONTH(regs); - t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_READ; - mostek_write(regs + MOSTEK_CREG, tmp); - - spin_unlock_irq(&mostek_lock); -} - -/* Set the current date and time inthe real time clock. */ -void set_rtc_time(struct rtc_time *t) -{ - void __iomem *regs = mstk48t02_regs; - u8 tmp; - - spin_lock_irq(&mostek_lock); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp |= MSTK_CREG_WRITE; - mostek_write(regs + MOSTEK_CREG, tmp); - - MSTK_SET_REG_SEC(regs,t->sec); - MSTK_SET_REG_MIN(regs,t->min); - MSTK_SET_REG_HOUR(regs,t->hour); - MSTK_SET_REG_DOW(regs,t->dow); - MSTK_SET_REG_DOM(regs,t->dom); - MSTK_SET_REG_MONTH(regs,t->month); - MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_WRITE; - mostek_write(regs + MOSTEK_CREG, tmp); - - spin_unlock_irq(&mostek_lock); -} - -static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm) -{ - struct rtc_time_generic __user *utm = argp; - - if (__put_user(tm->sec, &utm->tm_sec) || - __put_user(tm->min, &utm->tm_min) || - __put_user(tm->hour, &utm->tm_hour) || - __put_user(tm->dom, &utm->tm_mday) || - __put_user(tm->month, &utm->tm_mon) || - __put_user(tm->year, &utm->tm_year) || - __put_user(tm->dow, &utm->tm_wday) || - __put_user(0, &utm->tm_yday) || - __put_user(0, &utm->tm_isdst)) - return -EFAULT; - - return 0; -} - -static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp) -{ - struct rtc_time_generic __user *utm = argp; - - if (__get_user(tm->sec, &utm->tm_sec) || - __get_user(tm->min, &utm->tm_min) || - __get_user(tm->hour, &utm->tm_hour) || - __get_user(tm->dom, &utm->tm_mday) || - __get_user(tm->month, &utm->tm_mon) || - __get_user(tm->year, &utm->tm_year) || - __get_user(tm->dow, &utm->tm_wday)) - return -EFAULT; - - return 0; -} - -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct rtc_time rtc_tm; - void __user *argp = (void __user *)arg; - - switch (cmd) { - /* No interrupt support, return an error - * compatible with drivers/char/rtc.c - */ - case RTC_AIE_OFF: - case RTC_AIE_ON: - case RTC_PIE_OFF: - case RTC_PIE_ON: - case RTC_UIE_OFF: - case RTC_UIE_ON: - case RTC_IRQP_READ: - case RTC_IRQP_SET: - case RTC_EPOCH_SET: - case RTC_EPOCH_READ: - return -EINVAL; - - case RTCGET: - case RTC_RD_TIME: - memset(&rtc_tm, 0, sizeof(struct rtc_time)); - get_rtc_time(&rtc_tm); - - if (cmd == RTCGET) { - if (copy_to_user(argp, &rtc_tm, - sizeof(struct rtc_time))) - return -EFAULT; - } else if (put_rtc_time_generic(argp, &rtc_tm)) - return -EFAULT; - - return 0; - - - case RTCSET: - case RTC_SET_TIME: - if (!capable(CAP_SYS_TIME)) - return -EPERM; - - if (cmd == RTCSET) { - if (copy_from_user(&rtc_tm, argp, - sizeof(struct rtc_time))) - return -EFAULT; - } else if (get_rtc_time_generic(&rtc_tm, argp)) - return -EFAULT; - - set_rtc_time(&rtc_tm); - - return 0; - - default: - return -EINVAL; - } -} - -static int rtc_open(struct inode *inode, struct file *file) -{ - int ret; - - lock_kernel(); - spin_lock_irq(&mostek_lock); - if (rtc_busy) { - ret = -EBUSY; - } else { - rtc_busy = 1; - ret = 0; - } - spin_unlock_irq(&mostek_lock); - unlock_kernel(); - - return ret; -} - -static int rtc_release(struct inode *inode, struct file *file) -{ - rtc_busy = 0; - - return 0; -} - -static const struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = rtc_ioctl, - .open = rtc_open, - .release = rtc_release, -}; - -static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; - -static int __init rtc_sun_init(void) -{ - int error; - - /* It is possible we are being driven by some other RTC chip - * and thus another RTC driver is handling things. - */ - if (!mstk48t02_regs) - return -ENODEV; - - error = misc_register(&rtc_dev); - if (error) { - printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); - return error; - } - printk("rtc_sun_init: Registered Mostek RTC driver.\n"); - - return 0; -} - -static void __exit rtc_sun_cleanup(void) -{ - misc_deregister(&rtc_dev); -} - -module_init(rtc_sun_init); -module_exit(rtc_sun_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 777637594ac..27993c37775 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -1,7 +1,7 @@ -/* $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> @@ -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> @@ -21,7 +23,6 @@ #include <asm/irq.h> #include <asm/io.h> #include <asm/pgtable.h> -#include <asm/sbus.h> #define UCTRL_MINOR 174 @@ -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 */ @@ -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, @@ -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; } @@ -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 */ @@ -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)); @@ -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]; @@ -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 = @@ -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; @@ -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 = @@ -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(); - return 0; +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 const struct of_device_id uctrl_match[] = { + { + .name = "uctrl", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, uctrl_match); + +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) { - struct uctrl_driver *driver = &drv; + return of_register_driver(&uctrl_driver, &of_bus_type); +} - misc_deregister(&uctrl_dev); - if (driver->irq) - free_irq(driver->irq, driver); - if (driver->regs) - driver->regs = NULL; +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"); diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h deleted file mode 100644 index a5240c52aa0..00000000000 --- a/drivers/sbus/char/vfc.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef _LINUX_VFC_H_ -#define _LINUX_VFC_H_ - -/* - * The control register for the vfc is at offset 0x4000 - * The first field ram bank is located at offset 0x5000 - * The second field ram bank is at offset 0x7000 - * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) - * data and transmit register. - * i2c_s1 controls register s1 of the PCF8584 - * i2c_write seems to be similar to i2c_write but I am not - * quite sure why sun uses it - * - * I am also not sure whether or not you can read the fram bank as a - * whole or whether you must read each word individually from offset - * 0x5000 as soon as I figure it out I will update this file */ - -struct vfc_regs { - char pad1[0x4000]; - unsigned int control; /* Offset 0x4000 */ - char pad2[0xffb]; /* from offset 0x4004 to 0x5000 */ - unsigned int fram_bank1; /* Offset 0x5000 */ - char pad3[0xffb]; /* from offset 0x5004 to 0x6000 */ - unsigned int i2c_reg; /* Offset 0x6000 */ - unsigned int i2c_magic2; /* Offset 0x6004 */ - unsigned int i2c_s1; /* Offset 0x6008 */ - unsigned int i2c_write; /* Offset 0x600c */ - char pad4[0xff0]; /* from offset 0x6010 to 0x7000 */ - unsigned int fram_bank2; /* Offset 0x7000 */ - char pad5[0x1000]; -}; - -#define VFC_SAA9051_NR (13) -#define VFC_SAA9051_ADDR (0x8a) - /* The saa9051 returns the following for its status - * bit 0 - 0 - * bit 1 - SECAM color detected (1=found,0=not found) - * bit 2 - COLOR detected (1=found,0=not found) - * bit 3 - 0 - * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL)) - * bit 5 - 1 - * bit 6 - horizontal frequency lock (1=transmitter found, - * 0=no transmitter) - * bit 7 - Power on reset bit (1=reset,0=at least one successful - * read of the status byte) - */ - -#define VFC_SAA9051_PONRES (0x80) -#define VFC_SAA9051_HLOCK (0x40) -#define VFC_SAA9051_FD (0x10) -#define VFC_SAA9051_CD (0x04) -#define VFC_SAA9051_CS (0x02) - - -/* The various saa9051 sub addresses */ - -#define VFC_SAA9051_IDEL (0) -#define VFC_SAA9051_HSY_START (1) -#define VFC_SAA9051_HSY_STOP (2) -#define VFC_SAA9051_HC_START (3) -#define VFC_SAA9051_HC_STOP (4) -#define VFC_SAA9051_HS_START (5) -#define VFC_SAA9051_HORIZ_PEAK (6) -#define VFC_SAA9051_HUE (7) -#define VFC_SAA9051_C1 (8) -#define VFC_SAA9051_C2 (9) -#define VFC_SAA9051_C3 (0xa) -#define VFC_SAA9051_SECAM_DELAY (0xb) - - -/* Bit settings for saa9051 sub address 0x06 */ - -#define VFC_SAA9051_AP1 (0x01) -#define VFC_SAA9051_AP2 (0x02) -#define VFC_SAA9051_COR1 (0x04) -#define VFC_SAA9051_COR2 (0x08) -#define VFC_SAA9051_BP1 (0x10) -#define VFC_SAA9051_BP2 (0x20) -#define VFC_SAA9051_PF (0x40) -#define VFC_SAA9051_BY (0x80) - - -/* Bit settings for saa9051 sub address 0x08 */ - -#define VFC_SAA9051_CCFR0 (0x01) -#define VFC_SAA9051_CCFR1 (0x02) -#define VFC_SAA9051_YPN (0x04) -#define VFC_SAA9051_ALT (0x08) -#define VFC_SAA9051_CO (0x10) -#define VFC_SAA9051_VTR (0x20) -#define VFC_SAA9051_FS (0x40) -#define VFC_SAA9051_HPLL (0x80) - - -/* Bit settings for saa9051 sub address 9 */ - -#define VFC_SAA9051_SS0 (0x01) -#define VFC_SAA9051_SS1 (0x02) -#define VFC_SAA9051_AFCC (0x04) -#define VFC_SAA9051_CI (0x08) -#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */ -#define VFC_SAA9051_OEC (0x20) -#define VFC_SAA9051_OEY (0x40) -#define VFC_SAA9051_VNL (0x80) - - -/* Bit settings for saa9051 sub address 0x0A */ - -#define VFC_SAA9051_YDL0 (0x01) -#define VFC_SAA9051_YDL1 (0x02) -#define VFC_SAA9051_YDL2 (0x04) -#define VFC_SAA9051_SS2 (0x08) -#define VFC_SAA9051_SS3 (0x10) -#define VFC_SAA9051_YC (0x20) -#define VFC_SAA9051_CT (0x40) -#define VFC_SAA9051_SYC (0x80) - - -#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1]) -#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\ - (a)->saa9051_state_array,\ - VFC_SAA9051_NR)) - - -struct vfc_dev { - volatile struct vfc_regs __iomem *regs; - struct vfc_regs *phys_regs; - unsigned int control_reg; - struct mutex device_lock_mtx; - int instance; - int busy; - unsigned long which_io; - unsigned char saa9051_state_array[VFC_SAA9051_NR]; -}; - -void captstat_reset(struct vfc_dev *); -void memptr_reset(struct vfc_dev *); - -int vfc_pcf8584_init(struct vfc_dev *); -void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long); -void vfc_i2c_delay(struct vfc_dev *); -int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ; -int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ; -int vfc_i2c_reset_bus(struct vfc_dev *); -int vfc_init_i2c_bus(struct vfc_dev *); - -#define VFC_CONTROL_DIAGMODE 0x10000000 -#define VFC_CONTROL_MEMPTR 0x20000000 -#define VFC_CONTROL_CAPTURE 0x02000000 -#define VFC_CONTROL_CAPTRESET 0x04000000 - -#define VFC_STATUS_CAPTURE 0x08000000 - -#ifdef VFC_IOCTL_DEBUG -#define VFC_IOCTL_DEBUG_PRINTK(a) printk a -#else -#define VFC_IOCTL_DEBUG_PRINTK(a) -#endif - -#ifdef VFC_I2C_DEBUG -#define VFC_I2C_DEBUG_PRINTK(a) printk a -#else -#define VFC_I2C_DEBUG_PRINTK(a) -#endif - -#endif /* _LINUX_VFC_H_ */ - - - - - diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c deleted file mode 100644 index 25181bb7d62..00000000000 --- a/drivers/sbus/char/vfc_dev.c +++ /dev/null @@ -1,736 +0,0 @@ -/* - * drivers/sbus/char/vfc_dev.c - * - * Driver for the Videopix Frame Grabber. - * - * In order to use the VFC you need to program the video controller - * chip. This chip is the Phillips SAA9051. You need to call their - * documentation ordering line to get the docs. - * - * There is very little documentation on the VFC itself. There is - * some useful info that can be found in the manuals that come with - * the card. I will hopefully write some better docs at a later date. - * - * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) - * */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/mm.h> -#include <linux/smp_lock.h> - -#include <asm/openprom.h> -#include <asm/oplib.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/sbus.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/uaccess.h> - -#define VFC_MAJOR (60) - -#if 0 -#define VFC_IOCTL_DEBUG -#endif - -#include "vfc.h" -#include <asm/vfc_ioctls.h> - -static const struct file_operations vfc_fops; -static struct vfc_dev **vfc_dev_lst; -static char vfcstr[]="vfc"; -static unsigned char saa9051_init_array[VFC_SAA9051_NR] = { - 0x00, 0x64, 0x72, 0x52, - 0x36, 0x18, 0xff, 0x20, - 0xfc, 0x77, 0xe3, 0x50, - 0x3e -}; - -static void vfc_lock_device(struct vfc_dev *dev) -{ - mutex_lock(&dev->device_lock_mtx); -} - -static void vfc_unlock_device(struct vfc_dev *dev) -{ - mutex_unlock(&dev->device_lock_mtx); -} - - -static void vfc_captstat_reset(struct vfc_dev *dev) -{ - dev->control_reg |= VFC_CONTROL_CAPTRESET; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg &= ~VFC_CONTROL_CAPTRESET; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg |= VFC_CONTROL_CAPTRESET; - sbus_writel(dev->control_reg, &dev->regs->control); -} - -static void vfc_memptr_reset(struct vfc_dev *dev) -{ - dev->control_reg |= VFC_CONTROL_MEMPTR; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg &= ~VFC_CONTROL_MEMPTR; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg |= VFC_CONTROL_MEMPTR; - sbus_writel(dev->control_reg, &dev->regs->control); -} - -static int vfc_csr_init(struct vfc_dev *dev) -{ - dev->control_reg = 0x80000000; - sbus_writel(dev->control_reg, &dev->regs->control); - udelay(200); - dev->control_reg &= ~0x80000000; - sbus_writel(dev->control_reg, &dev->regs->control); - udelay(100); - sbus_writel(0x0f000000, &dev->regs->i2c_magic2); - - vfc_memptr_reset(dev); - - dev->control_reg &= ~VFC_CONTROL_DIAGMODE; - dev->control_reg &= ~VFC_CONTROL_CAPTURE; - dev->control_reg |= 0x40000000; - sbus_writel(dev->control_reg, &dev->regs->control); - - vfc_captstat_reset(dev); - - return 0; -} - -static int vfc_saa9051_init(struct vfc_dev *dev) -{ - int i; - - for (i = 0; i < VFC_SAA9051_NR; i++) - dev->saa9051_state_array[i] = saa9051_init_array[i]; - - vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR, - dev->saa9051_state_array, VFC_SAA9051_NR); - return 0; -} - -static int init_vfc_hw(struct vfc_dev *dev) -{ - vfc_lock_device(dev); - vfc_csr_init(dev); - - vfc_pcf8584_init(dev); - vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic - sun code above*/ - vfc_saa9051_init(dev); - vfc_unlock_device(dev); - return 0; -} - -static int init_vfc_devstruct(struct vfc_dev *dev, int instance) -{ - dev->instance=instance; - mutex_init(&dev->device_lock_mtx); - dev->control_reg=0; - dev->busy=0; - return 0; -} - -static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, - int instance) -{ - if(dev == NULL) { - printk(KERN_ERR "VFC: Bogus pointer passed\n"); - return -ENOMEM; - } - printk("Initializing vfc%d\n",instance); - dev->regs = NULL; - dev->regs = (volatile struct vfc_regs __iomem *) - sbus_ioremap(&sdev->resource[0], 0, - sizeof(struct vfc_regs), vfcstr); - dev->which_io = sdev->reg_addrs[0].which_io; - dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr; - if (dev->regs == NULL) - return -EIO; - - printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", - instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); - - if (init_vfc_devstruct(dev, instance)) - return -EINVAL; - if (init_vfc_hw(dev)) - return -EIO; - return 0; -} - - -static struct vfc_dev *vfc_get_dev_ptr(int instance) -{ - return vfc_dev_lst[instance]; -} - -static DEFINE_SPINLOCK(vfc_dev_lock); - -static int vfc_open(struct inode *inode, struct file *file) -{ - struct vfc_dev *dev; - - lock_kernel(); - spin_lock(&vfc_dev_lock); - dev = vfc_get_dev_ptr(iminor(inode)); - if (dev == NULL) { - spin_unlock(&vfc_dev_lock); - unlock_kernel(); - return -ENODEV; - } - if (dev->busy) { - spin_unlock(&vfc_dev_lock); - unlock_kernel(); - return -EBUSY; - } - - dev->busy = 1; - spin_unlock(&vfc_dev_lock); - - vfc_lock_device(dev); - - vfc_csr_init(dev); - vfc_pcf8584_init(dev); - vfc_init_i2c_bus(dev); - vfc_saa9051_init(dev); - vfc_memptr_reset(dev); - vfc_captstat_reset(dev); - - vfc_unlock_device(dev); - unlock_kernel(); - return 0; -} - -static int vfc_release(struct inode *inode,struct file *file) -{ - struct vfc_dev *dev; - - spin_lock(&vfc_dev_lock); - dev = vfc_get_dev_ptr(iminor(inode)); - if (!dev || !dev->busy) { - spin_unlock(&vfc_dev_lock); - return -EINVAL; - } - dev->busy = 0; - spin_unlock(&vfc_dev_lock); - return 0; -} - -static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp) -{ - struct vfc_debug_inout inout; - unsigned char *buffer; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - switch(cmd) { - case VFC_I2C_SEND: - if(copy_from_user(&inout, argp, sizeof(inout))) - return -EFAULT; - - buffer = kmalloc(inout.len, GFP_KERNEL); - if (buffer == NULL) - return -ENOMEM; - - if(copy_from_user(buffer, inout.buffer, inout.len)) { - kfree(buffer); - return -EFAULT; - } - - - vfc_lock_device(dev); - inout.ret= - vfc_i2c_sendbuf(dev,inout.addr & 0xff, - buffer,inout.len); - - if (copy_to_user(argp,&inout,sizeof(inout))) { - vfc_unlock_device(dev); - kfree(buffer); - return -EFAULT; - } - vfc_unlock_device(dev); - - break; - case VFC_I2C_RECV: - if (copy_from_user(&inout, argp, sizeof(inout))) - return -EFAULT; - - buffer = kzalloc(inout.len, GFP_KERNEL); - if (buffer == NULL) - return -ENOMEM; - - vfc_lock_device(dev); - inout.ret= - vfc_i2c_recvbuf(dev,inout.addr & 0xff - ,buffer,inout.len); - vfc_unlock_device(dev); - - if (copy_to_user(inout.buffer, buffer, inout.len)) { - kfree(buffer); - return -EFAULT; - } - if (copy_to_user(argp,&inout,sizeof(inout))) { - kfree(buffer); - return -EFAULT; - } - kfree(buffer); - break; - default: - return -EINVAL; - }; - - return 0; -} - -static int vfc_capture_start(struct vfc_dev *dev) -{ - vfc_captstat_reset(dev); - dev->control_reg = sbus_readl(&dev->regs->control); - if((dev->control_reg & VFC_STATUS_CAPTURE)) { - printk(KERN_ERR "vfc%d: vfc capture status not reset\n", - dev->instance); - return -EIO; - } - - vfc_lock_device(dev); - dev->control_reg &= ~VFC_CONTROL_CAPTURE; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg |= VFC_CONTROL_CAPTURE; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg &= ~VFC_CONTROL_CAPTURE; - sbus_writel(dev->control_reg, &dev->regs->control); - vfc_unlock_device(dev); - - return 0; -} - -static int vfc_capture_poll(struct vfc_dev *dev) -{ - int timeout = 1000; - - while (!timeout--) { - if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE) - break; - vfc_i2c_delay_no_busy(dev, 100); - } - if(!timeout) { - printk(KERN_WARNING "vfc%d: capture timed out\n", - dev->instance); - return -ETIMEDOUT; - } - return 0; -} - - - -static int vfc_set_control_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int setcmd, ret = 0; - - if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int))) - return -EFAULT; - - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", - dev->instance,setcmd)); - - switch(setcmd) { - case MEMPRST: - vfc_lock_device(dev); - vfc_memptr_reset(dev); - vfc_unlock_device(dev); - ret=0; - break; - case CAPTRCMD: - vfc_capture_start(dev); - vfc_capture_poll(dev); - break; - case DIAGMODE: - if(capable(CAP_SYS_ADMIN)) { - vfc_lock_device(dev); - dev->control_reg |= VFC_CONTROL_DIAGMODE; - sbus_writel(dev->control_reg, &dev->regs->control); - vfc_unlock_device(dev); - ret = 0; - } else { - ret = -EPERM; - } - break; - case NORMMODE: - vfc_lock_device(dev); - dev->control_reg &= ~VFC_CONTROL_DIAGMODE; - sbus_writel(dev->control_reg, &dev->regs->control); - vfc_unlock_device(dev); - ret = 0; - break; - case CAPTRSTR: - vfc_capture_start(dev); - ret = 0; - break; - case CAPTRWAIT: - vfc_capture_poll(dev); - ret = 0; - break; - default: - ret = -EINVAL; - break; - }; - - return ret; -} - - -static int vfc_port_change_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int ret = 0; - int cmd; - - if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " - "vfc_port_change_ioctl\n", - dev->instance)); - return -EFAULT; - } - - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n", - dev->instance, cmd)); - - switch(cmd) { - case 1: - case 2: - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18; - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2; - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3; - VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e; - break; - case 3: - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a; - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde; - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = - VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2; - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC; - VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0; - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= - ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); - break; - default: - ret = -EINVAL; - return ret; - break; - } - - switch(cmd) { - case 1: - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= - (VFC_SAA9051_SS0 | VFC_SAA9051_SS1); - break; - case 2: - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= - ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; - break; - case 3: - break; - default: - ret = -EINVAL; - return ret; - break; - } - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2); - ret=vfc_update_saa9051(dev); - udelay(500); - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2); - ret=vfc_update_saa9051(dev); - return ret; -} - -static int vfc_set_video_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int ret = 0; - int cmd; - - if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " - "vfc_set_video_ioctl\n", - dev->instance)); - return ret; - } - - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n", - dev->instance, cmd)); - switch(cmd) { - case STD_NTSC: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT; - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | - VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS; - ret = vfc_update_saa9051(dev); - break; - case STD_PAL: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | - VFC_SAA9051_CCFR1 | - VFC_SAA9051_CCFR0 | - VFC_SAA9051_FS); - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT; - ret = vfc_update_saa9051(dev); - break; - - case COLOR_ON: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO; - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &= - ~(VFC_SAA9051_BY | VFC_SAA9051_PF); - ret = vfc_update_saa9051(dev); - break; - case MONO: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO); - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |= - (VFC_SAA9051_BY | VFC_SAA9051_PF); - ret = vfc_update_saa9051(dev); - break; - default: - ret = -EINVAL; - break; - }; - - return ret; -} - -static int vfc_get_video_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int ret = 0; - unsigned int status = NO_LOCK; - unsigned char buf[1]; - - if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) { - printk(KERN_ERR "vfc%d: Unable to get status\n", - dev->instance); - return -EIO; - } - - if(buf[0] & VFC_SAA9051_HLOCK) { - status = NO_LOCK; - } else if(buf[0] & VFC_SAA9051_FD) { - if(buf[0] & VFC_SAA9051_CD) - status = NTSC_COLOR; - else - status = NTSC_NOCOLOR; - } else { - if(buf[0] & VFC_SAA9051_CD) - status = PAL_COLOR; - else - status = PAL_NOCOLOR; - } - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; " - "buf[0]=%x\n", dev->instance, status, buf[0])); - - if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " - "vfc_get_video_ioctl\n", - dev->instance)); - return ret; - } - return ret; -} - -static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = 0; - unsigned int tmp; - struct vfc_dev *dev; - void __user *argp = (void __user *)arg; - - dev = vfc_get_dev_ptr(iminor(inode)); - if(dev == NULL) - return -ENODEV; - - switch(cmd & 0x0000ffff) { - case VFCGCTRL: -#if 0 - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance)); -#endif - tmp = sbus_readl(&dev->regs->control); - if(copy_to_user(argp, &tmp, sizeof(unsigned int))) { - ret = -EFAULT; - break; - } - ret = 0; - break; - case VFCSCTRL: - ret = vfc_set_control_ioctl(inode, file, dev, arg); - break; - case VFCGVID: - ret = vfc_get_video_ioctl(inode, file, dev, arg); - break; - case VFCSVID: - ret = vfc_set_video_ioctl(inode, file, dev, arg); - break; - case VFCHUE: - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance)); - if(copy_from_user(&tmp,argp,sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " - "to IOCTL(VFCHUE)", dev->instance)); - ret = -EFAULT; - } else { - VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp; - vfc_update_saa9051(dev); - ret = 0; - } - break; - case VFCPORTCHG: - ret = vfc_port_change_ioctl(inode, file, dev, arg); - break; - case VFCRDINFO: - ret = -EINVAL; - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance)); - break; - default: - ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp); - break; - }; - - return ret; -} - -static int vfc_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned int map_size, ret, map_offset; - struct vfc_dev *dev; - - dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode)); - if(dev == NULL) - return -ENODEV; - - map_size = vma->vm_end - vma->vm_start; - if(map_size > sizeof(struct vfc_regs)) - map_size = sizeof(struct vfc_regs); - - vma->vm_flags |= - (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE); - map_offset = (unsigned int) (long)dev->phys_regs; - ret = io_remap_pfn_range(vma, vma->vm_start, - MK_IOSPACE_PFN(dev->which_io, - map_offset >> PAGE_SHIFT), - map_size, vma->vm_page_prot); - - if(ret) - return -EAGAIN; - - return 0; -} - - -static const struct file_operations vfc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = vfc_ioctl, - .mmap = vfc_mmap, - .open = vfc_open, - .release = vfc_release, -}; - -static int vfc_probe(void) -{ - struct sbus_bus *sbus; - struct sbus_dev *sdev = NULL; - int ret; - int instance = 0, cards = 0; - - for_all_sbusdev(sdev, sbus) { - if (strcmp(sdev->prom_name, "vfc") == 0) { - cards++; - continue; - } - } - - if (!cards) - return -ENODEV; - - vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL); - if (vfc_dev_lst == NULL) - return -ENOMEM; - vfc_dev_lst[cards] = NULL; - - ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops); - if(ret) { - printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR); - kfree(vfc_dev_lst); - return -EIO; - } - instance = 0; - for_all_sbusdev(sdev, sbus) { - if (strcmp(sdev->prom_name, "vfc") == 0) { - vfc_dev_lst[instance]=(struct vfc_dev *) - kmalloc(sizeof(struct vfc_dev), GFP_KERNEL); - if (vfc_dev_lst[instance] == NULL) - return -ENOMEM; - ret = init_vfc_device(sdev, - vfc_dev_lst[instance], - instance); - if(ret) { - printk(KERN_ERR "Unable to initialize" - " vfc%d device\n", - instance); - } else { - } - - instance++; - continue; - } - } - - return 0; -} - -#ifdef MODULE -int init_module(void) -#else -int vfc_init(void) -#endif -{ - return vfc_probe(); -} - -#ifdef MODULE -static void deinit_vfc_device(struct vfc_dev *dev) -{ - if(dev == NULL) - return; - sbus_iounmap(dev->regs, sizeof(struct vfc_regs)); - kfree(dev); -} - -void cleanup_module(void) -{ - struct vfc_dev **devp; - - unregister_chrdev(VFC_MAJOR,vfcstr); - - for (devp = vfc_dev_lst; *devp; devp++) - deinit_vfc_device(*devp); - - kfree(vfc_dev_lst); - return; -} -#endif - -MODULE_LICENSE("GPL"); - diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c deleted file mode 100644 index 32b986e0ed7..00000000000 --- a/drivers/sbus/char/vfc_i2c.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * drivers/sbus/char/vfc_i2c.c - * - * Driver for the Videopix Frame Grabber. - * - * Functions that support the Phillips i2c(I squared C) bus on the vfc - * Documentation for the Phillips I2C bus can be found on the - * phillips home page - * - * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) - * - */ - -/* NOTE: It seems to me that the documentation regarding the -pcd8584t/pcf8584 does not show the correct way to address the i2c bus. -Based on the information on the I2C bus itself and the remainder of -the Phillips docs the following algorithms appear to be correct. I am -fairly certain that the flowcharts in the phillips docs are wrong. */ - - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/delay.h> -#include <asm/openprom.h> -#include <asm/oplib.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/sbus.h> - -#if 0 -#define VFC_I2C_DEBUG -#endif - -#include "vfc.h" -#include "vfc_i2c.h" - -#define WRITE_S1(__val) \ - sbus_writel(__val, &dev->regs->i2c_s1) -#define WRITE_REG(__val) \ - sbus_writel(__val, &dev->regs->i2c_reg) - -#define VFC_I2C_READ (0x1) -#define VFC_I2C_WRITE (0x0) - -/****** - The i2c bus controller chip on the VFC is a pcd8584t, but - phillips claims it doesn't exist. As far as I can tell it is - identical to the PCF8584 so I treat it like it is the pcf8584. - - NOTE: The pcf8584 only cares - about the msb of the word you feed it -*****/ - -int vfc_pcf8584_init(struct vfc_dev *dev) -{ - /* This will also choose register S0_OWN so we can set it. */ - WRITE_S1(RESET); - - /* The pcf8584 shifts this value left one bit and uses - * it as its i2c bus address. - */ - WRITE_REG(0x55000000); - - /* This will set the i2c bus at the same speed sun uses, - * and set another magic bit. - */ - WRITE_S1(SELECT(S2)); - WRITE_REG(0x14000000); - - /* Enable the serial port, idle the i2c bus and set - * the data reg to s0. - */ - WRITE_S1(CLEAR_I2C_BUS); - udelay(100); - return 0; -} - -void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) -{ - schedule_timeout_uninterruptible(usecs_to_jiffies(usecs)); -} - -void inline vfc_i2c_delay(struct vfc_dev *dev) -{ - vfc_i2c_delay_no_busy(dev, 100); -} - -int vfc_init_i2c_bus(struct vfc_dev *dev) -{ - WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK); - vfc_i2c_reset_bus(dev); - return 0; -} - -int vfc_i2c_reset_bus(struct vfc_dev *dev) -{ - VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n", - dev->instance)); - if(dev == NULL) - return -EINVAL; - if(dev->regs == NULL) - return -EINVAL; - WRITE_S1(SEND_I2C_STOP); - WRITE_S1(SEND_I2C_STOP | ACK); - vfc_i2c_delay(dev); - WRITE_S1(CLEAR_I2C_BUS); - VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n", - dev->instance, - sbus_readl(&dev->regs->i2c_s1))); - return 0; -} - -static int vfc_i2c_wait_for_bus(struct vfc_dev *dev) -{ - int timeout = 1000; - - while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) { - if(!(timeout--)) - return -ETIMEDOUT; - vfc_i2c_delay(dev); - } - return 0; -} - -static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack) -{ - int timeout = 1000; - int s1; - - while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) { - if (!(timeout--)) - return -ETIMEDOUT; - vfc_i2c_delay(dev); - } - if (ack == VFC_I2C_ACK_CHECK) { - if(s1 & LRB) - return -EIO; - } - return 0; -} - -#define SHIFT(a) ((a) << 24) -static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, - char mode) -{ - int ret, raddr; -#if 1 - WRITE_S1(SEND_I2C_STOP | ACK); - WRITE_S1(SELECT(S0) | ENABLE_SERIAL); - vfc_i2c_delay(dev); -#endif - - switch(mode) { - case VFC_I2C_READ: - raddr = SHIFT(((unsigned int)addr | 0x1)); - WRITE_REG(raddr); - VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n", - dev->instance, addr | 0x1)); - break; - case VFC_I2C_WRITE: - raddr = SHIFT((unsigned int)addr & ~0x1); - WRITE_REG(raddr); - VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n", - dev->instance, addr & ~0x1)); - break; - default: - return -EINVAL; - }; - - WRITE_S1(SEND_I2C_START); - vfc_i2c_delay(dev); - ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait - for the - i2c send - to finish - here but - Sun - doesn't, - hmm */ - if (ret) { - printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n", - dev->instance); - return ret; - } else if (mode == VFC_I2C_READ) { - if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) { - printk(KERN_WARNING - "vfc%d: returned slave address " - "mismatch(%x,%x)\n", - dev->instance, raddr, ret); - } - } - return 0; -} - -static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte) -{ - int ret; - u32 val = SHIFT((unsigned int)*byte); - - WRITE_REG(val); - - ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK); - switch(ret) { - case -ETIMEDOUT: - printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n", - dev->instance); - break; - case -EIO: - ret = XMIT_LAST_BYTE; - break; - default: - break; - }; - - return ret; -} - -static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, - int last) -{ - int ret; - - if (last) { - WRITE_REG(NEGATIVE_ACK); - VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n", - dev->instance)); - } else { - WRITE_S1(ACK); - } - - ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK); - if(ret) { - printk(KERN_ERR "vfc%d: " - "VFC recv byte timed out\n", - dev->instance); - } - *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24; - return ret; -} - -int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr, - char *buf, int count) -{ - int ret, last; - - if(!(count && buf && dev && dev->regs) ) - return -EINVAL; - - if ((ret = vfc_i2c_wait_for_bus(dev))) { - printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance); - return ret; - } - - if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) { - WRITE_S1(SEND_I2C_STOP); - vfc_i2c_delay(dev); - return ret; - } - - last = 0; - while (count--) { - if (!count) - last = 1; - if ((ret = vfc_i2c_recv_byte(dev, buf, last))) { - printk(KERN_ERR "vfc%d: " - "VFC error while receiving byte\n", - dev->instance); - WRITE_S1(SEND_I2C_STOP); - ret = -EINVAL; - } - buf++; - } - WRITE_S1(SEND_I2C_STOP | ACK); - vfc_i2c_delay(dev); - return ret; -} - -int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, - char *buf, int count) -{ - int ret; - - if (!(buf && dev && dev->regs)) - return -EINVAL; - - if ((ret = vfc_i2c_wait_for_bus(dev))) { - printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance); - return ret; - } - - if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) { - WRITE_S1(SEND_I2C_STOP); - vfc_i2c_delay(dev); - return ret; - } - - while(count--) { - ret = vfc_i2c_xmit_byte(dev, buf); - switch(ret) { - case XMIT_LAST_BYTE: - VFC_I2C_DEBUG_PRINTK(("vfc%d: " - "Receiver ended transmission with " - " %d bytes remaining\n", - dev->instance, count)); - ret = 0; - goto done; - break; - case 0: - break; - default: - printk(KERN_ERR "vfc%d: " - "VFC error while sending byte\n", dev->instance); - break; - }; - - buf++; - } -done: - WRITE_S1(SEND_I2C_STOP | ACK); - vfc_i2c_delay(dev); - return ret; -} - - - - - - - - - diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h deleted file mode 100644 index a2e6973209d..00000000000 --- a/drivers/sbus/char/vfc_i2c.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _LINUX_VFC_I2C_H_ -#define _LINUX_VFC_I2C_H_ - -/* control bits */ -#define PIN (0x80000000) -#define ESO (0x40000000) -#define ES1 (0x20000000) -#define ES2 (0x10000000) -#define ENI (0x08000000) -#define STA (0x04000000) -#define STO (0x02000000) -#define ACK (0x01000000) - -/* status bits */ -#define STS (0x20000000) -#define BER (0x10000000) -#define LRB (0x08000000) -#define AAS (0x04000000) -#define LAB (0x02000000) -#define BB (0x01000000) - -#define SEND_I2C_START (PIN | ESO | STA) -#define SEND_I2C_STOP (PIN | ESO | STO) -#define CLEAR_I2C_BUS (PIN | ESO | ACK) -#define NEGATIVE_ACK ((ESO) & ~ACK) - -#define SELECT(a) (a) -#define S0 (PIN | ESO | ES1) -#define S0_OWN (PIN) -#define S2 (PIN | ES1) -#define S3 (PIN | ES2) - -#define ENABLE_SERIAL (PIN | ESO) -#define DISABLE_SERIAL (PIN) -#define RESET (PIN) - -#define XMIT_LAST_BYTE (1) -#define VFC_I2C_ACK_CHECK (1) -#define VFC_I2C_NO_ACK_CHECK (0) - -#endif /* _LINUX_VFC_I2C_H_ */ - - - diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c deleted file mode 100644 index ab0d2de3324..00000000000 --- a/drivers/sbus/dvma.c +++ /dev/null @@ -1,136 +0,0 @@ -/* dvma.c: Routines that are used to access DMA on the Sparc SBus. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> - -#include <asm/oplib.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/sbus.h> - -struct sbus_dma *dma_chain; - -static void __init init_one_dvma(struct sbus_dma *dma, int num_dma) -{ - printk("dma%d: ", num_dma); - - dma->next = NULL; - dma->running = 0; /* No transfers going on as of yet */ - dma->allocated = 0; /* No one has allocated us yet */ - switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) { - case DMA_VERS0: - dma->revision = dvmarev0; - printk("Revision 0 "); - break; - case DMA_ESCV1: - dma->revision = dvmaesc1; - printk("ESC Revision 1 "); - break; - case DMA_VERS1: - dma->revision = dvmarev1; - printk("Revision 1 "); - break; - case DMA_VERS2: - dma->revision = dvmarev2; - printk("Revision 2 "); - break; - case DMA_VERHME: - dma->revision = dvmahme; - printk("HME DVMA gate array "); - break; - case DMA_VERSPLUS: - dma->revision = dvmarevplus; - printk("Revision 1 PLUS "); - break; - default: - printk("unknown dma version %08x", - sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID); - dma->allocated = 1; - break; - } - printk("\n"); -} - -/* Probe this SBus DMA module(s) */ -void __init dvma_init(struct sbus_bus *sbus) -{ - struct sbus_dev *this_dev; - struct sbus_dma *dma; - struct sbus_dma *dchain; - static int num_dma = 0; - - for_each_sbusdev(this_dev, sbus) { - char *name = this_dev->prom_name; - int hme = 0; - - if(!strcmp(name, "SUNW,fas")) - hme = 1; - else if(strcmp(name, "dma") && - strcmp(name, "ledma") && - strcmp(name, "espdma")) - continue; - - /* Found one... */ - dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); - - dma->sdev = this_dev; - - /* Put at end of dma chain */ - dchain = dma_chain; - if(dchain) { - while(dchain->next) - dchain = dchain->next; - dchain->next = dma; - } else { - /* We're the first in line */ - dma_chain = dma; - } - - dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0, - dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1, - "dma"); - - dma->node = dma->sdev->prom_node; - - init_one_dvma(dma, num_dma++); - } -} - -#ifdef CONFIG_SUN4 - -#include <asm/sun4paddr.h> - -void __init sun4_dvma_init(void) -{ - struct sbus_dma *dma; - struct resource r; - - if(sun4_dma_physaddr) { - dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); - - /* No SBUS */ - dma->sdev = NULL; - - /* Only one DMA device */ - dma_chain = dma; - - memset(&r, 0, sizeof(r)); - r.start = sun4_dma_physaddr; - dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma"); - - /* No prom node */ - dma->node = 0x0; - - init_one_dvma(dma, 0); - } else { - dma_chain = NULL; - } -} - -#endif diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c deleted file mode 100644 index 9c129248466..00000000000 --- a/drivers/sbus/sbus.c +++ /dev/null @@ -1,316 +0,0 @@ -/* sbus.c: SBus support routines. - * - * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/of_device.h> - -#include <asm/system.h> -#include <asm/sbus.h> -#include <asm/dma.h> -#include <asm/oplib.h> -#include <asm/prom.h> -#include <asm/bpp.h> -#include <asm/irq.h> - -static ssize_t -show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) -{ - struct sbus_dev *sbus; - - sbus = to_sbus_device(dev); - - return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name); -} - -static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL); - -struct sbus_bus *sbus_root; - -static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) -{ - struct dev_archdata *sd; - unsigned long base; - const void *pval; - int len, err; - - sdev->prom_node = dp->node; - strcpy(sdev->prom_name, dp->name); - - pval = of_get_property(dp, "reg", &len); - sdev->num_registers = 0; - if (pval) { - memcpy(sdev->reg_addrs, pval, len); - - sdev->num_registers = - len / sizeof(struct linux_prom_registers); - - base = (unsigned long) sdev->reg_addrs[0].phys_addr; - - /* Compute the slot number. */ - if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) - sdev->slot = sbus_dev_slot(base); - else - sdev->slot = sdev->reg_addrs[0].which_io; - } - - pval = of_get_property(dp, "ranges", &len); - sdev->num_device_ranges = 0; - if (pval) { - memcpy(sdev->device_ranges, pval, len); - sdev->num_device_ranges = - len / sizeof(struct linux_prom_ranges); - } - - sbus_fill_device_irq(sdev); - - sd = &sdev->ofdev.dev.archdata; - sd->prom_node = dp; - sd->op = &sdev->ofdev; - - sdev->ofdev.node = dp; - if (sdev->parent) - sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; - else - sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; - sdev->ofdev.dev.bus = &sbus_bus_type; - dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node); - - if (of_device_register(&sdev->ofdev) != 0) - printk(KERN_DEBUG "sbus: device registration error for %s!\n", - dp->path_component_name); - - /* WE HAVE BEEN INVADED BY ALIENS! */ - err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr); -} - -static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) -{ - const void *pval; - int len; - - pval = of_get_property(dp, "ranges", &len); - sbus->num_sbus_ranges = 0; - if (pval) { - memcpy(sbus->sbus_ranges, pval, len); - sbus->num_sbus_ranges = - len / sizeof(struct linux_prom_ranges); - - sbus_arch_bus_ranges_init(dp->parent, sbus); - } -} - -static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, - int num_ranges, - struct linux_prom_registers *regs, - int num_regs) -{ - if (num_ranges) { - int regnum; - - for (regnum = 0; regnum < num_regs; regnum++) { - int rngnum; - - for (rngnum = 0; rngnum < num_ranges; rngnum++) { - if (regs[regnum].which_io == ranges[rngnum].ot_child_space) - break; - } - if (rngnum == num_ranges) { - /* We used to flag this as an error. Actually - * some devices do not report the regs as we expect. - * For example, see SUNW,pln device. In that case - * the reg property is in a format internal to that - * node, ie. it is not in the SBUS register space - * per se. -DaveM - */ - return; - } - regs[regnum].which_io = ranges[rngnum].ot_parent_space; - regs[regnum].phys_addr -= ranges[rngnum].ot_child_base; - regs[regnum].phys_addr += ranges[rngnum].ot_parent_base; - } - } -} - -static void __init __fixup_regs_sdev(struct sbus_dev *sdev) -{ - if (sdev->num_registers != 0) { - struct sbus_dev *parent = sdev->parent; - int i; - - while (parent != NULL) { - __apply_ranges_to_regs(parent->device_ranges, - parent->num_device_ranges, - sdev->reg_addrs, - sdev->num_registers); - - parent = parent->parent; - } - - __apply_ranges_to_regs(sdev->bus->sbus_ranges, - sdev->bus->num_sbus_ranges, - sdev->reg_addrs, - sdev->num_registers); - - for (i = 0; i < sdev->num_registers; i++) { - struct resource *res = &sdev->resource[i]; - - res->start = sdev->reg_addrs[i].phys_addr; - res->end = (res->start + - (unsigned long)sdev->reg_addrs[i].reg_size - 1UL); - res->flags = IORESOURCE_IO | - (sdev->reg_addrs[i].which_io & 0xff); - } - } -} - -static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) -{ - struct sbus_dev *sdev; - - for (sdev = first_sdev; sdev; sdev = sdev->next) { - if (sdev->child) - sbus_fixup_all_regs(sdev->child); - __fixup_regs_sdev(sdev); - } -} - -/* We preserve the "probe order" of these bus and device lists to give - * the same ordering as the old code. - */ -static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root) -{ - while (*root) - root = &(*root)->next; - *root = sbus; - sbus->next = NULL; -} - -static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) -{ - while (*root) - root = &(*root)->next; - *root = sdev; - sdev->next = NULL; -} - -static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus) -{ - dp = dp->child; - while (dp) { - struct sbus_dev *sdev; - - sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - if (sdev) { - sdev_insert(sdev, &parent->child); - - sdev->bus = sbus; - sdev->parent = parent; - sdev->ofdev.dev.archdata.iommu = - sbus->ofdev.dev.archdata.iommu; - sdev->ofdev.dev.archdata.stc = - sbus->ofdev.dev.archdata.stc; - - fill_sbus_device(dp, sdev); - - walk_children(dp, sdev, sbus); - } - dp = dp->sibling; - } -} - -static void __init build_one_sbus(struct device_node *dp, int num_sbus) -{ - struct sbus_bus *sbus; - unsigned int sbus_clock; - struct device_node *dev_dp; - - sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); - if (!sbus) - return; - - sbus_insert(sbus, &sbus_root); - sbus->prom_node = dp->node; - - sbus_setup_iommu(sbus, dp); - - printk("sbus%d: ", num_sbus); - - sbus_clock = of_getintprop_default(dp, "clock-frequency", - (25*1000*1000)); - sbus->clock_freq = sbus_clock; - - printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), - (int) (((sbus_clock/1000)%1000 != 0) ? - (((sbus_clock/1000)%1000) + 1000) : 0)); - - strcpy(sbus->prom_name, dp->name); - - sbus_setup_arch_props(sbus, dp); - - sbus_bus_ranges_init(dp, sbus); - - sbus->ofdev.node = dp; - sbus->ofdev.dev.parent = NULL; - sbus->ofdev.dev.bus = &sbus_bus_type; - dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus); - - if (of_device_register(&sbus->ofdev) != 0) - printk(KERN_DEBUG "sbus: device registration error for %s!\n", - dev_name(&sbus->ofdev.dev)); - - dev_dp = dp->child; - while (dev_dp) { - struct sbus_dev *sdev; - - sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - if (sdev) { - sdev_insert(sdev, &sbus->devices); - - sdev->bus = sbus; - sdev->parent = NULL; - sdev->ofdev.dev.archdata.iommu = - sbus->ofdev.dev.archdata.iommu; - sdev->ofdev.dev.archdata.stc = - sbus->ofdev.dev.archdata.stc; - - fill_sbus_device(dev_dp, sdev); - - walk_children(dev_dp, sdev, sbus); - } - dev_dp = dev_dp->sibling; - } - - sbus_fixup_all_regs(sbus->devices); - - dvma_init(sbus); -} - -static int __init sbus_init(void) -{ - struct device_node *dp; - const char *sbus_name = "sbus"; - int num_sbus = 0; - - if (sbus_arch_preinit()) - return 0; - - if (sparc_cpu_model == sun4d) - sbus_name = "sbi"; - - for_each_node_by_name(dp, sbus_name) { - build_one_sbus(dp, num_sbus); - num_sbus++; - - } - - sbus_arch_postinit(); - - return 0; -} - -subsys_initcall(sbus_init); diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index bb43a138818..28e22acf87e 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -521,7 +521,8 @@ struct esp { struct completion *eh_reset; - struct sbus_dma *dma; + void *dma; + int dmarev; }; /* A front-end driver for the ESP chip should do the following in diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 90535089672..69d6ad862b6 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1,6 +1,6 @@ /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver. * - * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net) * * A lot of this driver was directly stolen from Erik H. Moe's PCI * Qlogic ISP driver. Mucho kudos to him for this code. @@ -25,12 +25,14 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/jiffies.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/byteorder.h> #include "qlogicpti.h" -#include <asm/sbus.h> #include <asm/dma.h> #include <asm/system.h> #include <asm/ptrace.h> @@ -157,7 +159,7 @@ static inline void set_sbus_cfg1(struct qlogicpti *qpti) * is a nop and the chip ends up using the smallest burst * size. -DaveM */ - if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) { + if (sbus_can_burst64() && (bursts & DMA_BURST64)) { val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64); } else #endif @@ -684,19 +686,19 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti) static int __devinit qpti_map_regs(struct qlogicpti *qpti) { - struct sbus_dev *sdev = qpti->sdev; + struct of_device *op = qpti->op; - qpti->qregs = sbus_ioremap(&sdev->resource[0], 0, - sdev->reg_addrs[0].reg_size, - "PTI Qlogic/ISP"); + qpti->qregs = of_ioremap(&op->resource[0], 0, + resource_size(&op->resource[0]), + "PTI Qlogic/ISP"); if (!qpti->qregs) { printk("PTI: Qlogic/ISP registers are unmappable\n"); return -1; } if (qpti->is_pti) { - qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096), - sizeof(unsigned char), - "PTI Qlogic/ISP statreg"); + qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096), + sizeof(unsigned char), + "PTI Qlogic/ISP statreg"); if (!qpti->sreg) { printk("PTI: Qlogic/ISP status register is unmappable\n"); return -1; @@ -707,9 +709,9 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti) static int __devinit qpti_register_irq(struct qlogicpti *qpti) { - struct sbus_dev *sdev = qpti->sdev; + struct of_device *op = qpti->op; - qpti->qhost->irq = qpti->irq = sdev->irqs[0]; + qpti->qhost->irq = qpti->irq = op->irqs[0]; /* We used to try various overly-clever things to * reduce the interrupt processing overhead on @@ -732,17 +734,19 @@ fail: static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) { - qpti->scsi_id = prom_getintdefault(qpti->prom_node, - "initiator-id", - -1); + struct of_device *op = qpti->op; + struct device_node *dp; + + dp = op->node; + + qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1); if (qpti->scsi_id == -1) - qpti->scsi_id = prom_getintdefault(qpti->prom_node, - "scsi-initiator-id", - -1); + qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", + -1); if (qpti->scsi_id == -1) qpti->scsi_id = - prom_getintdefault(qpti->sdev->bus->prom_node, - "scsi-initiator-id", 7); + of_getintprop_default(dp->parent, + "scsi-initiator-id", 7); qpti->qhost->this_id = qpti->scsi_id; qpti->qhost->max_sectors = 64; @@ -751,12 +755,11 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) static void qpti_get_bursts(struct qlogicpti *qpti) { - struct sbus_dev *sdev = qpti->sdev; + struct of_device *op = qpti->op; u8 bursts, bmask; - bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff); - bmask = prom_getintdefault(sdev->bus->prom_node, - "burst-sizes", 0xff); + bursts = of_getintprop_default(op->node, "burst-sizes", 0xff); + bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff); if (bmask != 0xff) bursts &= bmask; if (bursts == 0xff || @@ -785,25 +788,25 @@ static void qpti_get_clock(struct qlogicpti *qpti) */ static int __devinit qpti_map_queues(struct qlogicpti *qpti) { - struct sbus_dev *sdev = qpti->sdev; + struct of_device *op = qpti->op; #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - qpti->res_cpu = sbus_alloc_consistent(sdev, - QSIZE(RES_QUEUE_LEN), - &qpti->res_dvma); + qpti->res_cpu = dma_alloc_coherent(&op->dev, + QSIZE(RES_QUEUE_LEN), + &qpti->res_dvma, GFP_ATOMIC); if (qpti->res_cpu == NULL || qpti->res_dvma == 0) { printk("QPTI: Cannot map response queue.\n"); return -1; } - qpti->req_cpu = sbus_alloc_consistent(sdev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - &qpti->req_dvma); + qpti->req_cpu = dma_alloc_coherent(&op->dev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + &qpti->req_dvma, GFP_ATOMIC); if (qpti->req_cpu == NULL || qpti->req_dvma == 0) { - sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); + dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); printk("QPTI: Cannot map request queue.\n"); return -1; } @@ -875,8 +878,9 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, int sg_count; sg = scsi_sglist(Cmnd); - sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd), - Cmnd->sc_data_direction); + sg_count = dma_map_sg(&qpti->op->dev, sg, + scsi_sg_count(Cmnd), + Cmnd->sc_data_direction); ds = cmd->dataseg; cmd->segment_cnt = sg_count; @@ -1152,9 +1156,9 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) Cmnd->result = DID_ERROR << 16; if (scsi_bufflen(Cmnd)) - sbus_unmap_sg(qpti->sdev, - scsi_sglist(Cmnd), scsi_sg_count(Cmnd), - Cmnd->sc_data_direction); + dma_unmap_sg(&qpti->op->dev, + scsi_sglist(Cmnd), scsi_sg_count(Cmnd), + Cmnd->sc_data_direction); qpti->cmd_count[Cmnd->device->id]--; sbus_writew(out_ptr, qpti->qregs + MBOX5); @@ -1268,34 +1272,32 @@ static struct scsi_host_template qpti_template = { .use_clustering = ENABLE_CLUSTERING, }; -static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match) { - static int nqptis; - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; struct scsi_host_template *tpnt = match->data; + struct device_node *dp = op->node; struct Scsi_Host *host; struct qlogicpti *qpti; + static int nqptis; const char *fcode; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. */ - if (sdev->irqs[0] == 0) + if (op->irqs[0] == 0) return -ENODEV; host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti)); if (!host) return -ENOMEM; - qpti = (struct qlogicpti *) host->hostdata; + qpti = shost_priv(host); host->max_id = MAX_TARGETS; qpti->qhost = host; - qpti->sdev = sdev; + qpti->op = op; qpti->qpti_id = nqptis; - qpti->prom_node = sdev->prom_node; - strcpy(qpti->prom_name, sdev->ofdev.node->name); + strcpy(qpti->prom_name, op->node->name); qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp"); if (qpti_map_regs(qpti) < 0) @@ -1341,12 +1343,12 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi (qpti->ultra ? "Ultra" : "Fast"), (qpti->differential ? "differential" : "single ended")); - if (scsi_add_host(host, &dev->dev)) { + if (scsi_add_host(host, &op->dev)) { printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id); goto fail_unmap_queues; } - dev_set_drvdata(&sdev->ofdev.dev, qpti); + dev_set_drvdata(&op->dev, qpti); qpti_chain_add(qpti); @@ -1357,19 +1359,20 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi fail_unmap_queues: #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - sbus_free_consistent(qpti->sdev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - sbus_free_consistent(qpti->sdev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); + dma_free_coherent(&op->dev, + QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); + dma_free_coherent(&op->dev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + qpti->req_cpu, qpti->req_dvma); #undef QSIZE fail_unmap_regs: - sbus_iounmap(qpti->qregs, - qpti->sdev->reg_addrs[0].reg_size); + of_iounmap(&op->resource[0], qpti->qregs, + resource_size(&op->resource[0])); if (qpti->is_pti) - sbus_iounmap(qpti->sreg, sizeof(unsigned char)); + of_iounmap(&op->resource[0], qpti->sreg, + sizeof(unsigned char)); fail_free_irq: free_irq(qpti->irq, qpti); @@ -1380,9 +1383,9 @@ fail_unlink: return -ENODEV; } -static int __devexit qpti_sbus_remove(struct of_device *dev) +static int __devexit qpti_sbus_remove(struct of_device *op) { - struct qlogicpti *qpti = dev_get_drvdata(&dev->dev); + struct qlogicpti *qpti = dev_get_drvdata(&op->dev); qpti_chain_del(qpti); @@ -1395,24 +1398,25 @@ static int __devexit qpti_sbus_remove(struct of_device *dev) free_irq(qpti->irq, qpti); #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - sbus_free_consistent(qpti->sdev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - sbus_free_consistent(qpti->sdev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); + dma_free_coherent(&op->dev, + QSIZE(RES_QUEUE_LEN), + qpti->res_cpu, qpti->res_dvma); + dma_free_coherent(&op->dev, + QSIZE(QLOGICPTI_REQ_QUEUE_LEN), + qpti->req_cpu, qpti->req_dvma); #undef QSIZE - sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size); + of_iounmap(&op->resource[0], qpti->qregs, + resource_size(&op->resource[0])); if (qpti->is_pti) - sbus_iounmap(qpti->sreg, sizeof(unsigned char)); + of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char)); scsi_host_put(qpti->qhost); return 0; } -static struct of_device_id qpti_match[] = { +static const struct of_device_id qpti_match[] = { { .name = "ptisp", .data = &qpti_template, @@ -1442,7 +1446,7 @@ static struct of_platform_driver qpti_sbus_driver = { static int __init qpti_init(void) { - return of_register_driver(&qpti_sbus_driver, &sbus_bus_type); + return of_register_driver(&qpti_sbus_driver, &of_bus_type); } static void __exit qpti_exit(void) @@ -1453,7 +1457,7 @@ static void __exit qpti_exit(void) MODULE_DESCRIPTION("QlogicISP SBUS driver"); MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_LICENSE("GPL"); -MODULE_VERSION("2.0"); +MODULE_VERSION("2.1"); module_init(qpti_init); module_exit(qpti_exit); diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h index ef6da2df584..9c053bbaa87 100644 --- a/drivers/scsi/qlogicpti.h +++ b/drivers/scsi/qlogicpti.h @@ -342,7 +342,7 @@ struct qlogicpti { u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ long send_marker; /* must we send a marker? */ - struct sbus_dev *sdev; + struct of_device *op; unsigned long __pad; int cmd_count[MAX_TARGETS]; diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index f9cf7015136..3d73aad4bc8 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -1,6 +1,6 @@ /* sun_esp.c: ESP front-end for Sparc SBUS systems. * - * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/kernel.h> @@ -9,60 +9,70 @@ #include <linux/module.h> #include <linux/mm.h> #include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/dma.h> -#include <asm/sbus.h> - #include <scsi/scsi_host.h> #include "esp_scsi.h" #define DRV_MODULE_NAME "sun_esp" #define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "April 19, 2007" +#define DRV_VERSION "1.100" +#define DRV_MODULE_RELDATE "August 27, 2008" #define dma_read32(REG) \ sbus_readl(esp->dma_regs + (REG)) #define dma_write32(VAL, REG) \ sbus_writel((VAL), esp->dma_regs + (REG)) -static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev) -{ - struct sbus_dev *sdev = esp->dev; - struct sbus_dma *dma; +/* DVMA chip revisions */ +enum dvma_rev { + dvmarev0, + dvmaesc1, + dvmarev1, + dvmarev2, + dvmarev3, + dvmarevplus, + dvmahme +}; - if (dma_sdev != NULL) { - for_each_dvma(dma) { - if (dma->sdev == dma_sdev) - break; - } - } else { - for_each_dvma(dma) { - if (dma->sdev == NULL) - break; +static int __devinit esp_sbus_setup_dma(struct esp *esp, + struct of_device *dma_of) +{ + esp->dma = dma_of; - /* If bus + slot are the same and it has the - * correct OBP name, it's ours. - */ - if (sdev->bus == dma->sdev->bus && - sdev->slot == dma->sdev->slot && - (!strcmp(dma->sdev->prom_name, "dma") || - !strcmp(dma->sdev->prom_name, "espdma"))) - break; - } - } + esp->dma_regs = of_ioremap(&dma_of->resource[0], 0, + resource_size(&dma_of->resource[0]), + "espdma"); + if (!esp->dma_regs) + return -ENOMEM; - if (dma == NULL) { - printk(KERN_ERR PFX "[%s] Cannot find dma.\n", - sdev->ofdev.node->full_name); - return -ENODEV; + switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) { + case DMA_VERS0: + esp->dmarev = dvmarev0; + break; + case DMA_ESCV1: + esp->dmarev = dvmaesc1; + break; + case DMA_VERS1: + esp->dmarev = dvmarev1; + break; + case DMA_VERS2: + esp->dmarev = dvmarev2; + break; + case DMA_VERHME: + esp->dmarev = dvmahme; + break; + case DMA_VERSPLUS: + esp->dmarev = dvmarevplus; + break; } - esp->dma = dma; - esp->dma_regs = dma->regs; return 0; @@ -70,18 +80,18 @@ static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sde static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) { - struct sbus_dev *sdev = esp->dev; + struct of_device *op = esp->dev; struct resource *res; /* On HME, two reg sets exist, first is DVMA, * second is ESP registers. */ if (hme) - res = &sdev->resource[1]; + res = &op->resource[1]; else - res = &sdev->resource[0]; + res = &op->resource[0]; - esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); + esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); if (!esp->regs) return -ENOMEM; @@ -90,10 +100,11 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) static int __devinit esp_sbus_map_command_block(struct esp *esp) { - struct sbus_dev *sdev = esp->dev; + struct of_device *op = esp->dev; - esp->command_block = sbus_alloc_consistent(sdev, 16, - &esp->command_block_dma); + esp->command_block = dma_alloc_coherent(&op->dev, 16, + &esp->command_block_dma, + GFP_ATOMIC); if (!esp->command_block) return -ENOMEM; return 0; @@ -102,17 +113,18 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp) static int __devinit esp_sbus_register_irq(struct esp *esp) { struct Scsi_Host *host = esp->host; - struct sbus_dev *sdev = esp->dev; + struct of_device *op = esp->dev; - host->irq = sdev->irqs[0]; + host->irq = op->irqs[0]; return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); } -static void __devinit esp_get_scsi_id(struct esp *esp) +static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma) { - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; + struct of_device *op = esp->dev; + struct device_node *dp; + dp = op->node; esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); if (esp->scsi_id != 0xff) goto done; @@ -121,13 +133,7 @@ static void __devinit esp_get_scsi_id(struct esp *esp) if (esp->scsi_id != 0xff) goto done; - if (!sdev->bus) { - /* SUN4 */ - esp->scsi_id = 7; - goto done; - } - - esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node, + esp->scsi_id = of_getintprop_default(espdma->node, "scsi-initiator-id", 7); done: @@ -137,9 +143,10 @@ done: static void __devinit esp_get_differential(struct esp *esp) { - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; + struct of_device *op = esp->dev; + struct device_node *dp; + dp = op->node; if (of_find_property(dp, "differential", NULL)) esp->flags |= ESP_FLAG_DIFFERENTIAL; else @@ -148,43 +155,36 @@ static void __devinit esp_get_differential(struct esp *esp) static void __devinit esp_get_clock_params(struct esp *esp) { - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; - struct device_node *bus_dp; + struct of_device *op = esp->dev; + struct device_node *bus_dp, *dp; int fmhz; - bus_dp = NULL; - if (sdev != NULL && sdev->bus != NULL) - bus_dp = sdev->bus->ofdev.node; + dp = op->node; + bus_dp = dp->parent; fmhz = of_getintprop_default(dp, "clock-frequency", 0); if (fmhz == 0) - fmhz = (!bus_dp) ? 0 : - of_getintprop_default(bus_dp, "clock-frequency", 0); + fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0); esp->cfreq = fmhz; } -static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma) +static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of) { - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; - u8 bursts; + struct device_node *dma_dp = dma_of->node; + struct of_device *op = esp->dev; + struct device_node *dp; + u8 bursts, val; + dp = op->node; bursts = of_getintprop_default(dp, "burst-sizes", 0xff); - if (dma) { - struct device_node *dma_dp = dma->ofdev.node; - u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; - } + val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); + if (val != 0xff) + bursts &= val; - if (sdev->bus) { - u8 val = of_getintprop_default(sdev->bus->ofdev.node, - "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; - } + val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff); + if (val != 0xff) + bursts &= val; if (bursts == 0xff || (bursts & DMA_BURST16) == 0 || @@ -194,9 +194,9 @@ static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma) esp->bursts = bursts; } -static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma) +static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma) { - esp_get_scsi_id(esp); + esp_get_scsi_id(esp, espdma); esp_get_differential(esp); esp_get_clock_params(esp); esp_get_bursts(esp, espdma); @@ -215,25 +215,33 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, size_t sz, int dir) { - return sbus_map_single(esp->dev, buf, sz, dir); + struct of_device *op = esp->dev; + + return dma_map_single(&op->dev, buf, sz, dir); } static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - return sbus_map_sg(esp->dev, sg, num_sg, dir); + struct of_device *op = esp->dev; + + return dma_map_sg(&op->dev, sg, num_sg, dir); } static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, size_t sz, int dir) { - sbus_unmap_single(esp->dev, addr, sz, dir); + struct of_device *op = esp->dev; + + dma_unmap_single(&op->dev, addr, sz, dir); } static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - sbus_unmap_sg(esp->dev, sg, num_sg, dir); + struct of_device *op = esp->dev; + + dma_unmap_sg(&op->dev, sg, num_sg, dir); } static int sbus_esp_irq_pending(struct esp *esp) @@ -247,24 +255,26 @@ static void sbus_esp_reset_dma(struct esp *esp) { int can_do_burst16, can_do_burst32, can_do_burst64; int can_do_sbus64, lim; + struct of_device *op; u32 val; can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; can_do_burst64 = 0; can_do_sbus64 = 0; - if (sbus_can_dma_64bit(esp->dev)) + op = esp->dev; + if (sbus_can_dma_64bit()) can_do_sbus64 = 1; - if (sbus_can_burst64(esp->sdev)) + if (sbus_can_burst64()) can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; /* Put the DVMA into a known state. */ - if (esp->dma->revision != dvmahme) { + if (esp->dmarev != dvmahme) { val = dma_read32(DMA_CSR); dma_write32(val | DMA_RST_SCSI, DMA_CSR); dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); } - switch (esp->dma->revision) { + switch (esp->dmarev) { case dvmahme: dma_write32(DMA_RESET_FAS366, DMA_CSR); dma_write32(DMA_RST_SCSI, DMA_CSR); @@ -282,7 +292,7 @@ static void sbus_esp_reset_dma(struct esp *esp) if (can_do_sbus64) { esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; - sbus_set_sbus64(esp->dev, esp->bursts); + sbus_set_sbus64(&op->dev, esp->bursts); } lim = 1000; @@ -346,14 +356,14 @@ static void sbus_esp_dma_drain(struct esp *esp) u32 csr; int lim; - if (esp->dma->revision == dvmahme) + if (esp->dmarev == dvmahme) return; csr = dma_read32(DMA_CSR); if (!(csr & DMA_FIFO_ISDRAIN)) return; - if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1) + if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1) dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); lim = 1000; @@ -369,7 +379,7 @@ static void sbus_esp_dma_drain(struct esp *esp) static void sbus_esp_dma_invalidate(struct esp *esp) { - if (esp->dma->revision == dvmahme) { + if (esp->dmarev == dvmahme) { dma_write32(DMA_RST_SCSI, DMA_CSR); esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | @@ -440,7 +450,7 @@ static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, else csr &= ~DMA_ST_WRITE; dma_write32(csr, DMA_CSR); - if (esp->dma->revision == dvmaesc1) { + if (esp->dmarev == dvmaesc1) { u32 end = PAGE_ALIGN(addr + dma_count + 16U); dma_write32(end - addr, DMA_COUNT); } @@ -476,10 +486,8 @@ static const struct esp_driver_ops sbus_esp_ops = { .dma_error = sbus_esp_dma_error, }; -static int __devinit esp_sbus_probe_one(struct device *dev, - struct sbus_dev *esp_dev, - struct sbus_dev *espdma, - struct sbus_bus *sbus, +static int __devinit esp_sbus_probe_one(struct of_device *op, + struct of_device *espdma, int hme) { struct scsi_host_template *tpnt = &scsi_esp_template; @@ -497,13 +505,13 @@ static int __devinit esp_sbus_probe_one(struct device *dev, esp = shost_priv(host); esp->host = host; - esp->dev = esp_dev; + esp->dev = op; esp->ops = &sbus_esp_ops; if (hme) esp->flags |= ESP_FLAG_WIDE_CAPABLE; - err = esp_sbus_find_dma(esp, espdma); + err = esp_sbus_setup_dma(esp, espdma); if (err < 0) goto fail_unlink; @@ -525,15 +533,15 @@ static int __devinit esp_sbus_probe_one(struct device *dev, * come up with the reset bit set, so make sure that * is clear first. */ - if (esp->dma->revision == dvmaesc1) { + if (esp->dmarev == dvmaesc1) { u32 val = dma_read32(DMA_CSR); dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); } - dev_set_drvdata(&esp_dev->ofdev.dev, esp); + dev_set_drvdata(&op->dev, esp); - err = scsi_esp_register(esp, dev); + err = scsi_esp_register(esp, &op->dev); if (err) goto fail_free_irq; @@ -542,41 +550,46 @@ static int __devinit esp_sbus_probe_one(struct device *dev, fail_free_irq: free_irq(host->irq, esp); fail_unmap_command_block: - sbus_free_consistent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); + dma_free_coherent(&op->dev, 16, + esp->command_block, + esp->command_block_dma); fail_unmap_regs: - sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); + of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE); fail_unlink: scsi_host_put(host); fail: return err; } -static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; - struct sbus_dev *dma_sdev = NULL; + struct device_node *dma_node = NULL; + struct device_node *dp = op->node; + struct of_device *dma_of = NULL; int hme = 0; if (dp->parent && (!strcmp(dp->parent->name, "espdma") || !strcmp(dp->parent->name, "dma"))) - dma_sdev = sdev->parent; + dma_node = dp->parent; else if (!strcmp(dp->name, "SUNW,fas")) { - dma_sdev = sdev; + dma_node = op->node; hme = 1; } + if (dma_node) + dma_of = of_find_device_by_node(dma_node); + if (!dma_of) + return -ENODEV; - return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev, - sdev->bus, hme); + return esp_sbus_probe_one(op, dma_of, hme); } -static int __devexit esp_sbus_remove(struct of_device *dev) +static int __devexit esp_sbus_remove(struct of_device *op) { - struct esp *esp = dev_get_drvdata(&dev->dev); + struct esp *esp = dev_get_drvdata(&op->dev); + struct of_device *dma_of = esp->dma; unsigned int irq = esp->host->irq; + bool is_hme; u32 val; scsi_esp_unregister(esp); @@ -586,17 +599,25 @@ static int __devexit esp_sbus_remove(struct of_device *dev) dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); free_irq(irq, esp); - sbus_free_consistent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); - sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); + + is_hme = (esp->dmarev == dvmahme); + + dma_free_coherent(&op->dev, 16, + esp->command_block, + esp->command_block_dma); + of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs, + SBUS_ESP_REG_SIZE); + of_iounmap(&dma_of->resource[0], esp->dma_regs, + resource_size(&dma_of->resource[0])); scsi_host_put(esp->host); + dev_set_drvdata(&op->dev, NULL); + return 0; } -static struct of_device_id esp_match[] = { +static const struct of_device_id esp_match[] = { { .name = "SUNW,esp", }, @@ -619,7 +640,7 @@ static struct of_platform_driver esp_sbus_driver = { static int __init sunesp_init(void) { - return of_register_driver(&esp_sbus_driver, &sbus_bus_type); + return of_register_driver(&esp_sbus_driver, &of_bus_type); } static void __exit sunesp_exit(void) diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index e41766d0803..a94a2ab4b57 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev) return 0; } -static struct of_device_id hv_match[] = { +static const struct of_device_id hv_match[] = { { .name = "console", .compatible = "qcn", diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 29b4458abf7..0355efe115d 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op) return 0; } -static struct of_device_id sab_match[] = { +static const struct of_device_id sab_match[] = { { .name = "se", }, diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index a378464f929..a4dc79b1d7a 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op) return 0; } -static struct of_device_id su_match[] = { +static const struct of_device_id su_match[] = { { .name = "su", }, diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 3cb4c8aee13..45a299f3561 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op) return 0; } -static struct of_device_id zs_match[] = { +static const struct of_device_id zs_match[] = { { .name = "zs", }, diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index e721644bad7..1e35ba6f18e 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -372,7 +372,7 @@ static int __devexit bw2_remove(struct of_device *op) return 0; } -static struct of_device_id bw2_match[] = { +static const struct of_device_id bw2_match[] = { { .name = "bwtwo", }, diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index b17e7467177..a2d1882791a 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -589,7 +589,7 @@ static int __devexit cg14_remove(struct of_device *op) return 0; } -static struct of_device_id cg14_match[] = { +static const struct of_device_id cg14_match[] = { { .name = "cgfourteen", }, diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 3aa7b6cb026..99f87fb61d0 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -456,7 +456,7 @@ static int __devexit cg3_remove(struct of_device *op) return 0; } -static struct of_device_id cg3_match[] = { +static const struct of_device_id cg3_match[] = { { .name = "cgthree", }, diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 2f64bb3bd25..940ec04f0f1 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -34,10 +34,11 @@ static int cg6_blank(int, struct fb_info *); static void cg6_imageblit(struct fb_info *, const struct fb_image *); static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); +static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); static int cg6_sync(struct fb_info *); static int cg6_mmap(struct fb_info *, struct vm_area_struct *); static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long); -static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); +static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *); /* * Frame buffer operations @@ -47,6 +48,7 @@ static struct fb_ops cg6_ops = { .owner = THIS_MODULE, .fb_setcolreg = cg6_setcolreg, .fb_blank = cg6_blank, + .fb_pan_display = cg6_pan_display, .fb_fillrect = cg6_fillrect, .fb_copyarea = cg6_copyarea, .fb_imageblit = cg6_imageblit, @@ -161,6 +163,7 @@ static struct fb_ops cg6_ops = { #define CG6_THC_MISC_INT_ENAB (1 << 5) #define CG6_THC_MISC_INT (1 << 4) #define CG6_THC_MISC_INIT 0x9f +#define CG6_THC_CURSOFF ((65536-32) | ((65536-32) << 16)) /* The contents are unknown */ struct cg6_tec { @@ -280,6 +283,33 @@ static int cg6_sync(struct fb_info *info) return 0; } +static void cg6_switch_from_graph(struct cg6_par *par) +{ + struct cg6_thc __iomem *thc = par->thc; + unsigned long flags; + + spin_lock_irqsave(&par->lock, flags); + + /* Hide the cursor. */ + sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy); + + spin_unlock_irqrestore(&par->lock, flags); +} + +static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct cg6_par *par = (struct cg6_par *)info->par; + + /* We just use this to catch switches out of + * graphics mode. + */ + cg6_switch_from_graph(par); + + if (var->xoffset || var->yoffset || var->vmode) + return -EINVAL; + return 0; +} + /** * cg6_fillrect - Draws a rectangle on the screen. * @@ -643,9 +673,13 @@ static void __devinit cg6_chip_init(struct fb_info *info) struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_tec __iomem *tec = par->tec; struct cg6_fbc __iomem *fbc = par->fbc; + struct cg6_thc __iomem *thc = par->thc; u32 rev, conf, mode; int i; + /* Hide the cursor. */ + sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy); + /* Turn off stuff in the Transform Engine. */ sbus_writel(0, &tec->tec_matrix); sbus_writel(0, &tec->tec_clip); @@ -814,7 +848,7 @@ static int __devexit cg6_remove(struct of_device *op) return 0; } -static struct of_device_id cg6_match[] = { +static const struct of_device_id cg6_match[] = { { .name = "cgsix", }, diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 7992b13ee68..9dbb9646081 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -1042,7 +1042,7 @@ static int __devexit ffb_remove(struct of_device *op) return 0; } -static struct of_device_id ffb_match[] = { +static const struct of_device_id ffb_match[] = { { .name = "SUNW,ffb", }, diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 13fea61d6ae..7c7e8c2da9d 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -33,6 +33,7 @@ static int leo_blank(int, struct fb_info *); static int leo_mmap(struct fb_info *, struct vm_area_struct *); static int leo_ioctl(struct fb_info *, unsigned int, unsigned long); +static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); /* * Frame buffer operations @@ -42,6 +43,7 @@ static struct fb_ops leo_ops = { .owner = THIS_MODULE, .fb_setcolreg = leo_setcolreg, .fb_blank = leo_blank, + .fb_pan_display = leo_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -206,6 +208,60 @@ static void leo_wait(struct leo_lx_krn __iomem *lx_krn) return; } +static void leo_switch_from_graph(struct fb_info *info) +{ + struct leo_par *par = (struct leo_par *) info->par; + struct leo_ld_ss0 __iomem *ss = par->ld_ss0; + struct leo_cursor __iomem *cursor = par->cursor; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&par->lock, flags); + + par->extent = ((info->var.xres - 1) | + ((info->var.yres - 1) << 16)); + + sbus_writel(0xffffffff, &ss->wid); + sbus_writel(0xffff, &ss->wmask); + sbus_writel(0, &ss->vclipmin); + sbus_writel(par->extent, &ss->vclipmax); + sbus_writel(0, &ss->fg); + sbus_writel(0xff000000, &ss->planemask); + sbus_writel(0x310850, &ss->rop); + sbus_writel(0, &ss->widclip); + sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), + &par->lc_ss0_usr->extent); + sbus_writel(4, &par->lc_ss0_usr->addrspace); + sbus_writel(0x80000000, &par->lc_ss0_usr->fill); + sbus_writel(0, &par->lc_ss0_usr->fontt); + do { + val = sbus_readl(&par->lc_ss0_usr->csr); + } while (val & 0x20000000); + + /* setup screen buffer for cfb_* functions */ + sbus_writel(1, &ss->wid); + sbus_writel(0x00ffffff, &ss->planemask); + sbus_writel(0x310b90, &ss->rop); + sbus_writel(0, &par->lc_ss0_usr->addrspace); + + /* hide cursor */ + sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc); + + spin_unlock_irqrestore(&par->lock, flags); +} + +static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + /* We just use this to catch switches out of + * graphics mode. + */ + leo_switch_from_graph(info); + + if (var->xoffset || var->yoffset || var->vmode) + return -EINVAL; + return 0; +} + /** * leo_setcolreg - Optional function. Sets a color register. * @regno: boolean, 0 copy local, 1 get_user() function @@ -454,44 +510,6 @@ static void leo_init_wids(struct fb_info *info) leo_wid_put(info, &wl); } -static void leo_switch_from_graph(struct fb_info *info) -{ - struct leo_par *par = (struct leo_par *) info->par; - struct leo_ld_ss0 __iomem *ss = par->ld_ss0; - unsigned long flags; - u32 val; - - spin_lock_irqsave(&par->lock, flags); - - par->extent = ((info->var.xres - 1) | - ((info->var.yres - 1) << 16)); - - sbus_writel(0xffffffff, &ss->wid); - sbus_writel(0xffff, &ss->wmask); - sbus_writel(0, &ss->vclipmin); - sbus_writel(par->extent, &ss->vclipmax); - sbus_writel(0, &ss->fg); - sbus_writel(0xff000000, &ss->planemask); - sbus_writel(0x310850, &ss->rop); - sbus_writel(0, &ss->widclip); - sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), - &par->lc_ss0_usr->extent); - sbus_writel(4, &par->lc_ss0_usr->addrspace); - sbus_writel(0x80000000, &par->lc_ss0_usr->fill); - sbus_writel(0, &par->lc_ss0_usr->fontt); - do { - val = sbus_readl(&par->lc_ss0_usr->csr); - } while (val & 0x20000000); - - /* setup screen buffer for cfb_* functions */ - sbus_writel(1, &ss->wid); - sbus_writel(0x00ffffff, &ss->planemask); - sbus_writel(0x310b90, &ss->rop); - sbus_writel(0, &par->lc_ss0_usr->addrspace); - - spin_unlock_irqrestore(&par->lock, flags); -} - static void leo_init_hw(struct fb_info *info) { struct leo_par *par = (struct leo_par *) info->par; @@ -641,7 +659,7 @@ static int __devexit leo_remove(struct of_device *op) return 0; } -static struct of_device_id leo_match[] = { +static const struct of_device_id leo_match[] = { { .name = "SUNW,leo", }, diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 9e903454ffc..7000f2cd585 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -349,7 +349,7 @@ static int __devexit p9100_remove(struct of_device *op) return 0; } -static struct of_device_id p9100_match[] = { +static const struct of_device_id p9100_match[] = { { .name = "p9100", }, diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 2a03f78bbb0..643afbfe827 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -505,7 +505,7 @@ static int __devexit tcx_remove(struct of_device *op) return 0; } -static struct of_device_id tcx_match[] = { +static const struct of_device_id tcx_match[] = { { .name = "SUNW,tcx", }, diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e0ef123fbde..6702d2ef043 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -123,6 +123,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o # SPARC64 Architecture +obj-$(CONFIG_WATCHDOG_RIO) += riowd.o +obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o + # XTENSA Architecture # Architecture Independant diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c new file mode 100644 index 00000000000..084dfe9cecf --- /dev/null +++ b/drivers/watchdog/cpwd.c @@ -0,0 +1,695 @@ +/* cpwd.c - driver implementation for hardware watchdog + * timers found on Sun Microsystems CP1400 and CP1500 boards. + * + * This device supports both the generic Linux watchdog + * interface and Solaris-compatible ioctls as best it is + * able. + * + * NOTE: CP1400 systems appear to have a defective intr_mask + * register on the PLD, preventing the disabling of + * timer interrupts. We use a timer to periodically + * reset 'stopped' watchdogs on affected platforms. + * + * Copyright (c) 2000 Eric Brower (ebrower@usa.net) + * Copyright (C) 2008 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/major.h> +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timer.h> +#include <linux/smp_lock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include <asm/watchdog.h> + +#define DRIVER_NAME "cpwd" +#define PFX DRIVER_NAME ": " + +#define WD_OBPNAME "watchdog" +#define WD_BADMODEL "SUNW,501-5336" +#define WD_BTIMEOUT (jiffies + (HZ * 1000)) +#define WD_BLIMIT 0xFFFF + +#define WD0_MINOR 212 +#define WD1_MINOR 213 +#define WD2_MINOR 214 + +/* Internal driver definitions. */ +#define WD0_ID 0 +#define WD1_ID 1 +#define WD2_ID 2 +#define WD_NUMDEVS 3 + +#define WD_INTR_OFF 0 +#define WD_INTR_ON 1 + +#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ +#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ +#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ + +/* Register value definitions + */ +#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ +#define WD1_INTR_MASK 0x02 +#define WD2_INTR_MASK 0x04 + +#define WD_S_RUNNING 0x01 /* Watchdog device status running */ +#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ + +struct cpwd { + void __iomem *regs; + spinlock_t lock; + + unsigned int irq; + + unsigned long timeout; + bool enabled; + bool reboot; + bool broken; + bool initialized; + + struct { + struct miscdevice misc; + void __iomem *regs; + u8 intr_mask; + u8 runstatus; + u16 timeout; + } devs[WD_NUMDEVS]; +}; + +static struct cpwd *cpwd_device; + +/* Sun uses Altera PLD EPF8820ATC144-4 + * providing three hardware watchdogs: + * + * 1) RIC - sends an interrupt when triggered + * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU + * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board + * + *** Timer register block definition (struct wd_timer_regblk) + * + * dcntr and limit registers (halfword access): + * ------------------- + * | 15 | ...| 1 | 0 | + * ------------------- + * |- counter val -| + * ------------------- + * dcntr - Current 16-bit downcounter value. + * When downcounter reaches '0' watchdog expires. + * Reading this register resets downcounter with 'limit' value. + * limit - 16-bit countdown value in 1/10th second increments. + * Writing this register begins countdown with input value. + * Reading from this register does not affect counter. + * NOTES: After watchdog reset, dcntr and limit contain '1' + * + * status register (byte access): + * --------------------------- + * | 7 | ... | 2 | 1 | 0 | + * --------------+------------ + * |- UNUSED -| EXP | RUN | + * --------------------------- + * status- Bit 0 - Watchdog is running + * Bit 1 - Watchdog has expired + * + *** PLD register block definition (struct wd_pld_regblk) + * + * intr_mask register (byte access): + * --------------------------------- + * | 7 | ... | 3 | 2 | 1 | 0 | + * +-------------+------------------ + * |- UNUSED -| WD3 | WD2 | WD1 | + * --------------------------------- + * WD3 - 1 == Interrupt disabled for watchdog 3 + * WD2 - 1 == Interrupt disabled for watchdog 2 + * WD1 - 1 == Interrupt disabled for watchdog 1 + * + * pld_status register (byte access): + * UNKNOWN, MAGICAL MYSTERY REGISTER + * + */ +#define WD_TIMER_REGSZ 16 +#define WD0_OFF 0 +#define WD1_OFF (WD_TIMER_REGSZ * 1) +#define WD2_OFF (WD_TIMER_REGSZ * 2) +#define PLD_OFF (WD_TIMER_REGSZ * 3) + +#define WD_DCNTR 0x00 +#define WD_LIMIT 0x04 +#define WD_STATUS 0x08 + +#define PLD_IMASK (PLD_OFF + 0x00) +#define PLD_STATUS (PLD_OFF + 0x04) + +static struct timer_list cpwd_timer; + +static int wd0_timeout = 0; +static int wd1_timeout = 0; +static int wd2_timeout = 0; + +module_param (wd0_timeout, int, 0); +MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); +module_param (wd1_timeout, int, 0); +MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); +module_param (wd2_timeout, int, 0); +MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); + +MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); +MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("watchdog"); + +static void cpwd_writew(u16 val, void __iomem *addr) +{ + writew(cpu_to_le16(val), addr); +} +static u16 cpwd_readw(void __iomem *addr) +{ + u16 val = readw(addr); + + return le16_to_cpu(val); +} + +static void cpwd_writeb(u8 val, void __iomem *addr) +{ + writeb(val, addr); +} + +static u8 cpwd_readb(void __iomem *addr) +{ + return readb(addr); +} + +/* Enable or disable watchdog interrupts + * Because of the CP1400 defect this should only be + * called during initialzation or by wd_[start|stop]timer() + * + * index - sub-device index, or -1 for 'all' + * enable - non-zero to enable interrupts, zero to disable + */ +static void cpwd_toggleintr(struct cpwd *p, int index, int enable) +{ + unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); + unsigned char setregs = + (index == -1) ? + (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : + (p->devs[index].intr_mask); + + if (enable == WD_INTR_ON) + curregs &= ~setregs; + else + curregs |= setregs; + + cpwd_writeb(curregs, p->regs + PLD_IMASK); +} + +/* Restarts timer with maximum limit value and + * does not unset 'brokenstop' value. + */ +static void cpwd_resetbrokentimer(struct cpwd *p, int index) +{ + cpwd_toggleintr(p, index, WD_INTR_ON); + cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT); +} + +/* Timer method called to reset stopped watchdogs-- + * because of the PLD bug on CP1400, we cannot mask + * interrupts within the PLD so me must continually + * reset the timers ad infinitum. + */ +static void cpwd_brokentimer(unsigned long data) +{ + struct cpwd *p = (struct cpwd *) data; + int id, tripped = 0; + + /* kill a running timer instance, in case we + * were called directly instead of by kernel timer + */ + if (timer_pending(&cpwd_timer)) + del_timer(&cpwd_timer); + + for (id = 0; id < WD_NUMDEVS; id++) { + if (p->devs[id].runstatus & WD_STAT_BSTOP) { + ++tripped; + cpwd_resetbrokentimer(p, id); + } + } + + if (tripped) { + /* there is at least one timer brokenstopped-- reschedule */ + cpwd_timer.expires = WD_BTIMEOUT; + add_timer(&cpwd_timer); + } +} + +/* Reset countdown timer with 'limit' value and continue countdown. + * This will not start a stopped timer. + */ +static void cpwd_pingtimer(struct cpwd *p, int index) +{ + if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) + cpwd_readw(p->devs[index].regs + WD_DCNTR); +} + +/* Stop a running watchdog timer-- the timer actually keeps + * running, but the interrupt is masked so that no action is + * taken upon expiration. + */ +static void cpwd_stoptimer(struct cpwd *p, int index) +{ + if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) { + cpwd_toggleintr(p, index, WD_INTR_OFF); + + if (p->broken) { + p->devs[index].runstatus |= WD_STAT_BSTOP; + cpwd_brokentimer((unsigned long) p); + } + } +} + +/* Start a watchdog timer with the specified limit value + * If the watchdog is running, it will be restarted with + * the provided limit value. + * + * This function will enable interrupts on the specified + * watchdog. + */ +static void cpwd_starttimer(struct cpwd *p, int index) +{ + if (p->broken) + p->devs[index].runstatus &= ~WD_STAT_BSTOP; + + p->devs[index].runstatus &= ~WD_STAT_SVCD; + + cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT); + cpwd_toggleintr(p, index, WD_INTR_ON); +} + +static int cpwd_getstatus(struct cpwd *p, int index) +{ + unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS); + unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK); + unsigned char ret = WD_STOPPED; + + /* determine STOPPED */ + if (!stat) + return ret; + + /* determine EXPIRED vs FREERUN vs RUNNING */ + else if (WD_S_EXPIRED & stat) { + ret = WD_EXPIRED; + } else if(WD_S_RUNNING & stat) { + if (intr & p->devs[index].intr_mask) { + ret = WD_FREERUN; + } else { + /* Fudge WD_EXPIRED status for defective CP1400-- + * IF timer is running + * AND brokenstop is set + * AND an interrupt has been serviced + * we are WD_EXPIRED. + * + * IF timer is running + * AND brokenstop is set + * AND no interrupt has been serviced + * we are WD_FREERUN. + */ + if (p->broken && + (p->devs[index].runstatus & WD_STAT_BSTOP)) { + if (p->devs[index].runstatus & WD_STAT_SVCD) { + ret = WD_EXPIRED; + } else { + /* we could as well pretend we are expired */ + ret = WD_FREERUN; + } + } else { + ret = WD_RUNNING; + } + } + } + + /* determine SERVICED */ + if (p->devs[index].runstatus & WD_STAT_SVCD) + ret |= WD_SERVICED; + + return(ret); +} + +static irqreturn_t cpwd_interrupt(int irq, void *dev_id) +{ + struct cpwd *p = dev_id; + + /* Only WD0 will interrupt-- others are NMI and we won't + * see them here.... + */ + spin_lock_irq(&p->lock); + + cpwd_stoptimer(p, WD0_ID); + p->devs[WD0_ID].runstatus |= WD_STAT_SVCD; + + spin_unlock_irq(&p->lock); + + return IRQ_HANDLED; +} + +static int cpwd_open(struct inode *inode, struct file *f) +{ + struct cpwd *p = cpwd_device; + + lock_kernel(); + switch(iminor(inode)) { + case WD0_MINOR: + case WD1_MINOR: + case WD2_MINOR: + break; + + default: + unlock_kernel(); + return -ENODEV; + } + + /* Register IRQ on first open of device */ + if (!p->initialized) { + if (request_irq(p->irq, &cpwd_interrupt, + IRQF_SHARED, DRIVER_NAME, p)) { + printk(KERN_ERR PFX "Cannot register IRQ %d\n", + p->irq); + unlock_kernel(); + return -EBUSY; + } + p->initialized = true; + } + + unlock_kernel(); + + return nonseekable_open(inode, f); +} + +static int cpwd_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static int cpwd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info info = { + .options = WDIOF_SETTIMEOUT, + .firmware_version = 1, + .identity = DRIVER_NAME, + }; + void __user *argp = (void __user *)arg; + int index = iminor(inode) - WD0_MINOR; + struct cpwd *p = cpwd_device; + int setopt = 0; + + switch (cmd) { + /* Generic Linux IOCTLs */ + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &info, sizeof(struct watchdog_info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(0, (int __user *)argp)) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + cpwd_pingtimer(p, index); + break; + + case WDIOC_SETOPTIONS: + if (copy_from_user(&setopt, argp, sizeof(unsigned int))) + return -EFAULT; + + if (setopt & WDIOS_DISABLECARD) { + if (p->enabled) + return -EINVAL; + cpwd_stoptimer(p, index); + } else if (setopt & WDIOS_ENABLECARD) { + cpwd_starttimer(p, index); + } else { + return -EINVAL; + } + break; + + /* Solaris-compatible IOCTLs */ + case WIOCGSTAT: + setopt = cpwd_getstatus(p, index); + if (copy_to_user(argp, &setopt, sizeof(unsigned int))) + return -EFAULT; + break; + + case WIOCSTART: + cpwd_starttimer(p, index); + break; + + case WIOCSTOP: + if (p->enabled) + return(-EINVAL); + + cpwd_stoptimer(p, index); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rval = -ENOIOCTLCMD; + + switch (cmd) { + /* solaris ioctls are specific to this driver */ + case WIOCSTART: + case WIOCSTOP: + case WIOCGSTAT: + lock_kernel(); + rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); + unlock_kernel(); + break; + + /* everything else is handled by the generic compat layer */ + default: + break; + } + + return rval; +} + +static ssize_t cpwd_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_path.dentry->d_inode; + struct cpwd *p = cpwd_device; + int index = iminor(inode); + + if (count) { + cpwd_pingtimer(p, index); + return 1; + } + + return 0; +} + +static ssize_t cpwd_read(struct file * file, char __user *buffer, + size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static const struct file_operations cpwd_fops = { + .owner = THIS_MODULE, + .ioctl = cpwd_ioctl, + .compat_ioctl = cpwd_compat_ioctl, + .open = cpwd_open, + .write = cpwd_write, + .read = cpwd_read, + .release = cpwd_release, +}; + +static int __devinit cpwd_probe(struct of_device *op, + const struct of_device_id *match) +{ + struct device_node *options; + const char *str_prop; + const void *prop_val; + int i, err = -EINVAL; + struct cpwd *p; + + if (cpwd_device) + return -EINVAL; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + err = -ENOMEM; + if (!p) { + printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n"); + goto out; + } + + p->irq = op->irqs[0]; + + spin_lock_init(&p->lock); + + p->regs = of_ioremap(&op->resource[0], 0, + 4 * WD_TIMER_REGSZ, DRIVER_NAME); + if (!p->regs) { + printk(KERN_ERR PFX "Unable to map registers.\n"); + goto out_free; + } + + options = of_find_node_by_path("/options"); + err = -ENODEV; + if (!options) { + printk(KERN_ERR PFX "Unable to find /options node.\n"); + goto out_iounmap; + } + + prop_val = of_get_property(options, "watchdog-enable?", NULL); + p->enabled = (prop_val ? true : false); + + prop_val = of_get_property(options, "watchdog-reboot?", NULL); + p->reboot = (prop_val ? true : false); + + str_prop = of_get_property(options, "watchdog-timeout", NULL); + if (str_prop) + p->timeout = simple_strtoul(str_prop, NULL, 10); + + /* CP1400s seem to have broken PLD implementations-- the + * interrupt_mask register cannot be written, so no timer + * interrupts can be masked within the PLD. + */ + str_prop = of_get_property(op->node, "model", NULL); + p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL)); + + if (!p->enabled) + cpwd_toggleintr(p, -1, WD_INTR_OFF); + + for (i = 0; i < WD_NUMDEVS; i++) { + static const char *cpwd_names[] = { "RIC", "XIR", "POR" }; + static int *parms[] = { &wd0_timeout, + &wd1_timeout, + &wd2_timeout }; + struct miscdevice *mp = &p->devs[i].misc; + + mp->minor = WD0_MINOR + i; + mp->name = cpwd_names[i]; + mp->fops = &cpwd_fops; + + p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ); + p->devs[i].intr_mask = (WD0_INTR_MASK << i); + p->devs[i].runstatus &= ~WD_STAT_BSTOP; + p->devs[i].runstatus |= WD_STAT_INIT; + p->devs[i].timeout = p->timeout; + if (*parms[i]) + p->devs[i].timeout = *parms[i]; + + err = misc_register(&p->devs[i].misc); + if (err) { + printk(KERN_ERR "Could not register misc device for " + "dev %d\n", i); + goto out_unregister; + } + } + + if (p->broken) { + init_timer(&cpwd_timer); + cpwd_timer.function = cpwd_brokentimer; + cpwd_timer.data = (unsigned long) p; + cpwd_timer.expires = WD_BTIMEOUT; + + printk(KERN_INFO PFX "PLD defect workaround enabled for " + "model " WD_BADMODEL ".\n"); + } + + dev_set_drvdata(&op->dev, p); + cpwd_device = p; + err = 0; + +out: + return err; + +out_unregister: + for (i--; i >= 0; i--) + misc_deregister(&p->devs[i].misc); + +out_iounmap: + of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); + +out_free: + kfree(p); + goto out; +} + +static int __devexit cpwd_remove(struct of_device *op) +{ + struct cpwd *p = dev_get_drvdata(&op->dev); + int i; + + for (i = 0; i < 4; i++) { + misc_deregister(&p->devs[i].misc); + + if (!p->enabled) { + cpwd_stoptimer(p, i); + if (p->devs[i].runstatus & WD_STAT_BSTOP) + cpwd_resetbrokentimer(p, i); + } + } + + if (p->broken) + del_timer_sync(&cpwd_timer); + + if (p->initialized) + free_irq(p->irq, p); + + of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); + kfree(p); + + cpwd_device = NULL; + + return 0; +} + +static const struct of_device_id cpwd_match[] = { + { + .name = "watchdog", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cpwd_match); + +static struct of_platform_driver cpwd_driver = { + .name = DRIVER_NAME, + .match_table = cpwd_match, + .probe = cpwd_probe, + .remove = __devexit_p(cpwd_remove), +}; + +static int __init cpwd_init(void) +{ + return of_register_driver(&cpwd_driver, &of_bus_type); +} + +static void __exit cpwd_exit(void) +{ + of_unregister_driver(&cpwd_driver); +} + +module_init(cpwd_init); +module_exit(cpwd_exit); diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/watchdog/riowd.c index 88c0fc6395e..09cb1833ea2 100644 --- a/drivers/sbus/char/riowatchdog.c +++ b/drivers/watchdog/riowd.c @@ -1,7 +1,6 @@ -/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $ - * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO +/* riowd.c - driver for hw watchdog inside Super I/O of RIO * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/kernel.h> @@ -12,14 +11,13 @@ #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/smp_lock.h> +#include <linux/watchdog.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/io.h> -#include <asm/ebus.h> -#include <asm/bbc.h> -#include <asm/oplib.h> #include <asm/uaccess.h> -#include <asm/watchdog.h> /* RIO uses the NatSemi Super I/O power management logical device * as its' watchdog. @@ -45,74 +43,35 @@ * The watchdog device generates no interrupts. */ -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); MODULE_SUPPORTED_DEVICE("watchdog"); MODULE_LICENSE("GPL"); -#define RIOWD_NAME "pmc" -#define RIOWD_MINOR 215 +#define DRIVER_NAME "riowd" +#define PFX DRIVER_NAME ": " -static DEFINE_SPINLOCK(riowd_lock); +struct riowd { + void __iomem *regs; + spinlock_t lock; +}; + +static struct riowd *riowd_device; -static void __iomem *bbc_regs; -static void __iomem *riowd_regs; #define WDTO_INDEX 0x05 static int riowd_timeout = 1; /* in minutes */ module_param(riowd_timeout, int, 0); MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); -#if 0 /* Currently unused. */ -static u8 riowd_readreg(int index) +static void riowd_writereg(struct riowd *p, u8 val, int index) { unsigned long flags; - u8 ret; - spin_lock_irqsave(&riowd_lock, flags); - writeb(index, riowd_regs + 0); - ret = readb(riowd_regs + 1); - spin_unlock_irqrestore(&riowd_lock, flags); - - return ret; -} -#endif - -static void riowd_writereg(u8 val, int index) -{ - unsigned long flags; - - spin_lock_irqsave(&riowd_lock, flags); - writeb(index, riowd_regs + 0); - writeb(val, riowd_regs + 1); - spin_unlock_irqrestore(&riowd_lock, flags); -} - -static void riowd_pingtimer(void) -{ - riowd_writereg(riowd_timeout, WDTO_INDEX); -} - -static void riowd_stoptimer(void) -{ - u8 val; - - riowd_writereg(0, WDTO_INDEX); - - val = readb(bbc_regs + BBC_WDACTION); - val &= ~BBC_WDACTION_RST; - writeb(val, bbc_regs + BBC_WDACTION); -} - -static void riowd_starttimer(void) -{ - u8 val; - - riowd_writereg(riowd_timeout, WDTO_INDEX); - - val = readb(bbc_regs + BBC_WDACTION); - val |= BBC_WDACTION_RST; - writeb(val, bbc_regs + BBC_WDACTION); + spin_lock_irqsave(&p->lock, flags); + writeb(index, p->regs + 0); + writeb(val, p->regs + 1); + spin_unlock_irqrestore(&p->lock, flags); } static int riowd_open(struct inode *inode, struct file *filp) @@ -131,9 +90,12 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { static struct watchdog_info info = { - WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" + .options = WDIOF_SETTIMEOUT, + .firmware_version = 1, + .identity = DRIVER_NAME, }; void __user *argp = (void __user *)arg; + struct riowd *p = riowd_device; unsigned int options; int new_margin; @@ -150,7 +112,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, break; case WDIOC_KEEPALIVE: - riowd_pingtimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); break; case WDIOC_SETOPTIONS: @@ -158,9 +120,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, return -EFAULT; if (options & WDIOS_DISABLECARD) - riowd_stoptimer(); + riowd_writereg(p, 0, WDTO_INDEX); else if (options & WDIOS_ENABLECARD) - riowd_starttimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); else return -EINVAL; @@ -170,9 +132,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, if (get_user(new_margin, (int __user *)argp)) return -EFAULT; if ((new_margin < 60) || (new_margin > (255 * 60))) - return -EINVAL; + return -EINVAL; riowd_timeout = (new_margin + 59) / 60; - riowd_pingtimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); /* Fall */ case WDIOC_GETTIMEOUT: @@ -187,8 +149,10 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + struct riowd *p = riowd_device; + if (count) { - riowd_pingtimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); return 1; } @@ -197,99 +161,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou static const struct file_operations riowd_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .ioctl = riowd_ioctl, .open = riowd_open, .write = riowd_write, .release = riowd_release, }; -static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops }; +static struct miscdevice riowd_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &riowd_fops +}; -static int __init riowd_bbc_init(void) +static int __devinit riowd_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - u8 val; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->ofdev.node->name, "bbc")) - goto found_bbc; - } - } + struct riowd *p; + int err = -EINVAL; -found_bbc: - if (!edev) - return -ENODEV; - bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE); - if (!bbc_regs) - return -ENODEV; + if (riowd_device) + goto out; - /* Turn it off. */ - val = readb(bbc_regs + BBC_WDACTION); - val &= ~BBC_WDACTION_RST; - writeb(val, bbc_regs + BBC_WDACTION); + err = -ENOMEM; + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto out; - return 0; -} + spin_lock_init(&p->lock); -static int __init riowd_init(void) -{ - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) - goto ebus_done; - } + p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME); + if (!p->regs) { + printk(KERN_ERR PFX "Cannot map registers.\n"); + goto out_free; } -ebus_done: - if (!edev) - goto fail; - - riowd_regs = ioremap(edev->resource[0].start, 2); - if (riowd_regs == NULL) { - printk(KERN_ERR "pmc: Cannot map registers.\n"); - return -ENODEV; + err = misc_register(&riowd_miscdev); + if (err) { + printk(KERN_ERR PFX "Cannot register watchdog misc device.\n"); + goto out_iounmap; } - if (riowd_bbc_init()) { - printk(KERN_ERR "pmc: Failure initializing BBC config.\n"); - goto fail; - } + printk(KERN_INFO PFX "Hardware watchdog [%i minutes], " + "regs at %p\n", riowd_timeout, p->regs); - if (misc_register(&riowd_miscdev)) { - printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n"); - goto fail; - } + dev_set_drvdata(&op->dev, p); + riowd_device = p; + err = 0; - printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " - "regs at %p\n", riowd_timeout, riowd_regs); +out_iounmap: + of_iounmap(&op->resource[0], p->regs, 2); - return 0; +out_free: + kfree(p); -fail: - if (riowd_regs) { - iounmap(riowd_regs); - riowd_regs = NULL; - } - if (bbc_regs) { - iounmap(bbc_regs); - bbc_regs = NULL; - } - return -ENODEV; +out: + return err; } -static void __exit riowd_cleanup(void) +static int __devexit riowd_remove(struct of_device *op) { + struct riowd *p = dev_get_drvdata(&op->dev); + misc_deregister(&riowd_miscdev); - iounmap(riowd_regs); - riowd_regs = NULL; - iounmap(bbc_regs); - bbc_regs = NULL; + of_iounmap(&op->resource[0], p->regs, 2); + kfree(p); + + return 0; +} + +static const struct of_device_id riowd_match[] = { + { + .name = "pmc", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, riowd_match); + +static struct of_platform_driver riowd_driver = { + .name = DRIVER_NAME, + .match_table = riowd_match, + .probe = riowd_probe, + .remove = __devexit_p(riowd_remove), +}; + +static int __init riowd_init(void) +{ + return of_register_driver(&riowd_driver, &of_bus_type); +} + +static void __exit riowd_exit(void) +{ + of_unregister_driver(&riowd_driver); } module_init(riowd_init); -module_exit(riowd_cleanup); +module_exit(riowd_exit); |