diff options
Diffstat (limited to 'drivers/usb/phy/phy.c')
-rw-r--r-- | drivers/usb/phy/phy.c | 276 |
1 files changed, 274 insertions, 2 deletions
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 032f5afaad4b..89f4ac4cd93e 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c | |||
@@ -18,6 +18,18 @@ | |||
18 | 18 | ||
19 | #include <linux/usb/phy.h> | 19 | #include <linux/usb/phy.h> |
20 | 20 | ||
21 | /* Default current range by charger type. */ | ||
22 | #define DEFAULT_SDP_CUR_MIN 2 | ||
23 | #define DEFAULT_SDP_CUR_MAX 500 | ||
24 | #define DEFAULT_SDP_CUR_MIN_SS 150 | ||
25 | #define DEFAULT_SDP_CUR_MAX_SS 900 | ||
26 | #define DEFAULT_DCP_CUR_MIN 500 | ||
27 | #define DEFAULT_DCP_CUR_MAX 5000 | ||
28 | #define DEFAULT_CDP_CUR_MIN 1500 | ||
29 | #define DEFAULT_CDP_CUR_MAX 5000 | ||
30 | #define DEFAULT_ACA_CUR_MIN 1500 | ||
31 | #define DEFAULT_ACA_CUR_MAX 5000 | ||
32 | |||
21 | static LIST_HEAD(phy_list); | 33 | static LIST_HEAD(phy_list); |
22 | static LIST_HEAD(phy_bind_list); | 34 | static LIST_HEAD(phy_bind_list); |
23 | static DEFINE_SPINLOCK(phy_lock); | 35 | static DEFINE_SPINLOCK(phy_lock); |
@@ -77,6 +89,221 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node) | |||
77 | return ERR_PTR(-EPROBE_DEFER); | 89 | return ERR_PTR(-EPROBE_DEFER); |
78 | } | 90 | } |
79 | 91 | ||
92 | static void usb_phy_set_default_current(struct usb_phy *usb_phy) | ||
93 | { | ||
94 | usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN; | ||
95 | usb_phy->chg_cur.sdp_max = DEFAULT_SDP_CUR_MAX; | ||
96 | usb_phy->chg_cur.dcp_min = DEFAULT_DCP_CUR_MIN; | ||
97 | usb_phy->chg_cur.dcp_max = DEFAULT_DCP_CUR_MAX; | ||
98 | usb_phy->chg_cur.cdp_min = DEFAULT_CDP_CUR_MIN; | ||
99 | usb_phy->chg_cur.cdp_max = DEFAULT_CDP_CUR_MAX; | ||
100 | usb_phy->chg_cur.aca_min = DEFAULT_ACA_CUR_MIN; | ||
101 | usb_phy->chg_cur.aca_max = DEFAULT_ACA_CUR_MAX; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * usb_phy_notify_charger_work - notify the USB charger state | ||
106 | * @work - the charger work to notify the USB charger state | ||
107 | * | ||
108 | * This work can be issued when USB charger state has been changed or | ||
109 | * USB charger current has been changed, then we can notify the current | ||
110 | * what can be drawn to power user and the charger state to userspace. | ||
111 | * | ||
112 | * If we get the charger type from extcon subsystem, we can notify the | ||
113 | * charger state to power user automatically by usb_phy_get_charger_type() | ||
114 | * issuing from extcon subsystem. | ||
115 | * | ||
116 | * If we get the charger type from ->charger_detect() instead of extcon | ||
117 | * subsystem, the usb phy driver should issue usb_phy_set_charger_state() | ||
118 | * to set charger state when the charger state has been changed. | ||
119 | */ | ||
120 | static void usb_phy_notify_charger_work(struct work_struct *work) | ||
121 | { | ||
122 | struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work); | ||
123 | char uchger_state[50] = { 0 }; | ||
124 | char *envp[] = { uchger_state, NULL }; | ||
125 | unsigned int min, max; | ||
126 | |||
127 | switch (usb_phy->chg_state) { | ||
128 | case USB_CHARGER_PRESENT: | ||
129 | usb_phy_get_charger_current(usb_phy, &min, &max); | ||
130 | |||
131 | atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); | ||
132 | snprintf(uchger_state, ARRAY_SIZE(uchger_state), | ||
133 | "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT"); | ||
134 | break; | ||
135 | case USB_CHARGER_ABSENT: | ||
136 | usb_phy_set_default_current(usb_phy); | ||
137 | |||
138 | atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); | ||
139 | snprintf(uchger_state, ARRAY_SIZE(uchger_state), | ||
140 | "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT"); | ||
141 | break; | ||
142 | default: | ||
143 | dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", | ||
144 | usb_phy->chg_state); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp); | ||
149 | } | ||
150 | |||
151 | static void __usb_phy_get_charger_type(struct usb_phy *usb_phy) | ||
152 | { | ||
153 | if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_SDP) > 0) { | ||
154 | usb_phy->chg_type = SDP_TYPE; | ||
155 | usb_phy->chg_state = USB_CHARGER_PRESENT; | ||
156 | } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_CDP) > 0) { | ||
157 | usb_phy->chg_type = CDP_TYPE; | ||
158 | usb_phy->chg_state = USB_CHARGER_PRESENT; | ||
159 | } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_DCP) > 0) { | ||
160 | usb_phy->chg_type = DCP_TYPE; | ||
161 | usb_phy->chg_state = USB_CHARGER_PRESENT; | ||
162 | } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_ACA) > 0) { | ||
163 | usb_phy->chg_type = ACA_TYPE; | ||
164 | usb_phy->chg_state = USB_CHARGER_PRESENT; | ||
165 | } else { | ||
166 | usb_phy->chg_type = UNKNOWN_TYPE; | ||
167 | usb_phy->chg_state = USB_CHARGER_ABSENT; | ||
168 | } | ||
169 | |||
170 | schedule_work(&usb_phy->chg_work); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * usb_phy_get_charger_type - get charger type from extcon subsystem | ||
175 | * @nb -the notifier block to determine charger type | ||
176 | * @state - the cable state | ||
177 | * @data - private data | ||
178 | * | ||
179 | * Determin the charger type from extcon subsystem which also means the | ||
180 | * charger state has been chaned, then we should notify this event. | ||
181 | */ | ||
182 | static int usb_phy_get_charger_type(struct notifier_block *nb, | ||
183 | unsigned long state, void *data) | ||
184 | { | ||
185 | struct usb_phy *usb_phy = container_of(nb, struct usb_phy, type_nb); | ||
186 | |||
187 | __usb_phy_get_charger_type(usb_phy); | ||
188 | return NOTIFY_OK; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * usb_phy_set_charger_current - set the USB charger current | ||
193 | * @usb_phy - the USB phy to be used | ||
194 | * @mA - the current need to be set | ||
195 | * | ||
196 | * Usually we only change the charger default current when USB finished the | ||
197 | * enumeration as one SDP charger. As one SDP charger, usb_phy_set_power() | ||
198 | * will issue this function to change charger current when after setting USB | ||
199 | * configuration, or suspend/resume USB. For other type charger, we should | ||
200 | * use the default charger current and we do not suggest to issue this function | ||
201 | * to change the charger current. | ||
202 | * | ||
203 | * When USB charger current has been changed, we need to notify the power users. | ||
204 | */ | ||
205 | void usb_phy_set_charger_current(struct usb_phy *usb_phy, unsigned int mA) | ||
206 | { | ||
207 | switch (usb_phy->chg_type) { | ||
208 | case SDP_TYPE: | ||
209 | if (usb_phy->chg_cur.sdp_max == mA) | ||
210 | return; | ||
211 | |||
212 | usb_phy->chg_cur.sdp_max = (mA > DEFAULT_SDP_CUR_MAX_SS) ? | ||
213 | DEFAULT_SDP_CUR_MAX_SS : mA; | ||
214 | break; | ||
215 | case DCP_TYPE: | ||
216 | if (usb_phy->chg_cur.dcp_max == mA) | ||
217 | return; | ||
218 | |||
219 | usb_phy->chg_cur.dcp_max = (mA > DEFAULT_DCP_CUR_MAX) ? | ||
220 | DEFAULT_DCP_CUR_MAX : mA; | ||
221 | break; | ||
222 | case CDP_TYPE: | ||
223 | if (usb_phy->chg_cur.cdp_max == mA) | ||
224 | return; | ||
225 | |||
226 | usb_phy->chg_cur.cdp_max = (mA > DEFAULT_CDP_CUR_MAX) ? | ||
227 | DEFAULT_CDP_CUR_MAX : mA; | ||
228 | break; | ||
229 | case ACA_TYPE: | ||
230 | if (usb_phy->chg_cur.aca_max == mA) | ||
231 | return; | ||
232 | |||
233 | usb_phy->chg_cur.aca_max = (mA > DEFAULT_ACA_CUR_MAX) ? | ||
234 | DEFAULT_ACA_CUR_MAX : mA; | ||
235 | break; | ||
236 | default: | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | schedule_work(&usb_phy->chg_work); | ||
241 | } | ||
242 | EXPORT_SYMBOL_GPL(usb_phy_set_charger_current); | ||
243 | |||
244 | /** | ||
245 | * usb_phy_get_charger_current - get the USB charger current | ||
246 | * @usb_phy - the USB phy to be used | ||
247 | * @min - the minimum current | ||
248 | * @max - the maximum current | ||
249 | * | ||
250 | * Usually we will notify the maximum current to power user, but for some | ||
251 | * special case, power user also need the minimum current value. Then the | ||
252 | * power user can issue this function to get the suitable current. | ||
253 | */ | ||
254 | void usb_phy_get_charger_current(struct usb_phy *usb_phy, | ||
255 | unsigned int *min, unsigned int *max) | ||
256 | { | ||
257 | switch (usb_phy->chg_type) { | ||
258 | case SDP_TYPE: | ||
259 | *min = usb_phy->chg_cur.sdp_min; | ||
260 | *max = usb_phy->chg_cur.sdp_max; | ||
261 | break; | ||
262 | case DCP_TYPE: | ||
263 | *min = usb_phy->chg_cur.dcp_min; | ||
264 | *max = usb_phy->chg_cur.dcp_max; | ||
265 | break; | ||
266 | case CDP_TYPE: | ||
267 | *min = usb_phy->chg_cur.cdp_min; | ||
268 | *max = usb_phy->chg_cur.cdp_max; | ||
269 | break; | ||
270 | case ACA_TYPE: | ||
271 | *min = usb_phy->chg_cur.aca_min; | ||
272 | *max = usb_phy->chg_cur.aca_max; | ||
273 | break; | ||
274 | default: | ||
275 | *min = 0; | ||
276 | *max = 0; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | EXPORT_SYMBOL_GPL(usb_phy_get_charger_current); | ||
281 | |||
282 | /** | ||
283 | * usb_phy_set_charger_state - set the USB charger state | ||
284 | * @usb_phy - the USB phy to be used | ||
285 | * @state - the new state need to be set for charger | ||
286 | * | ||
287 | * The usb phy driver can issue this function when the usb phy driver | ||
288 | * detected the charger state has been changed, in this case the charger | ||
289 | * type should be get from ->charger_detect(). | ||
290 | */ | ||
291 | void usb_phy_set_charger_state(struct usb_phy *usb_phy, | ||
292 | enum usb_charger_state state) | ||
293 | { | ||
294 | if (usb_phy->chg_state == state || !usb_phy->charger_detect) | ||
295 | return; | ||
296 | |||
297 | usb_phy->chg_state = state; | ||
298 | if (usb_phy->chg_state == USB_CHARGER_PRESENT) | ||
299 | usb_phy->chg_type = usb_phy->charger_detect(usb_phy); | ||
300 | else | ||
301 | usb_phy->chg_type = UNKNOWN_TYPE; | ||
302 | |||
303 | schedule_work(&usb_phy->chg_work); | ||
304 | } | ||
305 | EXPORT_SYMBOL_GPL(usb_phy_set_charger_state); | ||
306 | |||
80 | static void devm_usb_phy_release(struct device *dev, void *res) | 307 | static void devm_usb_phy_release(struct device *dev, void *res) |
81 | { | 308 | { |
82 | struct usb_phy *phy = *(struct usb_phy **)res; | 309 | struct usb_phy *phy = *(struct usb_phy **)res; |
@@ -124,6 +351,44 @@ static int usb_add_extcon(struct usb_phy *x) | |||
124 | "register VBUS notifier failed\n"); | 351 | "register VBUS notifier failed\n"); |
125 | return ret; | 352 | return ret; |
126 | } | 353 | } |
354 | } else { | ||
355 | x->type_nb.notifier_call = usb_phy_get_charger_type; | ||
356 | |||
357 | ret = devm_extcon_register_notifier(x->dev, x->edev, | ||
358 | EXTCON_CHG_USB_SDP, | ||
359 | &x->type_nb); | ||
360 | if (ret) { | ||
361 | dev_err(x->dev, | ||
362 | "register extcon USB SDP failed.\n"); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | ret = devm_extcon_register_notifier(x->dev, x->edev, | ||
367 | EXTCON_CHG_USB_CDP, | ||
368 | &x->type_nb); | ||
369 | if (ret) { | ||
370 | dev_err(x->dev, | ||
371 | "register extcon USB CDP failed.\n"); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | ret = devm_extcon_register_notifier(x->dev, x->edev, | ||
376 | EXTCON_CHG_USB_DCP, | ||
377 | &x->type_nb); | ||
378 | if (ret) { | ||
379 | dev_err(x->dev, | ||
380 | "register extcon USB DCP failed.\n"); | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | ret = devm_extcon_register_notifier(x->dev, x->edev, | ||
385 | EXTCON_CHG_USB_ACA, | ||
386 | &x->type_nb); | ||
387 | if (ret) { | ||
388 | dev_err(x->dev, | ||
389 | "register extcon USB ACA failed.\n"); | ||
390 | return ret; | ||
391 | } | ||
127 | } | 392 | } |
128 | 393 | ||
129 | if (x->id_nb.notifier_call) { | 394 | if (x->id_nb.notifier_call) { |
@@ -145,6 +410,13 @@ static int usb_add_extcon(struct usb_phy *x) | |||
145 | } | 410 | } |
146 | } | 411 | } |
147 | 412 | ||
413 | usb_phy_set_default_current(x); | ||
414 | INIT_WORK(&x->chg_work, usb_phy_notify_charger_work); | ||
415 | x->chg_type = UNKNOWN_TYPE; | ||
416 | x->chg_state = USB_CHARGER_DEFAULT; | ||
417 | if (x->type_nb.notifier_call) | ||
418 | __usb_phy_get_charger_type(x); | ||
419 | |||
148 | return 0; | 420 | return 0; |
149 | } | 421 | } |
150 | 422 | ||
@@ -302,8 +574,8 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | |||
302 | 574 | ||
303 | node = of_parse_phandle(dev->of_node, phandle, index); | 575 | node = of_parse_phandle(dev->of_node, phandle, index); |
304 | if (!node) { | 576 | if (!node) { |
305 | dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, | 577 | dev_dbg(dev, "failed to get %s phandle in %pOF node\n", phandle, |
306 | dev->of_node->full_name); | 578 | dev->of_node); |
307 | return ERR_PTR(-ENODEV); | 579 | return ERR_PTR(-ENODEV); |
308 | } | 580 | } |
309 | phy = devm_usb_get_phy_by_node(dev, node, NULL); | 581 | phy = devm_usb_get_phy_by_node(dev, node, NULL); |