1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC 4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 5 * 6 * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: 7 * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. 8 */ 9 10 #include <linux/extcon-provider.h> 11 #include <linux/interrupt.h> 12 #include <linux/kernel.h> 13 #include <linux/mfd/intel_soc_pmic.h> 14 #include <linux/module.h> 15 #include <linux/platform_device.h> 16 #include <linux/power_supply.h> 17 #include <linux/property.h> 18 #include <linux/regmap.h> 19 #include <linux/regulator/consumer.h> 20 #include <linux/slab.h> 21 #include <linux/usb/role.h> 22 23 #include "extcon-intel.h" 24 25 #define CHT_WC_PHYCTRL 0x5e07 26 27 #define CHT_WC_CHGRCTRL0 0x5e16 28 #define CHT_WC_CHGRCTRL0_CHGRRESET BIT(0) 29 #define CHT_WC_CHGRCTRL0_EMRGCHREN BIT(1) 30 #define CHT_WC_CHGRCTRL0_EXTCHRDIS BIT(2) 31 #define CHT_WC_CHGRCTRL0_SWCONTROL BIT(3) 32 #define CHT_WC_CHGRCTRL0_TTLCK BIT(4) 33 #define CHT_WC_CHGRCTRL0_CCSM_OFF BIT(5) 34 #define CHT_WC_CHGRCTRL0_DBPOFF BIT(6) 35 #define CHT_WC_CHGRCTRL0_CHR_WDT_NOKICK BIT(7) 36 37 #define CHT_WC_CHGRCTRL1 0x5e17 38 #define CHT_WC_CHGRCTRL1_FUSB_INLMT_100 BIT(0) 39 #define CHT_WC_CHGRCTRL1_FUSB_INLMT_150 BIT(1) 40 #define CHT_WC_CHGRCTRL1_FUSB_INLMT_500 BIT(2) 41 #define CHT_WC_CHGRCTRL1_FUSB_INLMT_900 BIT(3) 42 #define CHT_WC_CHGRCTRL1_FUSB_INLMT_1500 BIT(4) 43 #define CHT_WC_CHGRCTRL1_FTEMP_EVENT BIT(5) 44 #define CHT_WC_CHGRCTRL1_OTGMODE BIT(6) 45 #define CHT_WC_CHGRCTRL1_DBPEN BIT(7) 46 47 #define CHT_WC_USBSRC 0x5e29 48 #define CHT_WC_USBSRC_STS_MASK GENMASK(1, 0) 49 #define CHT_WC_USBSRC_STS_SUCCESS 2 50 #define CHT_WC_USBSRC_STS_FAIL 3 51 #define CHT_WC_USBSRC_TYPE_SHIFT 2 52 #define CHT_WC_USBSRC_TYPE_MASK GENMASK(5, 2) 53 #define CHT_WC_USBSRC_TYPE_NONE 0 54 #define CHT_WC_USBSRC_TYPE_SDP 1 55 #define CHT_WC_USBSRC_TYPE_DCP 2 56 #define CHT_WC_USBSRC_TYPE_CDP 3 57 #define CHT_WC_USBSRC_TYPE_ACA 4 58 #define CHT_WC_USBSRC_TYPE_SE1 5 59 #define CHT_WC_USBSRC_TYPE_MHL 6 60 #define CHT_WC_USBSRC_TYPE_FLOATING 7 61 #define CHT_WC_USBSRC_TYPE_OTHER 8 62 #define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9 63 64 #define CHT_WC_CHGDISCTRL 0x5e2f 65 #define CHT_WC_CHGDISCTRL_OUT BIT(0) 66 /* 0 - open drain, 1 - regular push-pull output */ 67 #define CHT_WC_CHGDISCTRL_DRV BIT(4) 68 /* 0 - pin is controlled by SW, 1 - by HW */ 69 #define CHT_WC_CHGDISCTRL_FN BIT(6) 70 71 #define CHT_WC_PWRSRC_IRQ 0x6e03 72 #define CHT_WC_PWRSRC_IRQ_MASK 0x6e0f 73 #define CHT_WC_PWRSRC_STS 0x6e1e 74 #define CHT_WC_PWRSRC_VBUS BIT(0) 75 #define CHT_WC_PWRSRC_DC BIT(1) 76 #define CHT_WC_PWRSRC_BATT BIT(2) 77 #define CHT_WC_PWRSRC_USBID_MASK GENMASK(4, 3) 78 #define CHT_WC_PWRSRC_USBID_SHIFT 3 79 #define CHT_WC_PWRSRC_RID_ACA 0 80 #define CHT_WC_PWRSRC_RID_GND 1 81 #define CHT_WC_PWRSRC_RID_FLOAT 2 82 83 #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d 84 #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0) 85 #define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4) 86 #define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5) 87 88 enum cht_wc_mux_select { 89 MUX_SEL_PMIC = 0, 90 MUX_SEL_SOC, 91 }; 92 93 static const unsigned int cht_wc_extcon_cables[] = { 94 EXTCON_USB, 95 EXTCON_USB_HOST, 96 EXTCON_CHG_USB_SDP, 97 EXTCON_CHG_USB_CDP, 98 EXTCON_CHG_USB_DCP, 99 EXTCON_CHG_USB_ACA, 100 EXTCON_NONE, 101 }; 102 103 struct cht_wc_extcon_data { 104 struct device *dev; 105 struct regmap *regmap; 106 struct extcon_dev *edev; 107 struct usb_role_switch *role_sw; 108 struct regulator *vbus_boost; 109 struct power_supply *psy; 110 enum power_supply_usb_type usb_type; 111 unsigned int previous_cable; 112 bool usb_host; 113 bool vbus_boost_enabled; 114 }; 115 116 static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts) 117 { 118 switch ((pwrsrc_sts & CHT_WC_PWRSRC_USBID_MASK) >> CHT_WC_PWRSRC_USBID_SHIFT) { 119 case CHT_WC_PWRSRC_RID_GND: 120 return INTEL_USB_ID_GND; 121 case CHT_WC_PWRSRC_RID_FLOAT: 122 return INTEL_USB_ID_FLOAT; 123 /* 124 * According to the spec. we should read the USB-ID pin ADC value here 125 * to determine the resistance of the used pull-down resister and then 126 * return RID_A / RID_B / RID_C based on this. But all "Accessory 127 * Charger Adapter"s (ACAs) which users can actually buy always use 128 * a combination of a charging port with one or more USB-A ports, so 129 * they should always use a resistor indicating RID_A. But the spec 130 * is hard to read / badly-worded so some of them actually indicate 131 * they are a RID_B ACA evnen though they clearly are a RID_A ACA. 132 * To workaround this simply always return INTEL_USB_RID_A, which 133 * matches all the ACAs which users can actually buy. 134 */ 135 case CHT_WC_PWRSRC_RID_ACA: 136 return INTEL_USB_RID_A; 137 default: 138 return INTEL_USB_ID_FLOAT; 139 } 140 } 141 142 static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext, 143 bool ignore_errors) 144 { 145 int ret, usbsrc, status; 146 unsigned long timeout; 147 148 /* Charger detection can take upto 600ms, wait 800ms max. */ 149 timeout = jiffies + msecs_to_jiffies(800); 150 do { 151 ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc); 152 if (ret) { 153 dev_err(ext->dev, "Error reading usbsrc: %d\n", ret); 154 return ret; 155 } 156 157 status = usbsrc & CHT_WC_USBSRC_STS_MASK; 158 if (status == CHT_WC_USBSRC_STS_SUCCESS || 159 status == CHT_WC_USBSRC_STS_FAIL) 160 break; 161 162 msleep(50); /* Wait a bit before retrying */ 163 } while (time_before(jiffies, timeout)); 164 165 if (status != CHT_WC_USBSRC_STS_SUCCESS) { 166 if (!ignore_errors) { 167 if (status == CHT_WC_USBSRC_STS_FAIL) 168 dev_warn(ext->dev, "Could not detect charger type\n"); 169 else 170 dev_warn(ext->dev, "Timeout detecting charger type\n"); 171 } 172 173 /* Safe fallback */ 174 usbsrc = CHT_WC_USBSRC_TYPE_SDP << CHT_WC_USBSRC_TYPE_SHIFT; 175 } 176 177 usbsrc = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT; 178 switch (usbsrc) { 179 default: 180 dev_warn(ext->dev, 181 "Unhandled charger type %d, defaulting to SDP\n", 182 ret); 183 ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP; 184 return EXTCON_CHG_USB_SDP; 185 case CHT_WC_USBSRC_TYPE_SDP: 186 case CHT_WC_USBSRC_TYPE_FLOATING: 187 case CHT_WC_USBSRC_TYPE_OTHER: 188 ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP; 189 return EXTCON_CHG_USB_SDP; 190 case CHT_WC_USBSRC_TYPE_CDP: 191 ext->usb_type = POWER_SUPPLY_USB_TYPE_CDP; 192 return EXTCON_CHG_USB_CDP; 193 case CHT_WC_USBSRC_TYPE_DCP: 194 case CHT_WC_USBSRC_TYPE_DCP_EXTPHY: 195 case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */ 196 ext->usb_type = POWER_SUPPLY_USB_TYPE_DCP; 197 return EXTCON_CHG_USB_DCP; 198 case CHT_WC_USBSRC_TYPE_ACA: 199 ext->usb_type = POWER_SUPPLY_USB_TYPE_ACA; 200 return EXTCON_CHG_USB_ACA; 201 } 202 } 203 204 static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state) 205 { 206 int ret; 207 208 ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state); 209 if (ret) 210 dev_err(ext->dev, "Error writing phyctrl: %d\n", ret); 211 } 212 213 static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, 214 bool enable) 215 { 216 int ret, val; 217 218 /* 219 * The 5V boost converter is enabled through a gpio on the PMIC, since 220 * there currently is no gpio driver we access the gpio reg directly. 221 */ 222 val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT; 223 if (enable) 224 val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT; 225 226 ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val); 227 if (ret) 228 dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); 229 } 230 231 static void cht_wc_extcon_set_otgmode(struct cht_wc_extcon_data *ext, 232 bool enable) 233 { 234 unsigned int val = enable ? CHT_WC_CHGRCTRL1_OTGMODE : 0; 235 int ret; 236 237 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL1, 238 CHT_WC_CHGRCTRL1_OTGMODE, val); 239 if (ret) 240 dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret); 241 242 if (ext->vbus_boost && ext->vbus_boost_enabled != enable) { 243 if (enable) 244 ret = regulator_enable(ext->vbus_boost); 245 else 246 ret = regulator_disable(ext->vbus_boost); 247 248 if (ret) 249 dev_err(ext->dev, "Error updating Vbus boost regulator: %d\n", ret); 250 else 251 ext->vbus_boost_enabled = enable; 252 } 253 } 254 255 static void cht_wc_extcon_enable_charging(struct cht_wc_extcon_data *ext, 256 bool enable) 257 { 258 unsigned int val = enable ? 0 : CHT_WC_CHGDISCTRL_OUT; 259 int ret; 260 261 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL, 262 CHT_WC_CHGDISCTRL_OUT, val); 263 if (ret) 264 dev_err(ext->dev, "Error updating CHGDISCTRL reg: %d\n", ret); 265 } 266 267 /* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */ 268 static void cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext, 269 unsigned int cable, bool state) 270 { 271 extcon_set_state_sync(ext->edev, cable, state); 272 if (cable == EXTCON_CHG_USB_SDP) 273 extcon_set_state_sync(ext->edev, EXTCON_USB, state); 274 } 275 276 static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext) 277 { 278 int ret, pwrsrc_sts, id; 279 unsigned int cable = EXTCON_NONE; 280 /* Ignore errors in host mode, as the 5v boost converter is on then */ 281 bool ignore_get_charger_errors = ext->usb_host; 282 enum usb_role role; 283 284 ext->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 285 286 ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); 287 if (ret) { 288 dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); 289 return; 290 } 291 292 id = cht_wc_extcon_get_id(ext, pwrsrc_sts); 293 if (id == INTEL_USB_ID_GND) { 294 cht_wc_extcon_enable_charging(ext, false); 295 cht_wc_extcon_set_otgmode(ext, true); 296 297 /* The 5v boost causes a false VBUS / SDP detect, skip */ 298 goto charger_det_done; 299 } 300 301 cht_wc_extcon_set_otgmode(ext, false); 302 cht_wc_extcon_enable_charging(ext, true); 303 304 /* Plugged into a host/charger or not connected? */ 305 if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) { 306 /* Route D+ and D- to PMIC for future charger detection */ 307 cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC); 308 goto set_state; 309 } 310 311 ret = cht_wc_extcon_get_charger(ext, ignore_get_charger_errors); 312 if (ret >= 0) 313 cable = ret; 314 315 charger_det_done: 316 /* Route D+ and D- to SoC for the host or gadget controller */ 317 cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC); 318 319 set_state: 320 if (cable != ext->previous_cable) { 321 cht_wc_extcon_set_state(ext, cable, true); 322 cht_wc_extcon_set_state(ext, ext->previous_cable, false); 323 ext->previous_cable = cable; 324 } 325 326 ext->usb_host = ((id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A)); 327 extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host); 328 329 if (ext->usb_host) 330 role = USB_ROLE_HOST; 331 else if (pwrsrc_sts & CHT_WC_PWRSRC_VBUS) 332 role = USB_ROLE_DEVICE; 333 else 334 role = USB_ROLE_NONE; 335 336 /* Note: this is a no-op when ext->role_sw is NULL */ 337 ret = usb_role_switch_set_role(ext->role_sw, role); 338 if (ret) 339 dev_err(ext->dev, "Error setting USB-role: %d\n", ret); 340 341 if (ext->psy) 342 power_supply_changed(ext->psy); 343 } 344 345 static irqreturn_t cht_wc_extcon_isr(int irq, void *data) 346 { 347 struct cht_wc_extcon_data *ext = data; 348 int ret, irqs; 349 350 ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs); 351 if (ret) { 352 dev_err(ext->dev, "Error reading irqs: %d\n", ret); 353 return IRQ_NONE; 354 } 355 356 cht_wc_extcon_pwrsrc_event(ext); 357 358 ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs); 359 if (ret) { 360 dev_err(ext->dev, "Error writing irqs: %d\n", ret); 361 return IRQ_NONE; 362 } 363 364 return IRQ_HANDLED; 365 } 366 367 static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable) 368 { 369 int ret, mask, val; 370 371 val = enable ? 0 : CHT_WC_CHGDISCTRL_FN; 372 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL, 373 CHT_WC_CHGDISCTRL_FN, val); 374 if (ret) 375 dev_err(ext->dev, 376 "Error setting sw control for CHGDIS pin: %d\n", 377 ret); 378 379 mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF; 380 val = enable ? mask : 0; 381 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val); 382 if (ret) 383 dev_err(ext->dev, "Error setting sw control: %d\n", ret); 384 385 return ret; 386 } 387 388 static int cht_wc_extcon_find_role_sw(struct cht_wc_extcon_data *ext) 389 { 390 const struct software_node *swnode; 391 struct fwnode_handle *fwnode; 392 393 swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); 394 if (!swnode) 395 return -EPROBE_DEFER; 396 397 fwnode = software_node_fwnode(swnode); 398 ext->role_sw = usb_role_switch_find_by_fwnode(fwnode); 399 fwnode_handle_put(fwnode); 400 401 return ext->role_sw ? 0 : -EPROBE_DEFER; 402 } 403 404 static void cht_wc_extcon_put_role_sw(void *data) 405 { 406 struct cht_wc_extcon_data *ext = data; 407 408 usb_role_switch_put(ext->role_sw); 409 } 410 411 /* Some boards require controlling the role-sw and Vbus based on the id-pin */ 412 static int cht_wc_extcon_get_role_sw_and_regulator(struct cht_wc_extcon_data *ext) 413 { 414 int ret; 415 416 ret = cht_wc_extcon_find_role_sw(ext); 417 if (ret) 418 return ret; 419 420 ret = devm_add_action_or_reset(ext->dev, cht_wc_extcon_put_role_sw, ext); 421 if (ret) 422 return ret; 423 424 /* 425 * On x86/ACPI platforms the regulator <-> consumer link is provided 426 * by platform_data passed to the regulator driver. This means that 427 * this info is not available before the regulator driver has bound. 428 * Use devm_regulator_get_optional() to avoid getting a dummy 429 * regulator and wait for the regulator to show up if necessary. 430 */ 431 ext->vbus_boost = devm_regulator_get_optional(ext->dev, "vbus"); 432 if (IS_ERR(ext->vbus_boost)) { 433 ret = PTR_ERR(ext->vbus_boost); 434 if (ret == -ENODEV) 435 ret = -EPROBE_DEFER; 436 437 return dev_err_probe(ext->dev, ret, "getting Vbus regulator"); 438 } 439 440 return 0; 441 } 442 443 static int cht_wc_extcon_psy_get_prop(struct power_supply *psy, 444 enum power_supply_property psp, 445 union power_supply_propval *val) 446 { 447 struct cht_wc_extcon_data *ext = power_supply_get_drvdata(psy); 448 449 switch (psp) { 450 case POWER_SUPPLY_PROP_USB_TYPE: 451 val->intval = ext->usb_type; 452 break; 453 case POWER_SUPPLY_PROP_ONLINE: 454 val->intval = ext->usb_type ? 1 : 0; 455 break; 456 default: 457 return -EINVAL; 458 } 459 460 return 0; 461 } 462 463 static const enum power_supply_property cht_wc_extcon_psy_props[] = { 464 POWER_SUPPLY_PROP_USB_TYPE, 465 POWER_SUPPLY_PROP_ONLINE, 466 }; 467 468 static const struct power_supply_desc cht_wc_extcon_psy_desc = { 469 .name = "cht_wcove_pwrsrc", 470 .type = POWER_SUPPLY_TYPE_USB, 471 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | 472 BIT(POWER_SUPPLY_USB_TYPE_CDP) | 473 BIT(POWER_SUPPLY_USB_TYPE_DCP) | 474 BIT(POWER_SUPPLY_USB_TYPE_ACA) | 475 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), 476 .properties = cht_wc_extcon_psy_props, 477 .num_properties = ARRAY_SIZE(cht_wc_extcon_psy_props), 478 .get_property = cht_wc_extcon_psy_get_prop, 479 }; 480 481 static int cht_wc_extcon_register_psy(struct cht_wc_extcon_data *ext) 482 { 483 struct power_supply_config psy_cfg = { .drv_data = ext }; 484 485 ext->psy = devm_power_supply_register(ext->dev, 486 &cht_wc_extcon_psy_desc, 487 &psy_cfg); 488 return PTR_ERR_OR_ZERO(ext->psy); 489 } 490 491 static int cht_wc_extcon_probe(struct platform_device *pdev) 492 { 493 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 494 struct cht_wc_extcon_data *ext; 495 unsigned long mask = ~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_USBID_MASK); 496 int pwrsrc_sts, id; 497 int irq, ret; 498 499 irq = platform_get_irq(pdev, 0); 500 if (irq < 0) 501 return irq; 502 503 ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL); 504 if (!ext) 505 return -ENOMEM; 506 507 ext->dev = &pdev->dev; 508 ext->regmap = pmic->regmap; 509 ext->previous_cable = EXTCON_NONE; 510 511 /* Initialize extcon device */ 512 ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables); 513 if (IS_ERR(ext->edev)) 514 return PTR_ERR(ext->edev); 515 516 switch (pmic->cht_wc_model) { 517 case INTEL_CHT_WC_GPD_WIN_POCKET: 518 /* 519 * When a host-cable is detected the BIOS enables an external 5v boost 520 * converter to power connected devices there are 2 problems with this: 521 * 1) This gets seen by the external battery charger as a valid Vbus 522 * supply and it then tries to feed Vsys from this creating a 523 * feedback loop which causes aprox. 300 mA extra battery drain 524 * (and unless we drive the external-charger-disable pin high it 525 * also tries to charge the battery causing even more feedback). 526 * 2) This gets seen by the pwrsrc block as a SDP USB Vbus supply 527 * Since the external battery charger has its own 5v boost converter 528 * which does not have these issues, we simply turn the separate 529 * external 5v boost converter off and leave it off entirely. 530 */ 531 cht_wc_extcon_set_5v_boost(ext, false); 532 break; 533 case INTEL_CHT_WC_LENOVO_YOGABOOK1: 534 case INTEL_CHT_WC_LENOVO_YT3_X90: 535 /* Do this first, as it may very well return -EPROBE_DEFER. */ 536 ret = cht_wc_extcon_get_role_sw_and_regulator(ext); 537 if (ret) 538 return ret; 539 /* 540 * The bq25890 used here relies on this driver's BC-1.2 charger 541 * detection, and the bq25890 driver expect this info to be 542 * available through a parent power_supply class device which 543 * models the detected charger (idem to how the Type-C TCPM code 544 * registers a power_supply classdev for the connected charger). 545 */ 546 ret = cht_wc_extcon_register_psy(ext); 547 if (ret) 548 return ret; 549 break; 550 case INTEL_CHT_WC_XIAOMI_MIPAD2: 551 ret = cht_wc_extcon_get_role_sw_and_regulator(ext); 552 if (ret) 553 return ret; 554 break; 555 default: 556 break; 557 } 558 559 /* Enable sw control */ 560 ret = cht_wc_extcon_sw_control(ext, true); 561 if (ret) 562 goto disable_sw_control; 563 564 /* Disable charging by external battery charger */ 565 cht_wc_extcon_enable_charging(ext, false); 566 567 /* Register extcon device */ 568 ret = devm_extcon_dev_register(ext->dev, ext->edev); 569 if (ret) { 570 dev_err(ext->dev, "Error registering extcon device: %d\n", ret); 571 goto disable_sw_control; 572 } 573 574 ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); 575 if (ret) { 576 dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); 577 goto disable_sw_control; 578 } 579 580 /* 581 * If no USB host or device connected, route D+ and D- to PMIC for 582 * initial charger detection 583 */ 584 id = cht_wc_extcon_get_id(ext, pwrsrc_sts); 585 if (id != INTEL_USB_ID_GND) 586 cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC); 587 588 /* Get initial state */ 589 cht_wc_extcon_pwrsrc_event(ext); 590 591 ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr, 592 IRQF_ONESHOT, pdev->name, ext); 593 if (ret) { 594 dev_err(ext->dev, "Error requesting interrupt: %d\n", ret); 595 goto disable_sw_control; 596 } 597 598 /* Unmask irqs */ 599 ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, mask); 600 if (ret) { 601 dev_err(ext->dev, "Error writing irq-mask: %d\n", ret); 602 goto disable_sw_control; 603 } 604 605 platform_set_drvdata(pdev, ext); 606 607 return 0; 608 609 disable_sw_control: 610 cht_wc_extcon_sw_control(ext, false); 611 return ret; 612 } 613 614 static void cht_wc_extcon_remove(struct platform_device *pdev) 615 { 616 struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev); 617 618 cht_wc_extcon_sw_control(ext, false); 619 } 620 621 static const struct platform_device_id cht_wc_extcon_table[] = { 622 { .name = "cht_wcove_pwrsrc" }, 623 {}, 624 }; 625 MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table); 626 627 static struct platform_driver cht_wc_extcon_driver = { 628 .probe = cht_wc_extcon_probe, 629 .remove = cht_wc_extcon_remove, 630 .id_table = cht_wc_extcon_table, 631 .driver = { 632 .name = "cht_wcove_pwrsrc", 633 }, 634 }; 635 module_platform_driver(cht_wc_extcon_driver); 636 637 MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver"); 638 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 639 MODULE_LICENSE("GPL v2"); 640