diff options
author | Murali Karicheri <m-karicheri2@ti.com> | 2012-10-22 11:58:01 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-25 14:32:29 -0400 |
commit | 0bbeb3c3e84bc963d1c66661e082d207023b0e5c (patch) | |
tree | 7cde25a865c1acd1bc030da4816ea78603484ec8 | |
parent | cadf74869013dc309bde50ed446f56d33a6a9806 (diff) |
of serial port driver - add clk_get_rate() support
Currently this driver expects the clock-frequency attribute. This
patch allows getting clock-frequency through clk driver API
clk_get_rate() if clock-frequency attribute is not defined.
So in the device bindings for serial device, one can add clocks
phandle to refer to the clk device to get the rate.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/tty/serial/of_serial.c | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index df443b908ca3..533ccfe77094 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 | }; |
@@ -51,7 +53,8 @@ EXPORT_SYMBOL_GPL(tegra_serial_handle_break); | |||
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 __devinit 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 (info->clk == NULL) { | ||
70 | dev_warn(&ofdev->dev, | ||
71 | "clk or clock-frequency not defined\n"); | ||
72 | return -ENODEV; | ||
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,6 +128,10 @@ 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 | /* |
@@ -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 | } |