📄 locomo.c
字号:
set_irq_flags(IRQ_LOCOMO_LT_BASE, IRQF_VALID | IRQF_PROBE); set_irq_chip(IRQ_LOCOMO_SPI_BASE, &locomo_chip); set_irq_chipdata(IRQ_LOCOMO_SPI_BASE, irqbase); set_irq_chained_handler(IRQ_LOCOMO_SPI_BASE, locomo_spi_handler); set_irq_flags(IRQ_LOCOMO_SPI_BASE, IRQF_VALID | IRQF_PROBE); /* install handlers for IRQ_LOCOMO_KEY_BASE generated interrupts */ set_irq_chip(LOCOMO_IRQ_KEY_START, &locomo_key_chip); set_irq_chipdata(LOCOMO_IRQ_KEY_START, irqbase); set_irq_handler(LOCOMO_IRQ_KEY_START, do_edge_IRQ); set_irq_flags(LOCOMO_IRQ_KEY_START, IRQF_VALID | IRQF_PROBE); /* install handlers for IRQ_LOCOMO_GPIO_BASE generated interrupts */ for (irq = LOCOMO_IRQ_GPIO_START; irq < LOCOMO_IRQ_GPIO_START + 16; irq++) { set_irq_chip(irq, &locomo_gpio_chip); set_irq_chipdata(irq, irqbase); set_irq_handler(irq, do_edge_IRQ); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } /* install handlers for IRQ_LOCOMO_LT_BASE generated interrupts */ set_irq_chip(LOCOMO_IRQ_LT_START, &locomo_lt_chip); set_irq_chipdata(LOCOMO_IRQ_LT_START, irqbase); set_irq_handler(LOCOMO_IRQ_LT_START, do_edge_IRQ); set_irq_flags(LOCOMO_IRQ_LT_START, IRQF_VALID | IRQF_PROBE); /* install handlers for IRQ_LOCOMO_SPI_BASE generated interrupts */ for (irq = LOCOMO_IRQ_SPI_START; irq < LOCOMO_IRQ_SPI_START + 3; irq++) { set_irq_chip(irq, &locomo_spi_chip); set_irq_chipdata(irq, irqbase); set_irq_handler(irq, do_edge_IRQ); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); }}static void locomo_dev_release(struct device *_dev){ struct locomo_dev *dev = LOCOMO_DEV(_dev); release_resource(&dev->res); kfree(dev);}static intlocomo_init_one_child(struct locomo *lchip, struct resource *parent, struct locomo_dev_info *info){ struct locomo_dev *dev; int ret; dev = kmalloc(sizeof(struct locomo_dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; goto out; } memset(dev, 0, sizeof(struct locomo_dev)); strncpy(dev->dev.bus_id,info->name,sizeof(dev->dev.bus_id)); /* * If the parent device has a DMA mask associated with it, * propagate it down to the children. */ if (lchip->dev->dma_mask) { dev->dma_mask = *lchip->dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask; } dev->devid = info->devid; dev->dev.parent = lchip->dev; dev->dev.bus = &locomo_bus_type; dev->dev.release = locomo_dev_release; dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; dev->res.start = lchip->phys + info->offset; dev->res.end = dev->res.start + info->length; dev->res.name = dev->dev.bus_id; dev->res.flags = IORESOURCE_MEM; dev->mapbase = lchip->base + info->offset; memmove(dev->irq, info->irq, sizeof(dev->irq)); if (info->length) { ret = request_resource(parent, &dev->res); if (ret) { printk("LoCoMo: failed to allocate resource for %s\n", dev->res.name); goto out; } } ret = device_register(&dev->dev); if (ret) { release_resource(&dev->res); out: kfree(dev); } return ret;}/** * locomo_probe - probe for a single LoCoMo chip. * @phys_addr: physical address of device. * * Probe for a LoCoMo chip. This must be called * before any other locomo-specific code. * * Returns: * %-ENODEV device not found. * %-EBUSY physical address already marked in-use. * %0 successful. */static int__locomo_probe(struct device *me, struct resource *mem, int irq){ struct locomo *lchip; unsigned long r; int i, ret = -ENODEV; lchip = kmalloc(sizeof(struct locomo), GFP_KERNEL); if (!lchip) return -ENOMEM; memset(lchip, 0, sizeof(struct locomo)); lchip->dev = me; dev_set_drvdata(lchip->dev, lchip); lchip->phys = mem->start; lchip->irq = irq; /* * Map the whole region. This also maps the * registers for our children. */ lchip->base = ioremap(mem->start, PAGE_SIZE); if (!lchip->base) { ret = -ENOMEM; goto out; } /* locomo initialize */ locomo_writel(0, lchip->base + LOCOMO_ICR); /* KEYBOARD */ locomo_writel(0, lchip->base + LOCOMO_KIC); /* GPIO */ locomo_writel(0, lchip->base + LOCOMO_GPO); locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) , lchip->base + LOCOMO_GPE); locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) , lchip->base + LOCOMO_GPD); locomo_writel(0, lchip->base + LOCOMO_GIE); /* FrontLight */ locomo_writel(0, lchip->base + LOCOMO_ALS); locomo_writel(0, lchip->base + LOCOMO_ALD); /* Longtime timer */ locomo_writel(0, lchip->base + LOCOMO_LTINT); /* SPI */ locomo_writel(0, lchip->base + LOCOMO_SPIIE); locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); r = locomo_readl(lchip->base + LOCOMO_ASD); r |= 0x8000; locomo_writel(r, lchip->base + LOCOMO_ASD); locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD); r = locomo_readl(lchip->base + LOCOMO_HSD); r |= 0x8000; locomo_writel(r, lchip->base + LOCOMO_HSD); locomo_writel(128 / 8, lchip->base + LOCOMO_HSC); /* XON */ locomo_writel(0x80, lchip->base + LOCOMO_TADC); udelay(1000); /* CLK9MEN */ r = locomo_readl(lchip->base + LOCOMO_TADC); r |= 0x10; locomo_writel(r, lchip->base + LOCOMO_TADC); udelay(100); /* init DAC */ r = locomo_readl(lchip->base + LOCOMO_DAC); r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; locomo_writel(r, lchip->base + LOCOMO_DAC); r = locomo_readl(lchip->base + LOCOMO_VER); printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff)); /* * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available. */ if (lchip->irq != NO_IRQ) locomo_setup_irq(lchip); for (i = 0; i < ARRAY_SIZE(locomo_devices); i++) locomo_init_one_child(lchip, mem, &locomo_devices[i]); return 0; out: kfree(lchip); return ret;}static void __locomo_remove(struct locomo *lchip){ struct list_head *l, *n; list_for_each_safe(l, n, &lchip->dev->children) { struct device *d = list_to_dev(l); device_unregister(d); } if (lchip->irq != NO_IRQ) { set_irq_chained_handler(lchip->irq, NULL); set_irq_data(lchip->irq, NULL); } iounmap(lchip->base); kfree(lchip);}static int locomo_probe(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct resource *mem = NULL, *irq = NULL; int i; for (i = 0; i < pdev->num_resources; i++) { if (pdev->resource[i].flags & IORESOURCE_MEM) mem = &pdev->resource[i]; if (pdev->resource[i].flags & IORESOURCE_IRQ) irq = &pdev->resource[i]; } return __locomo_probe(dev, mem, irq ? irq->start : NO_IRQ);}static int locomo_remove(struct device *dev){ struct locomo *lchip = dev_get_drvdata(dev); if (lchip) { __locomo_remove(lchip); dev_set_drvdata(dev, NULL); kfree(dev->saved_state); dev->saved_state = NULL; } return 0;}/* * Not sure if this should be on the system bus or not yet. * We really want some way to register a system device at * the per-machine level, and then have this driver pick * up the registered devices. */static struct device_driver locomo_device_driver = { .name = "locomo", .bus = &platform_bus_type, .probe = locomo_probe, .remove = locomo_remove,};/* * Get the parent device driver (us) structure * from a child function device */static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev){ return (struct locomo *)dev_get_drvdata(ldev->dev.parent);}/* * LoCoMo "Register Access Bus." * * We model this as a regular bus type, and hang devices directly * off this. */static int locomo_match(struct device *_dev, struct device_driver *_drv){ struct locomo_dev *dev = LOCOMO_DEV(_dev); struct locomo_driver *drv = LOCOMO_DRV(_drv); return dev->devid == drv->devid;}static int locomo_bus_suspend(struct device *dev, u32 state){ struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv && drv->suspend) ret = drv->suspend(ldev, state); return ret;}static int locomo_bus_resume(struct device *dev){ struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv && drv->resume) ret = drv->resume(ldev); return ret;}static int locomo_bus_probe(struct device *dev){ struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = -ENODEV; if (drv->probe) ret = drv->probe(ldev); return ret;}static int locomo_bus_remove(struct device *dev){ struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = 0; if (drv->remove) ret = drv->remove(ldev); return ret;}struct bus_type locomo_bus_type = { .name = "locomo-bus", .match = locomo_match, .suspend = locomo_bus_suspend, .resume = locomo_bus_resume,};int locomo_driver_register(struct locomo_driver *driver){ driver->drv.probe = locomo_bus_probe; driver->drv.remove = locomo_bus_remove; driver->drv.bus = &locomo_bus_type; return driver_register(&driver->drv);}void locomo_driver_unregister(struct locomo_driver *driver){ driver_unregister(&driver->drv);}static int __init locomo_init(void){ int ret = bus_register(&locomo_bus_type); if (ret == 0) driver_register(&locomo_device_driver); return ret;}static void __exit locomo_exit(void){ driver_unregister(&locomo_device_driver); bus_unregister(&locomo_bus_type);}module_init(locomo_init);module_exit(locomo_exit);MODULE_DESCRIPTION("Sharp LoCoMo core driver");MODULE_LICENSE("GPL");MODULE_AUTHOR("John Lenz <jelenz@students.wisc.edu>");EXPORT_SYMBOL(locomo_driver_register);EXPORT_SYMBOL(locomo_driver_unregister);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -