diff options
author | Bin Liu <b-liu@ti.com> | 2015-11-03 12:51:15 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2015-12-15 10:12:41 -0500 |
commit | 98bfb39466954c69d2a448e6ddcab6d91cd48e25 (patch) | |
tree | e5a93ad5f204c67f04663a29c9217500bdd72c42 | |
parent | fa4dce2022241f3c938372af0faf9d263061f6a9 (diff) |
usb: of: add an api to get dr_mode by the phy node
Some USB phy drivers have different handling for the controller in each
dr_mode. But the phy driver does not have visibility to the dr_mode of
the controller.
This adds an api to return the dr_mode of the controller which
associates the given phy node.
Signed-off-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/common/common.c | 60 | ||||
-rw-r--r-- | include/linux/usb/of.h | 5 |
2 files changed, 59 insertions, 6 deletions
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 673d53038ed2..e6ec125e4485 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/usb/ch9.h> | 17 | #include <linux/usb/ch9.h> |
18 | #include <linux/usb/of.h> | 18 | #include <linux/usb/of.h> |
19 | #include <linux/usb/otg.h> | 19 | #include <linux/usb/otg.h> |
20 | #include <linux/of_platform.h> | ||
20 | 21 | ||
21 | const char *usb_otg_state_string(enum usb_otg_state state) | 22 | const char *usb_otg_state_string(enum usb_otg_state state) |
22 | { | 23 | { |
@@ -106,25 +107,72 @@ static const char *const usb_dr_modes[] = { | |||
106 | [USB_DR_MODE_OTG] = "otg", | 107 | [USB_DR_MODE_OTG] = "otg", |
107 | }; | 108 | }; |
108 | 109 | ||
110 | static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) | ||
115 | if (!strcmp(usb_dr_modes[i], str)) | ||
116 | return i; | ||
117 | |||
118 | return USB_DR_MODE_UNKNOWN; | ||
119 | } | ||
120 | |||
109 | enum usb_dr_mode usb_get_dr_mode(struct device *dev) | 121 | enum usb_dr_mode usb_get_dr_mode(struct device *dev) |
110 | { | 122 | { |
111 | const char *dr_mode; | 123 | const char *dr_mode; |
112 | int err, i; | 124 | int err; |
113 | 125 | ||
114 | err = device_property_read_string(dev, "dr_mode", &dr_mode); | 126 | err = device_property_read_string(dev, "dr_mode", &dr_mode); |
115 | if (err < 0) | 127 | if (err < 0) |
116 | return USB_DR_MODE_UNKNOWN; | 128 | return USB_DR_MODE_UNKNOWN; |
117 | 129 | ||
118 | for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) | 130 | return usb_get_dr_mode_from_string(dr_mode); |
119 | if (!strcmp(dr_mode, usb_dr_modes[i])) | ||
120 | return i; | ||
121 | |||
122 | return USB_DR_MODE_UNKNOWN; | ||
123 | } | 131 | } |
124 | EXPORT_SYMBOL_GPL(usb_get_dr_mode); | 132 | EXPORT_SYMBOL_GPL(usb_get_dr_mode); |
125 | 133 | ||
126 | #ifdef CONFIG_OF | 134 | #ifdef CONFIG_OF |
127 | /** | 135 | /** |
136 | * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device | ||
137 | * which is associated with the given phy device_node | ||
138 | * @np: Pointer to the given phy device_node | ||
139 | * | ||
140 | * In dts a usb controller associates with phy devices. The function gets | ||
141 | * the string from property 'dr_mode' of the controller associated with the | ||
142 | * given phy device node, and returns the correspondig enum usb_dr_mode. | ||
143 | */ | ||
144 | enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) | ||
145 | { | ||
146 | struct device_node *controller = NULL; | ||
147 | struct device_node *phy; | ||
148 | const char *dr_mode; | ||
149 | int index; | ||
150 | int err; | ||
151 | |||
152 | do { | ||
153 | controller = of_find_node_with_property(controller, "phys"); | ||
154 | index = 0; | ||
155 | do { | ||
156 | phy = of_parse_phandle(controller, "phys", index); | ||
157 | of_node_put(phy); | ||
158 | if (phy == phy_np) | ||
159 | goto finish; | ||
160 | index++; | ||
161 | } while (phy); | ||
162 | } while (controller); | ||
163 | |||
164 | finish: | ||
165 | err = of_property_read_string(controller, "dr_mode", &dr_mode); | ||
166 | of_node_put(controller); | ||
167 | |||
168 | if (err < 0) | ||
169 | return USB_DR_MODE_UNKNOWN; | ||
170 | |||
171 | return usb_get_dr_mode_from_string(dr_mode); | ||
172 | } | ||
173 | EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy); | ||
174 | |||
175 | /** | ||
128 | * of_usb_host_tpl_support - to get if Targeted Peripheral List is supported | 176 | * of_usb_host_tpl_support - to get if Targeted Peripheral List is supported |
129 | * for given targeted hosts (non-PC hosts) | 177 | * for given targeted hosts (non-PC hosts) |
130 | * @np: Pointer to the given device_node | 178 | * @np: Pointer to the given device_node |
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index c3fe9e48ce27..3805757dcdc2 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h | |||
@@ -12,10 +12,15 @@ | |||
12 | #include <linux/usb/phy.h> | 12 | #include <linux/usb/phy.h> |
13 | 13 | ||
14 | #if IS_ENABLED(CONFIG_OF) | 14 | #if IS_ENABLED(CONFIG_OF) |
15 | enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np); | ||
15 | bool of_usb_host_tpl_support(struct device_node *np); | 16 | bool of_usb_host_tpl_support(struct device_node *np); |
16 | int of_usb_update_otg_caps(struct device_node *np, | 17 | int of_usb_update_otg_caps(struct device_node *np, |
17 | struct usb_otg_caps *otg_caps); | 18 | struct usb_otg_caps *otg_caps); |
18 | #else | 19 | #else |
20 | enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) | ||
21 | { | ||
22 | return USB_DR_MODE_UNKNOWN; | ||
23 | } | ||
19 | static inline bool of_usb_host_tpl_support(struct device_node *np) | 24 | static inline bool of_usb_host_tpl_support(struct device_node *np) |
20 | { | 25 | { |
21 | return false; | 26 | return false; |