diff options
Diffstat (limited to 'drivers/tty/serial/of_serial.c')
| -rw-r--r-- | drivers/tty/serial/of_serial.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index df443b908ca3..e7cae1c2d7d2 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c | |||
| @@ -21,8 +21,10 @@ | |||
| 21 | #include <linux/of_serial.h> | 21 | #include <linux/of_serial.h> |
| 22 | #include <linux/of_platform.h> | 22 | #include <linux/of_platform.h> |
| 23 | #include <linux/nwpserial.h> | 23 | #include <linux/nwpserial.h> |
| 24 | #include <linux/clk.h> | ||
| 24 | 25 | ||
| 25 | struct of_serial_info { | 26 | struct of_serial_info { |
| 27 | struct clk *clk; | ||
| 26 | int type; | 28 | int type; |
| 27 | int line; | 29 | int line; |
| 28 | }; | 30 | }; |
| @@ -50,8 +52,9 @@ EXPORT_SYMBOL_GPL(tegra_serial_handle_break); | |||
| 50 | /* | 52 | /* |
| 51 | * Fill a struct uart_port for a given device node | 53 | * Fill a struct uart_port for a given device node |
| 52 | */ | 54 | */ |
| 53 | static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | 55 | static int of_platform_serial_setup(struct platform_device *ofdev, |
| 54 | int type, struct uart_port *port) | 56 | int type, struct uart_port *port, |
| 57 | struct of_serial_info *info) | ||
| 55 | { | 58 | { |
| 56 | struct resource resource; | 59 | struct resource resource; |
| 57 | struct device_node *np = ofdev->dev.of_node; | 60 | struct device_node *np = ofdev->dev.of_node; |
| @@ -60,8 +63,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | |||
| 60 | 63 | ||
| 61 | memset(port, 0, sizeof *port); | 64 | memset(port, 0, sizeof *port); |
| 62 | if (of_property_read_u32(np, "clock-frequency", &clk)) { | 65 | if (of_property_read_u32(np, "clock-frequency", &clk)) { |
| 63 | dev_warn(&ofdev->dev, "no clock-frequency property set\n"); | 66 | |
| 64 | return -ENODEV; | 67 | /* Get clk rate through clk driver if present */ |
| 68 | info->clk = clk_get(&ofdev->dev, NULL); | ||
| 69 | if (IS_ERR(info->clk)) { | ||
| 70 | dev_warn(&ofdev->dev, | ||
| 71 | "clk or clock-frequency not defined\n"); | ||
| 72 | return PTR_ERR(info->clk); | ||
| 73 | } | ||
| 74 | |||
| 75 | clk_prepare_enable(info->clk); | ||
| 76 | clk = clk_get_rate(info->clk); | ||
| 65 | } | 77 | } |
| 66 | /* If current-speed was set, then try not to change it. */ | 78 | /* If current-speed was set, then try not to change it. */ |
| 67 | if (of_property_read_u32(np, "current-speed", &spd) == 0) | 79 | if (of_property_read_u32(np, "current-speed", &spd) == 0) |
| @@ -70,7 +82,7 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | |||
| 70 | ret = of_address_to_resource(np, 0, &resource); | 82 | ret = of_address_to_resource(np, 0, &resource); |
| 71 | if (ret) { | 83 | if (ret) { |
| 72 | dev_warn(&ofdev->dev, "invalid address\n"); | 84 | dev_warn(&ofdev->dev, "invalid address\n"); |
| 73 | return ret; | 85 | goto out; |
| 74 | } | 86 | } |
| 75 | 87 | ||
| 76 | spin_lock_init(&port->lock); | 88 | spin_lock_init(&port->lock); |
| @@ -97,7 +109,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | |||
| 97 | default: | 109 | default: |
| 98 | dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", | 110 | dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", |
| 99 | prop); | 111 | prop); |
| 100 | return -EINVAL; | 112 | ret = -EINVAL; |
| 113 | goto out; | ||
| 101 | } | 114 | } |
| 102 | } | 115 | } |
| 103 | 116 | ||
| @@ -115,13 +128,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | |||
| 115 | port->handle_break = tegra_serial_handle_break; | 128 | port->handle_break = tegra_serial_handle_break; |
| 116 | 129 | ||
| 117 | return 0; | 130 | return 0; |
| 131 | out: | ||
| 132 | if (info->clk) | ||
| 133 | clk_disable_unprepare(info->clk); | ||
| 134 | return ret; | ||
| 118 | } | 135 | } |
| 119 | 136 | ||
| 120 | /* | 137 | /* |
| 121 | * Try to register a serial port | 138 | * Try to register a serial port |
| 122 | */ | 139 | */ |
| 123 | static struct of_device_id of_platform_serial_table[]; | 140 | static struct of_device_id of_platform_serial_table[]; |
| 124 | static int __devinit of_platform_serial_probe(struct platform_device *ofdev) | 141 | static int of_platform_serial_probe(struct platform_device *ofdev) |
| 125 | { | 142 | { |
| 126 | const struct of_device_id *match; | 143 | const struct of_device_id *match; |
| 127 | struct of_serial_info *info; | 144 | struct of_serial_info *info; |
| @@ -141,7 +158,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) | |||
| 141 | return -ENOMEM; | 158 | return -ENOMEM; |
| 142 | 159 | ||
| 143 | port_type = (unsigned long)match->data; | 160 | port_type = (unsigned long)match->data; |
| 144 | ret = of_platform_serial_setup(ofdev, port_type, &port); | 161 | ret = of_platform_serial_setup(ofdev, port_type, &port, info); |
| 145 | if (ret) | 162 | if (ret) |
| 146 | goto out; | 163 | goto out; |
| 147 | 164 | ||
| @@ -204,6 +221,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev) | |||
| 204 | /* need to add code for these */ | 221 | /* need to add code for these */ |
| 205 | break; | 222 | break; |
| 206 | } | 223 | } |
| 224 | |||
| 225 | if (info->clk) | ||
| 226 | clk_disable_unprepare(info->clk); | ||
| 207 | kfree(info); | 227 | kfree(info); |
| 208 | return 0; | 228 | return 0; |
| 209 | } | 229 | } |
| @@ -211,7 +231,7 @@ static int of_platform_serial_remove(struct platform_device *ofdev) | |||
| 211 | /* | 231 | /* |
| 212 | * A few common types, add more as needed. | 232 | * A few common types, add more as needed. |
| 213 | */ | 233 | */ |
| 214 | static struct of_device_id __devinitdata of_platform_serial_table[] = { | 234 | static struct of_device_id of_platform_serial_table[] = { |
| 215 | { .compatible = "ns8250", .data = (void *)PORT_8250, }, | 235 | { .compatible = "ns8250", .data = (void *)PORT_8250, }, |
| 216 | { .compatible = "ns16450", .data = (void *)PORT_16450, }, | 236 | { .compatible = "ns16450", .data = (void *)PORT_16450, }, |
| 217 | { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, | 237 | { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, |
