1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ISP1704 USB Charger Detection driver 4 * 5 * Copyright (C) 2010 Nokia Corporation 6 * Copyright (C) 2012 - 2013 Pali Rohár <pali.rohar@gmail.com> 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/err.h> 12 #include <linux/init.h> 13 #include <linux/types.h> 14 #include <linux/device.h> 15 #include <linux/sysfs.h> 16 #include <linux/platform_device.h> 17 #include <linux/power_supply.h> 18 #include <linux/delay.h> 19 #include <linux/of.h> 20 21 #include <linux/gpio/consumer.h> 22 #include <linux/usb/otg.h> 23 #include <linux/usb/ulpi.h> 24 #include <linux/usb/ch9.h> 25 #include <linux/usb/gadget.h> 26 27 /* Vendor specific Power Control register */ 28 #define ISP1704_PWR_CTRL 0x3d 29 #define ISP1704_PWR_CTRL_SWCTRL (1 << 0) 30 #define ISP1704_PWR_CTRL_DET_COMP (1 << 1) 31 #define ISP1704_PWR_CTRL_BVALID_RISE (1 << 2) 32 #define ISP1704_PWR_CTRL_BVALID_FALL (1 << 3) 33 #define ISP1704_PWR_CTRL_DP_WKPU_EN (1 << 4) 34 #define ISP1704_PWR_CTRL_VDAT_DET (1 << 5) 35 #define ISP1704_PWR_CTRL_DPVSRC_EN (1 << 6) 36 #define ISP1704_PWR_CTRL_HWDETECT (1 << 7) 37 38 #define NXP_VENDOR_ID 0x04cc 39 40 static u16 isp170x_id[] = { 41 0x1704, 42 0x1707, 43 }; 44 45 struct isp1704_charger { 46 struct device *dev; 47 struct power_supply *psy; 48 struct power_supply_desc psy_desc; 49 struct gpio_desc *enable_gpio; 50 struct usb_phy *phy; 51 struct notifier_block nb; 52 struct work_struct work; 53 54 /* properties */ 55 char model[8]; 56 unsigned present:1; 57 unsigned online:1; 58 unsigned current_max; 59 }; 60 61 static inline int isp1704_read(struct isp1704_charger *isp, u32 reg) 62 { 63 return usb_phy_io_read(isp->phy, reg); 64 } 65 66 static inline int isp1704_write(struct isp1704_charger *isp, u32 reg, u32 val) 67 { 68 return usb_phy_io_write(isp->phy, val, reg); 69 } 70 71 static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on) 72 { 73 gpiod_set_value(isp->enable_gpio, on); 74 } 75 76 /* 77 * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB 78 * chargers). 79 * 80 * REVISIT: The method is defined in Battery Charging Specification and is 81 * applicable to any ULPI transceiver. Nothing isp170x specific here. 82 */ 83 static inline int isp1704_charger_type(struct isp1704_charger *isp) 84 { 85 u8 reg; 86 u8 func_ctrl; 87 u8 otg_ctrl; 88 int type = POWER_SUPPLY_TYPE_USB_DCP; 89 90 func_ctrl = isp1704_read(isp, ULPI_FUNC_CTRL); 91 otg_ctrl = isp1704_read(isp, ULPI_OTG_CTRL); 92 93 /* disable pulldowns */ 94 reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN; 95 isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), reg); 96 97 /* full speed */ 98 isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL), 99 ULPI_FUNC_CTRL_XCVRSEL_MASK); 100 isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), 101 ULPI_FUNC_CTRL_FULL_SPEED); 102 103 /* Enable strong pull-up on DP (1.5K) and reset */ 104 reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET; 105 isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), reg); 106 usleep_range(1000, 2000); 107 108 reg = isp1704_read(isp, ULPI_DEBUG); 109 if ((reg & 3) != 3) 110 type = POWER_SUPPLY_TYPE_USB_CDP; 111 112 /* recover original state */ 113 isp1704_write(isp, ULPI_FUNC_CTRL, func_ctrl); 114 isp1704_write(isp, ULPI_OTG_CTRL, otg_ctrl); 115 116 return type; 117 } 118 119 /* 120 * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger 121 * is actually a dedicated charger, the following steps need to be taken. 122 */ 123 static inline int isp1704_charger_verify(struct isp1704_charger *isp) 124 { 125 int ret = 0; 126 u8 r; 127 128 /* Reset the transceiver */ 129 r = isp1704_read(isp, ULPI_FUNC_CTRL); 130 r |= ULPI_FUNC_CTRL_RESET; 131 isp1704_write(isp, ULPI_FUNC_CTRL, r); 132 usleep_range(1000, 2000); 133 134 /* Set normal mode */ 135 r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK); 136 isp1704_write(isp, ULPI_FUNC_CTRL, r); 137 138 /* Clear the DP and DM pull-down bits */ 139 r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN; 140 isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), r); 141 142 /* Enable strong pull-up on DP (1.5K) and reset */ 143 r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET; 144 isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), r); 145 usleep_range(1000, 2000); 146 147 /* Read the line state */ 148 if (!isp1704_read(isp, ULPI_DEBUG)) { 149 /* Disable strong pull-up on DP (1.5K) */ 150 isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL), 151 ULPI_FUNC_CTRL_TERMSELECT); 152 return 1; 153 } 154 155 /* Is it a charger or PS/2 connection */ 156 157 /* Enable weak pull-up resistor on DP */ 158 isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL), 159 ISP1704_PWR_CTRL_DP_WKPU_EN); 160 161 /* Disable strong pull-up on DP (1.5K) */ 162 isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL), 163 ULPI_FUNC_CTRL_TERMSELECT); 164 165 /* Enable weak pull-down resistor on DM */ 166 isp1704_write(isp, ULPI_SET(ULPI_OTG_CTRL), 167 ULPI_OTG_CTRL_DM_PULLDOWN); 168 169 /* It's a charger if the line states are clear */ 170 if (!(isp1704_read(isp, ULPI_DEBUG))) 171 ret = 1; 172 173 /* Disable weak pull-up resistor on DP */ 174 isp1704_write(isp, ULPI_CLR(ISP1704_PWR_CTRL), 175 ISP1704_PWR_CTRL_DP_WKPU_EN); 176 177 return ret; 178 } 179 180 static inline int isp1704_charger_detect(struct isp1704_charger *isp) 181 { 182 unsigned long timeout; 183 u8 pwr_ctrl; 184 int ret = 0; 185 186 pwr_ctrl = isp1704_read(isp, ISP1704_PWR_CTRL); 187 188 /* set SW control bit in PWR_CTRL register */ 189 isp1704_write(isp, ISP1704_PWR_CTRL, 190 ISP1704_PWR_CTRL_SWCTRL); 191 192 /* enable manual charger detection */ 193 isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL), 194 ISP1704_PWR_CTRL_SWCTRL 195 | ISP1704_PWR_CTRL_DPVSRC_EN); 196 usleep_range(1000, 2000); 197 198 timeout = jiffies + msecs_to_jiffies(300); 199 do { 200 /* Check if there is a charger */ 201 if (isp1704_read(isp, ISP1704_PWR_CTRL) 202 & ISP1704_PWR_CTRL_VDAT_DET) { 203 ret = isp1704_charger_verify(isp); 204 break; 205 } 206 } while (!time_after(jiffies, timeout) && isp->online); 207 208 /* recover original state */ 209 isp1704_write(isp, ISP1704_PWR_CTRL, pwr_ctrl); 210 211 return ret; 212 } 213 214 static inline int isp1704_charger_detect_dcp(struct isp1704_charger *isp) 215 { 216 if (isp1704_charger_detect(isp) && 217 isp1704_charger_type(isp) == POWER_SUPPLY_TYPE_USB_DCP) 218 return true; 219 else 220 return false; 221 } 222 223 static void isp1704_charger_work(struct work_struct *data) 224 { 225 struct isp1704_charger *isp = 226 container_of(data, struct isp1704_charger, work); 227 static DEFINE_MUTEX(lock); 228 229 mutex_lock(&lock); 230 231 switch (isp->phy->last_event) { 232 case USB_EVENT_VBUS: 233 /* do not call wall charger detection more times */ 234 if (!isp->present) { 235 isp->online = true; 236 isp->present = 1; 237 isp1704_charger_set_power(isp, 1); 238 239 /* detect wall charger */ 240 if (isp1704_charger_detect_dcp(isp)) { 241 isp->psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP; 242 isp->current_max = 1800; 243 } else { 244 isp->psy_desc.type = POWER_SUPPLY_TYPE_USB; 245 isp->current_max = 500; 246 } 247 248 /* enable data pullups */ 249 if (isp->phy->otg->gadget) 250 usb_gadget_connect(isp->phy->otg->gadget); 251 } 252 253 if (isp->psy_desc.type != POWER_SUPPLY_TYPE_USB_DCP) { 254 /* 255 * Only 500mA here or high speed chirp 256 * handshaking may break 257 */ 258 if (isp->current_max > 500) 259 isp->current_max = 500; 260 261 if (isp->current_max > 100) 262 isp->psy_desc.type = POWER_SUPPLY_TYPE_USB_CDP; 263 } 264 break; 265 case USB_EVENT_NONE: 266 isp->online = false; 267 isp->present = 0; 268 isp->current_max = 0; 269 isp->psy_desc.type = POWER_SUPPLY_TYPE_USB; 270 271 /* 272 * Disable data pullups. We need to prevent the controller from 273 * enumerating. 274 * 275 * FIXME: This is here to allow charger detection with Host/HUB 276 * chargers. The pullups may be enabled elsewhere, so this can 277 * not be the final solution. 278 */ 279 if (isp->phy->otg->gadget) 280 usb_gadget_disconnect(isp->phy->otg->gadget); 281 282 isp1704_charger_set_power(isp, 0); 283 break; 284 default: 285 goto out; 286 } 287 288 power_supply_changed(isp->psy); 289 out: 290 mutex_unlock(&lock); 291 } 292 293 static int isp1704_notifier_call(struct notifier_block *nb, 294 unsigned long val, void *v) 295 { 296 struct isp1704_charger *isp = 297 container_of(nb, struct isp1704_charger, nb); 298 299 schedule_work(&isp->work); 300 301 return NOTIFY_OK; 302 } 303 304 static int isp1704_charger_get_property(struct power_supply *psy, 305 enum power_supply_property psp, 306 union power_supply_propval *val) 307 { 308 struct isp1704_charger *isp = power_supply_get_drvdata(psy); 309 310 switch (psp) { 311 case POWER_SUPPLY_PROP_PRESENT: 312 val->intval = isp->present; 313 break; 314 case POWER_SUPPLY_PROP_ONLINE: 315 val->intval = isp->online; 316 break; 317 case POWER_SUPPLY_PROP_CURRENT_MAX: 318 val->intval = isp->current_max; 319 break; 320 case POWER_SUPPLY_PROP_MODEL_NAME: 321 val->strval = isp->model; 322 break; 323 case POWER_SUPPLY_PROP_MANUFACTURER: 324 val->strval = "NXP"; 325 break; 326 default: 327 return -EINVAL; 328 } 329 return 0; 330 } 331 332 static enum power_supply_property power_props[] = { 333 POWER_SUPPLY_PROP_PRESENT, 334 POWER_SUPPLY_PROP_ONLINE, 335 POWER_SUPPLY_PROP_CURRENT_MAX, 336 POWER_SUPPLY_PROP_MODEL_NAME, 337 POWER_SUPPLY_PROP_MANUFACTURER, 338 }; 339 340 static inline int isp1704_test_ulpi(struct isp1704_charger *isp) 341 { 342 int vendor; 343 int product; 344 int i; 345 int ret = -ENODEV; 346 347 /* Test ULPI interface */ 348 ret = isp1704_write(isp, ULPI_SCRATCH, 0xaa); 349 if (ret < 0) 350 return ret; 351 352 ret = isp1704_read(isp, ULPI_SCRATCH); 353 if (ret < 0) 354 return ret; 355 356 if (ret != 0xaa) 357 return -ENODEV; 358 359 /* Verify the product and vendor id matches */ 360 vendor = isp1704_read(isp, ULPI_VENDOR_ID_LOW); 361 vendor |= isp1704_read(isp, ULPI_VENDOR_ID_HIGH) << 8; 362 if (vendor != NXP_VENDOR_ID) 363 return -ENODEV; 364 365 product = isp1704_read(isp, ULPI_PRODUCT_ID_LOW); 366 product |= isp1704_read(isp, ULPI_PRODUCT_ID_HIGH) << 8; 367 368 for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) { 369 if (product == isp170x_id[i]) { 370 sprintf(isp->model, "isp%x", product); 371 return product; 372 } 373 } 374 375 dev_err(isp->dev, "product id %x not matching known ids", product); 376 377 return -ENODEV; 378 } 379 380 static int isp1704_charger_probe(struct platform_device *pdev) 381 { 382 struct isp1704_charger *isp; 383 int ret = -ENODEV; 384 struct power_supply_config psy_cfg = {}; 385 386 isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); 387 if (!isp) 388 return -ENOMEM; 389 390 isp->enable_gpio = devm_gpiod_get(&pdev->dev, "nxp,enable", 391 GPIOD_OUT_HIGH); 392 if (IS_ERR(isp->enable_gpio)) { 393 ret = PTR_ERR(isp->enable_gpio); 394 dev_err(&pdev->dev, "Could not get reset gpio: %d\n", ret); 395 return ret; 396 } 397 398 if (pdev->dev.of_node) 399 isp->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); 400 else 401 isp->phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 402 403 if (IS_ERR(isp->phy)) { 404 ret = PTR_ERR(isp->phy); 405 dev_err(&pdev->dev, "usb_get_phy failed\n"); 406 goto fail0; 407 } 408 409 isp->dev = &pdev->dev; 410 platform_set_drvdata(pdev, isp); 411 412 isp1704_charger_set_power(isp, 1); 413 414 ret = isp1704_test_ulpi(isp); 415 if (ret < 0) { 416 dev_err(&pdev->dev, "isp1704_test_ulpi failed\n"); 417 goto fail1; 418 } 419 420 isp->psy_desc.name = "isp1704"; 421 isp->psy_desc.type = POWER_SUPPLY_TYPE_USB; 422 isp->psy_desc.properties = power_props; 423 isp->psy_desc.num_properties = ARRAY_SIZE(power_props); 424 isp->psy_desc.get_property = isp1704_charger_get_property; 425 426 psy_cfg.drv_data = isp; 427 428 isp->psy = power_supply_register(isp->dev, &isp->psy_desc, &psy_cfg); 429 if (IS_ERR(isp->psy)) { 430 ret = PTR_ERR(isp->psy); 431 dev_err(&pdev->dev, "power_supply_register failed\n"); 432 goto fail1; 433 } 434 435 /* 436 * REVISIT: using work in order to allow the usb notifications to be 437 * made atomically in the future. 438 */ 439 INIT_WORK(&isp->work, isp1704_charger_work); 440 441 isp->nb.notifier_call = isp1704_notifier_call; 442 443 ret = usb_register_notifier(isp->phy, &isp->nb); 444 if (ret) { 445 dev_err(&pdev->dev, "usb_register_notifier failed\n"); 446 goto fail2; 447 } 448 449 dev_info(isp->dev, "registered with product id %s\n", isp->model); 450 451 /* 452 * Taking over the D+ pullup. 453 * 454 * FIXME: The device will be disconnected if it was already 455 * enumerated. The charger driver should be always loaded before any 456 * gadget is loaded. 457 */ 458 if (isp->phy->otg->gadget) 459 usb_gadget_disconnect(isp->phy->otg->gadget); 460 461 if (isp->phy->last_event == USB_EVENT_NONE) 462 isp1704_charger_set_power(isp, 0); 463 464 /* Detect charger if VBUS is valid (the cable was already plugged). */ 465 if (isp->phy->last_event == USB_EVENT_VBUS && 466 !isp->phy->otg->default_a) 467 schedule_work(&isp->work); 468 469 return 0; 470 fail2: 471 power_supply_unregister(isp->psy); 472 fail1: 473 isp1704_charger_set_power(isp, 0); 474 fail0: 475 dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); 476 477 return ret; 478 } 479 480 static int isp1704_charger_remove(struct platform_device *pdev) 481 { 482 struct isp1704_charger *isp = platform_get_drvdata(pdev); 483 484 usb_unregister_notifier(isp->phy, &isp->nb); 485 power_supply_unregister(isp->psy); 486 isp1704_charger_set_power(isp, 0); 487 488 return 0; 489 } 490 491 #ifdef CONFIG_OF 492 static const struct of_device_id omap_isp1704_of_match[] = { 493 { .compatible = "nxp,isp1704", }, 494 { .compatible = "nxp,isp1707", }, 495 {}, 496 }; 497 MODULE_DEVICE_TABLE(of, omap_isp1704_of_match); 498 #endif 499 500 static struct platform_driver isp1704_charger_driver = { 501 .driver = { 502 .name = "isp1704_charger", 503 .of_match_table = of_match_ptr(omap_isp1704_of_match), 504 }, 505 .probe = isp1704_charger_probe, 506 .remove = isp1704_charger_remove, 507 }; 508 509 module_platform_driver(isp1704_charger_driver); 510 511 MODULE_ALIAS("platform:isp1704_charger"); 512 MODULE_AUTHOR("Nokia Corporation"); 513 MODULE_DESCRIPTION("ISP170x USB Charger driver"); 514 MODULE_LICENSE("GPL"); 515