Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.23-rc3 163 lines 4.1 kB view raw
1/* 2 * Serial Port driver for Open Firmware platform devices 3 * 4 * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 * 11 */ 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/serial_core.h> 15#include <linux/serial_8250.h> 16 17#include <asm/of_platform.h> 18#include <asm/prom.h> 19 20struct of_serial_info { 21 int type; 22 int line; 23}; 24 25/* 26 * Fill a struct uart_port for a given device node 27 */ 28static int __devinit of_platform_serial_setup(struct of_device *ofdev, 29 int type, struct uart_port *port) 30{ 31 struct resource resource; 32 struct device_node *np = ofdev->node; 33 const unsigned int *clk, *spd; 34 int ret; 35 36 memset(port, 0, sizeof *port); 37 spd = of_get_property(np, "current-speed", NULL); 38 clk = of_get_property(np, "clock-frequency", NULL); 39 if (!clk) { 40 dev_warn(&ofdev->dev, "no clock-frequency property set\n"); 41 return -ENODEV; 42 } 43 44 ret = of_address_to_resource(np, 0, &resource); 45 if (ret) { 46 dev_warn(&ofdev->dev, "invalid address\n"); 47 return ret; 48 } 49 50 spin_lock_init(&port->lock); 51 port->mapbase = resource.start; 52 port->irq = irq_of_parse_and_map(np, 0); 53 port->iotype = UPIO_MEM; 54 port->type = type; 55 port->uartclk = *clk; 56 port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP 57 | UPF_FIXED_PORT; 58 port->dev = &ofdev->dev; 59 port->custom_divisor = *clk / (16 * (*spd)); 60 61 return 0; 62} 63 64/* 65 * Try to register a serial port 66 */ 67static int __devinit of_platform_serial_probe(struct of_device *ofdev, 68 const struct of_device_id *id) 69{ 70 struct of_serial_info *info; 71 struct uart_port port; 72 int port_type; 73 int ret; 74 75 if (of_find_property(ofdev->node, "used-by-rtas", NULL)) 76 return -EBUSY; 77 78 info = kmalloc(sizeof(*info), GFP_KERNEL); 79 if (info == NULL) 80 return -ENOMEM; 81 82 port_type = (unsigned long)id->data; 83 ret = of_platform_serial_setup(ofdev, port_type, &port); 84 if (ret) 85 goto out; 86 87 switch (port_type) { 88 case PORT_8250 ... PORT_MAX_8250: 89 ret = serial8250_register_port(&port); 90 break; 91 default: 92 /* need to add code for these */ 93 case PORT_UNKNOWN: 94 dev_info(&ofdev->dev, "Unknown serial port found, ignored\n"); 95 ret = -ENODEV; 96 break; 97 } 98 if (ret < 0) 99 goto out; 100 101 info->type = port_type; 102 info->line = ret; 103 ofdev->dev.driver_data = info; 104 return 0; 105out: 106 kfree(info); 107 irq_dispose_mapping(port.irq); 108 return ret; 109} 110 111/* 112 * Release a line 113 */ 114static int of_platform_serial_remove(struct of_device *ofdev) 115{ 116 struct of_serial_info *info = ofdev->dev.driver_data; 117 switch (info->type) { 118 case PORT_8250 ... PORT_MAX_8250: 119 serial8250_unregister_port(info->line); 120 break; 121 default: 122 /* need to add code for these */ 123 break; 124 } 125 kfree(info); 126 return 0; 127} 128 129/* 130 * A few common types, add more as needed. 131 */ 132static struct of_device_id __devinitdata of_platform_serial_table[] = { 133 { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, }, 134 { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, }, 135 { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, }, 136 { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, }, 137 { .type = "serial", .data = (void *)PORT_UNKNOWN, }, 138 { /* end of list */ }, 139}; 140 141static struct of_platform_driver __devinitdata of_platform_serial_driver = { 142 .owner = THIS_MODULE, 143 .name = "of_serial", 144 .probe = of_platform_serial_probe, 145 .remove = of_platform_serial_remove, 146 .match_table = of_platform_serial_table, 147}; 148 149static int __init of_platform_serial_init(void) 150{ 151 return of_register_platform_driver(&of_platform_serial_driver); 152} 153module_init(of_platform_serial_init); 154 155static void __exit of_platform_serial_exit(void) 156{ 157 return of_unregister_platform_driver(&of_platform_serial_driver); 158}; 159module_exit(of_platform_serial_exit); 160 161MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>"); 162MODULE_LICENSE("GPL"); 163MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");