aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
authorBenson Leung <bleung@chromium.org>2017-12-13 05:32:15 -0500
committerChanwoo Choi <cw00.choi@samsung.com>2017-12-15 03:21:49 -0500
commitc7eb47f9e45226571be31212f6efd4b307d3b59d (patch)
treec4277b27d85431d5021a4516cace435d0b384153 /drivers/extcon
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
extcon: usbc-cros-ec: add support to notify USB type cables.
Extend the driver to notify host and device type cables and the presence of power. Signed-off-by: Benson Leung <bleung@chromium.org> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/extcon-usbc-cros-ec.c142
1 files changed, 138 insertions, 4 deletions
diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c
index 6187f731b29d..6721ab01fe7d 100644
--- a/drivers/extcon/extcon-usbc-cros-ec.c
+++ b/drivers/extcon/extcon-usbc-cros-ec.c
@@ -34,16 +34,26 @@ struct cros_ec_extcon_info {
34 34
35 struct notifier_block notifier; 35 struct notifier_block notifier;
36 36
37 unsigned int dr; /* data role */
38 bool pr; /* power role (true if VBUS enabled) */
37 bool dp; /* DisplayPort enabled */ 39 bool dp; /* DisplayPort enabled */
38 bool mux; /* SuperSpeed (usb3) enabled */ 40 bool mux; /* SuperSpeed (usb3) enabled */
39 unsigned int power_type; 41 unsigned int power_type;
40}; 42};
41 43
42static const unsigned int usb_type_c_cable[] = { 44static const unsigned int usb_type_c_cable[] = {
45 EXTCON_USB,
46 EXTCON_USB_HOST,
43 EXTCON_DISP_DP, 47 EXTCON_DISP_DP,
44 EXTCON_NONE, 48 EXTCON_NONE,
45}; 49};
46 50
51enum usb_data_roles {
52 DR_NONE,
53 DR_HOST,
54 DR_DEVICE,
55};
56
47/** 57/**
48 * cros_ec_pd_command() - Send a command to the EC. 58 * cros_ec_pd_command() - Send a command to the EC.
49 * @info: pointer to struct cros_ec_extcon_info 59 * @info: pointer to struct cros_ec_extcon_info
@@ -150,6 +160,7 @@ static int cros_ec_usb_get_role(struct cros_ec_extcon_info *info,
150 pd_control.port = info->port_id; 160 pd_control.port = info->port_id;
151 pd_control.role = USB_PD_CTRL_ROLE_NO_CHANGE; 161 pd_control.role = USB_PD_CTRL_ROLE_NO_CHANGE;
152 pd_control.mux = USB_PD_CTRL_MUX_NO_CHANGE; 162 pd_control.mux = USB_PD_CTRL_MUX_NO_CHANGE;
163 pd_control.swap = USB_PD_CTRL_SWAP_NONE;
153 ret = cros_ec_pd_command(info, EC_CMD_USB_PD_CONTROL, 1, 164 ret = cros_ec_pd_command(info, EC_CMD_USB_PD_CONTROL, 1,
154 &pd_control, sizeof(pd_control), 165 &pd_control, sizeof(pd_control),
155 &resp, sizeof(resp)); 166 &resp, sizeof(resp));
@@ -183,11 +194,72 @@ static int cros_ec_pd_get_num_ports(struct cros_ec_extcon_info *info)
183 return resp.num_ports; 194 return resp.num_ports;
184} 195}
185 196
197static const char *cros_ec_usb_role_string(unsigned int role)
198{
199 return role == DR_NONE ? "DISCONNECTED" :
200 (role == DR_HOST ? "DFP" : "UFP");
201}
202
203static const char *cros_ec_usb_power_type_string(unsigned int type)
204{
205 switch (type) {
206 case USB_CHG_TYPE_NONE:
207 return "USB_CHG_TYPE_NONE";
208 case USB_CHG_TYPE_PD:
209 return "USB_CHG_TYPE_PD";
210 case USB_CHG_TYPE_PROPRIETARY:
211 return "USB_CHG_TYPE_PROPRIETARY";
212 case USB_CHG_TYPE_C:
213 return "USB_CHG_TYPE_C";
214 case USB_CHG_TYPE_BC12_DCP:
215 return "USB_CHG_TYPE_BC12_DCP";
216 case USB_CHG_TYPE_BC12_CDP:
217 return "USB_CHG_TYPE_BC12_CDP";
218 case USB_CHG_TYPE_BC12_SDP:
219 return "USB_CHG_TYPE_BC12_SDP";
220 case USB_CHG_TYPE_OTHER:
221 return "USB_CHG_TYPE_OTHER";
222 case USB_CHG_TYPE_VBUS:
223 return "USB_CHG_TYPE_VBUS";
224 case USB_CHG_TYPE_UNKNOWN:
225 return "USB_CHG_TYPE_UNKNOWN";
226 default:
227 return "USB_CHG_TYPE_UNKNOWN";
228 }
229}
230
231static bool cros_ec_usb_power_type_is_wall_wart(unsigned int type,
232 unsigned int role)
233{
234 switch (type) {
235 /* FIXME : Guppy, Donnettes, and other chargers will be miscategorized
236 * because they identify with USB_CHG_TYPE_C, but we can't return true
237 * here from that code because that breaks Suzy-Q and other kinds of
238 * USB Type-C cables and peripherals.
239 */
240 case USB_CHG_TYPE_PROPRIETARY:
241 case USB_CHG_TYPE_BC12_DCP:
242 return true;
243 case USB_CHG_TYPE_PD:
244 case USB_CHG_TYPE_C:
245 case USB_CHG_TYPE_BC12_CDP:
246 case USB_CHG_TYPE_BC12_SDP:
247 case USB_CHG_TYPE_OTHER:
248 case USB_CHG_TYPE_VBUS:
249 case USB_CHG_TYPE_UNKNOWN:
250 case USB_CHG_TYPE_NONE:
251 default:
252 return false;
253 }
254}
255
186static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, 256static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
187 bool force) 257 bool force)
188{ 258{
189 struct device *dev = info->dev; 259 struct device *dev = info->dev;
190 int role, power_type; 260 int role, power_type;
261 unsigned int dr = DR_NONE;
262 bool pr = false;
191 bool polarity = false; 263 bool polarity = false;
192 bool dp = false; 264 bool dp = false;
193 bool mux = false; 265 bool mux = false;
@@ -206,9 +278,12 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
206 dev_err(dev, "failed getting role err = %d\n", role); 278 dev_err(dev, "failed getting role err = %d\n", role);
207 return role; 279 return role;
208 } 280 }
281 dev_dbg(dev, "disconnected\n");
209 } else { 282 } else {
210 int pd_mux_state; 283 int pd_mux_state;
211 284
285 dr = (role & PD_CTRL_RESP_ROLE_DATA) ? DR_HOST : DR_DEVICE;
286 pr = (role & PD_CTRL_RESP_ROLE_POWER);
212 pd_mux_state = cros_ec_usb_get_pd_mux_state(info); 287 pd_mux_state = cros_ec_usb_get_pd_mux_state(info);
213 if (pd_mux_state < 0) 288 if (pd_mux_state < 0)
214 pd_mux_state = USB_PD_MUX_USB_ENABLED; 289 pd_mux_state = USB_PD_MUX_USB_ENABLED;
@@ -216,20 +291,62 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
216 dp = pd_mux_state & USB_PD_MUX_DP_ENABLED; 291 dp = pd_mux_state & USB_PD_MUX_DP_ENABLED;
217 mux = pd_mux_state & USB_PD_MUX_USB_ENABLED; 292 mux = pd_mux_state & USB_PD_MUX_USB_ENABLED;
218 hpd = pd_mux_state & USB_PD_MUX_HPD_IRQ; 293 hpd = pd_mux_state & USB_PD_MUX_HPD_IRQ;
219 }
220 294
221 if (force || info->dp != dp || info->mux != mux || 295 dev_dbg(dev,
222 info->power_type != power_type) { 296 "connected role 0x%x pwr type %d dr %d pr %d pol %d mux %d dp %d hpd %d\n",
297 role, power_type, dr, pr, polarity, mux, dp, hpd);
298 }
223 299
300 /*
301 * When there is no USB host (e.g. USB PD charger),
302 * we are not really a UFP for the AP.
303 */
304 if (dr == DR_DEVICE &&
305 cros_ec_usb_power_type_is_wall_wart(power_type, role))
306 dr = DR_NONE;
307
308 if (force || info->dr != dr || info->pr != pr || info->dp != dp ||
309 info->mux != mux || info->power_type != power_type) {
310 bool host_connected = false, device_connected = false;
311
312 dev_dbg(dev, "Type/Role switch! type = %s role = %s\n",
313 cros_ec_usb_power_type_string(power_type),
314 cros_ec_usb_role_string(dr));
315 info->dr = dr;
316 info->pr = pr;
224 info->dp = dp; 317 info->dp = dp;
225 info->mux = mux; 318 info->mux = mux;
226 info->power_type = power_type; 319 info->power_type = power_type;
227 320
228 extcon_set_state(info->edev, EXTCON_DISP_DP, dp); 321 if (dr == DR_DEVICE)
322 device_connected = true;
323 else if (dr == DR_HOST)
324 host_connected = true;
229 325
326 extcon_set_state(info->edev, EXTCON_USB, device_connected);
327 extcon_set_state(info->edev, EXTCON_USB_HOST, host_connected);
328 extcon_set_state(info->edev, EXTCON_DISP_DP, dp);
329 extcon_set_property(info->edev, EXTCON_USB,
330 EXTCON_PROP_USB_VBUS,
331 (union extcon_property_value)(int)pr);
332 extcon_set_property(info->edev, EXTCON_USB_HOST,
333 EXTCON_PROP_USB_VBUS,
334 (union extcon_property_value)(int)pr);
335 extcon_set_property(info->edev, EXTCON_USB,
336 EXTCON_PROP_USB_TYPEC_POLARITY,
337 (union extcon_property_value)(int)polarity);
338 extcon_set_property(info->edev, EXTCON_USB_HOST,
339 EXTCON_PROP_USB_TYPEC_POLARITY,
340 (union extcon_property_value)(int)polarity);
230 extcon_set_property(info->edev, EXTCON_DISP_DP, 341 extcon_set_property(info->edev, EXTCON_DISP_DP,
231 EXTCON_PROP_USB_TYPEC_POLARITY, 342 EXTCON_PROP_USB_TYPEC_POLARITY,
232 (union extcon_property_value)(int)polarity); 343 (union extcon_property_value)(int)polarity);
344 extcon_set_property(info->edev, EXTCON_USB,
345 EXTCON_PROP_USB_SS,
346 (union extcon_property_value)(int)mux);
347 extcon_set_property(info->edev, EXTCON_USB_HOST,
348 EXTCON_PROP_USB_SS,
349 (union extcon_property_value)(int)mux);
233 extcon_set_property(info->edev, EXTCON_DISP_DP, 350 extcon_set_property(info->edev, EXTCON_DISP_DP,
234 EXTCON_PROP_USB_SS, 351 EXTCON_PROP_USB_SS,
235 (union extcon_property_value)(int)mux); 352 (union extcon_property_value)(int)mux);
@@ -237,6 +354,8 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info,
237 EXTCON_PROP_DISP_HPD, 354 EXTCON_PROP_DISP_HPD,
238 (union extcon_property_value)(int)hpd); 355 (union extcon_property_value)(int)hpd);
239 356
357 extcon_sync(info->edev, EXTCON_USB);
358 extcon_sync(info->edev, EXTCON_USB_HOST);
240 extcon_sync(info->edev, EXTCON_DISP_DP); 359 extcon_sync(info->edev, EXTCON_DISP_DP);
241 360
242 } else if (hpd) { 361 } else if (hpd) {
@@ -322,13 +441,28 @@ static int extcon_cros_ec_probe(struct platform_device *pdev)
322 return ret; 441 return ret;
323 } 442 }
324 443
444 extcon_set_property_capability(info->edev, EXTCON_USB,
445 EXTCON_PROP_USB_VBUS);
446 extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
447 EXTCON_PROP_USB_VBUS);
448 extcon_set_property_capability(info->edev, EXTCON_USB,
449 EXTCON_PROP_USB_TYPEC_POLARITY);
450 extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
451 EXTCON_PROP_USB_TYPEC_POLARITY);
325 extcon_set_property_capability(info->edev, EXTCON_DISP_DP, 452 extcon_set_property_capability(info->edev, EXTCON_DISP_DP,
326 EXTCON_PROP_USB_TYPEC_POLARITY); 453 EXTCON_PROP_USB_TYPEC_POLARITY);
454 extcon_set_property_capability(info->edev, EXTCON_USB,
455 EXTCON_PROP_USB_SS);
456 extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
457 EXTCON_PROP_USB_SS);
327 extcon_set_property_capability(info->edev, EXTCON_DISP_DP, 458 extcon_set_property_capability(info->edev, EXTCON_DISP_DP,
328 EXTCON_PROP_USB_SS); 459 EXTCON_PROP_USB_SS);
329 extcon_set_property_capability(info->edev, EXTCON_DISP_DP, 460 extcon_set_property_capability(info->edev, EXTCON_DISP_DP,
330 EXTCON_PROP_DISP_HPD); 461 EXTCON_PROP_DISP_HPD);
331 462
463 info->dr = DR_NONE;
464 info->pr = false;
465
332 platform_set_drvdata(pdev, info); 466 platform_set_drvdata(pdev, info);
333 467
334 /* Get PD events from the EC */ 468 /* Get PD events from the EC */