1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ON Semiconductor LC824206XA Micro USB Switch driver 4 * 5 * Copyright (c) 2024 Hans de Goede <hansg@kernel.org> 6 * 7 * ON Semiconductor has an "Advance Information" datasheet available 8 * (ENA2222-D.PDF), but no full datasheet. So there is no documentation 9 * available for the registers. 10 * 11 * This driver is based on the register info from the extcon-fsa9285.c driver, 12 * from the Lollipop Android sources for the Lenovo Yoga Tablet 2 (Pro) 13 * 830 / 1050 / 1380 models. Note despite the name this is actually a driver 14 * for the LC824206XA not the FSA9285. The Android sources can be downloaded 15 * from Lenovo's support page for these tablets, filename: 16 * yoga_tab_2_osc_android_to_lollipop_201505.rar. 17 */ 18 19 #include <linux/bits.h> 20 #include <linux/delay.h> 21 #include <linux/device.h> 22 #include <linux/extcon-provider.h> 23 #include <linux/i2c.h> 24 #include <linux/interrupt.h> 25 #include <linux/module.h> 26 #include <linux/power_supply.h> 27 #include <linux/property.h> 28 #include <linux/regulator/consumer.h> 29 #include <linux/workqueue.h> 30 31 /* 32 * Register defines as mentioned above there is no datasheet with register 33 * info, so this may not be 100% accurate. 34 */ 35 #define REG00 0x00 36 #define REG00_INIT_VALUE 0x01 37 38 #define REG_STATUS 0x01 39 #define STATUS_OVP BIT(0) 40 #define STATUS_DATA_SHORT BIT(1) 41 #define STATUS_VBUS_PRESENT BIT(2) 42 #define STATUS_USB_ID GENMASK(7, 3) 43 #define STATUS_USB_ID_GND 0x80 44 #define STATUS_USB_ID_ACA 0xf0 45 #define STATUS_USB_ID_FLOAT 0xf8 46 47 /* 48 * This controls the DP/DM muxes + other switches, 49 * meaning of individual bits is unknown. 50 */ 51 #define REG_SWITCH_CONTROL 0x02 52 #define SWITCH_STEREO_MIC 0xc8 53 #define SWITCH_USB_HOST 0xec 54 #define SWITCH_DISCONNECTED 0xf8 55 #define SWITCH_USB_DEVICE 0xfc 56 57 /* 5 bits? ADC 0x10 GND, 0x1a-0x1f ACA, 0x1f float */ 58 #define REG_ID_PIN_ADC_VALUE 0x03 59 60 /* Masks for all 3 interrupt registers */ 61 #define INTR_ID_PIN_CHANGE BIT(0) 62 #define INTR_VBUS_CHANGE BIT(1) 63 /* Both of these get set after a continuous mode ADC conversion */ 64 #define INTR_ID_PIN_ADC_INT1 BIT(2) 65 #define INTR_ID_PIN_ADC_INT2 BIT(3) 66 /* Charger type available in reg 0x09 */ 67 #define INTR_CHARGER_DET_DONE BIT(4) 68 #define INTR_OVP BIT(5) 69 70 /* There are 7 interrupt sources, bit 6 use is unknown (OCP?) */ 71 #define INTR_ALL GENMASK(6, 0) 72 73 /* Unmask interrupts this driver cares about */ 74 #define INTR_MASK \ 75 (INTR_ALL & ~(INTR_ID_PIN_CHANGE | INTR_VBUS_CHANGE | INTR_CHARGER_DET_DONE)) 76 77 /* Active (event happened and not cleared yet) interrupts */ 78 #define REG_INTR_STATUS 0x04 79 80 /* 81 * Writing a 1 to a bit here clears it in INTR_STATUS. These bits do NOT 82 * auto-reset to 0, so these must be set to 0 manually after clearing. 83 */ 84 #define REG_INTR_CLEAR 0x05 85 86 /* Interrupts which bit is set to 1 here will not raise the HW IRQ */ 87 #define REG_INTR_MASK 0x06 88 89 /* ID pin ADC control, meaning of individual bits is unknown */ 90 #define REG_ID_PIN_ADC_CTRL 0x07 91 #define ID_PIN_ADC_AUTO 0x40 92 #define ID_PIN_ADC_CONTINUOUS 0x44 93 94 #define REG_CHARGER_DET 0x08 95 #define CHARGER_DET_ON BIT(0) 96 #define CHARGER_DET_CDP_ON BIT(1) 97 #define CHARGER_DET_CDP_VAL BIT(2) 98 99 #define REG_CHARGER_TYPE 0x09 100 #define CHARGER_TYPE_UNKNOWN 0x00 101 #define CHARGER_TYPE_DCP 0x01 102 #define CHARGER_TYPE_SDP_OR_CDP 0x04 103 #define CHARGER_TYPE_QC 0x06 104 105 #define REG10 0x10 106 #define REG10_INIT_VALUE 0x00 107 108 struct lc824206xa_data { 109 struct work_struct work; 110 struct i2c_client *client; 111 struct extcon_dev *edev; 112 struct power_supply *psy; 113 struct regulator *vbus_boost; 114 unsigned int usb_type; 115 unsigned int cable; 116 unsigned int previous_cable; 117 u8 switch_control; 118 u8 previous_switch_control; 119 bool vbus_ok; 120 bool vbus_boost_enabled; 121 bool fastcharge_over_miclr; 122 }; 123 124 static const unsigned int lc824206xa_cables[] = { 125 EXTCON_USB_HOST, 126 EXTCON_CHG_USB_SDP, 127 EXTCON_CHG_USB_CDP, 128 EXTCON_CHG_USB_DCP, 129 EXTCON_CHG_USB_ACA, 130 EXTCON_CHG_USB_FAST, 131 EXTCON_NONE, 132 }; 133 134 /* read/write reg helpers to add error logging to smbus byte functions */ 135 static int lc824206xa_read_reg(struct lc824206xa_data *data, u8 reg) 136 { 137 int ret; 138 139 ret = i2c_smbus_read_byte_data(data->client, reg); 140 if (ret < 0) 141 dev_err(&data->client->dev, "Error %d reading reg 0x%02x\n", ret, reg); 142 143 return ret; 144 } 145 146 static int lc824206xa_write_reg(struct lc824206xa_data *data, u8 reg, u8 val) 147 { 148 int ret; 149 150 ret = i2c_smbus_write_byte_data(data->client, reg, val); 151 if (ret < 0) 152 dev_err(&data->client->dev, "Error %d writing reg 0x%02x\n", ret, reg); 153 154 return ret; 155 } 156 157 static int lc824206xa_get_id(struct lc824206xa_data *data) 158 { 159 int ret; 160 161 ret = lc824206xa_write_reg(data, REG_ID_PIN_ADC_CTRL, ID_PIN_ADC_CONTINUOUS); 162 if (ret) 163 return ret; 164 165 ret = lc824206xa_read_reg(data, REG_ID_PIN_ADC_VALUE); 166 167 lc824206xa_write_reg(data, REG_ID_PIN_ADC_CTRL, ID_PIN_ADC_AUTO); 168 169 return ret; 170 } 171 172 static void lc824206xa_set_vbus_boost(struct lc824206xa_data *data, bool enable) 173 { 174 int ret; 175 176 if (data->vbus_boost_enabled == enable) 177 return; 178 179 if (enable) 180 ret = regulator_enable(data->vbus_boost); 181 else 182 ret = regulator_disable(data->vbus_boost); 183 184 if (ret == 0) 185 data->vbus_boost_enabled = enable; 186 else 187 dev_err(&data->client->dev, "Error updating Vbus boost regulator: %d\n", ret); 188 } 189 190 static void lc824206xa_charger_detect(struct lc824206xa_data *data) 191 { 192 int charger_type, ret; 193 194 charger_type = lc824206xa_read_reg(data, REG_CHARGER_TYPE); 195 if (charger_type < 0) 196 return; 197 198 dev_dbg(&data->client->dev, "charger type 0x%02x\n", charger_type); 199 200 switch (charger_type) { 201 case CHARGER_TYPE_UNKNOWN: 202 data->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 203 /* Treat as SDP */ 204 data->cable = EXTCON_CHG_USB_SDP; 205 data->switch_control = SWITCH_USB_DEVICE; 206 break; 207 case CHARGER_TYPE_SDP_OR_CDP: 208 data->usb_type = POWER_SUPPLY_USB_TYPE_SDP; 209 data->cable = EXTCON_CHG_USB_SDP; 210 data->switch_control = SWITCH_USB_DEVICE; 211 212 ret = lc824206xa_write_reg(data, REG_CHARGER_DET, 213 CHARGER_DET_CDP_ON | CHARGER_DET_ON); 214 if (ret < 0) 215 break; 216 217 msleep(100); 218 ret = lc824206xa_read_reg(data, REG_CHARGER_DET); 219 if (ret >= 0 && (ret & CHARGER_DET_CDP_VAL)) { 220 data->usb_type = POWER_SUPPLY_USB_TYPE_CDP; 221 data->cable = EXTCON_CHG_USB_CDP; 222 } 223 224 lc824206xa_write_reg(data, REG_CHARGER_DET, CHARGER_DET_ON); 225 break; 226 case CHARGER_TYPE_DCP: 227 data->usb_type = POWER_SUPPLY_USB_TYPE_DCP; 228 data->cable = EXTCON_CHG_USB_DCP; 229 if (data->fastcharge_over_miclr) 230 data->switch_control = SWITCH_STEREO_MIC; 231 else 232 data->switch_control = SWITCH_DISCONNECTED; 233 break; 234 case CHARGER_TYPE_QC: 235 data->usb_type = POWER_SUPPLY_USB_TYPE_DCP; 236 data->cable = EXTCON_CHG_USB_DCP; 237 data->switch_control = SWITCH_DISCONNECTED; 238 break; 239 default: 240 dev_warn(&data->client->dev, "Unknown charger type: 0x%02x\n", charger_type); 241 break; 242 } 243 } 244 245 static void lc824206xa_work(struct work_struct *work) 246 { 247 struct lc824206xa_data *data = container_of(work, struct lc824206xa_data, work); 248 bool vbus_boost_enable = false; 249 int status, id; 250 251 status = lc824206xa_read_reg(data, REG_STATUS); 252 if (status < 0) 253 return; 254 255 dev_dbg(&data->client->dev, "status 0x%02x\n", status); 256 257 data->vbus_ok = (status & (STATUS_VBUS_PRESENT | STATUS_OVP)) == STATUS_VBUS_PRESENT; 258 259 /* Read id pin ADC if necessary */ 260 switch (status & STATUS_USB_ID) { 261 case STATUS_USB_ID_GND: 262 case STATUS_USB_ID_FLOAT: 263 break; 264 default: 265 /* Happens when the connector is inserted slowly, log at dbg level */ 266 dev_dbg(&data->client->dev, "Unknown status 0x%02x\n", status); 267 fallthrough; 268 case STATUS_USB_ID_ACA: 269 id = lc824206xa_get_id(data); 270 dev_dbg(&data->client->dev, "RID 0x%02x\n", id); 271 switch (id) { 272 case 0x10: 273 status = STATUS_USB_ID_GND; 274 break; 275 case 0x18 ... 0x1e: 276 status = STATUS_USB_ID_ACA; 277 break; 278 case 0x1f: 279 status = STATUS_USB_ID_FLOAT; 280 break; 281 default: 282 dev_warn(&data->client->dev, "Unknown RID 0x%02x\n", id); 283 return; 284 } 285 } 286 287 /* Check for out of spec OTG charging hubs, treat as ACA */ 288 if ((status & STATUS_USB_ID) == STATUS_USB_ID_GND && 289 data->vbus_ok && !data->vbus_boost_enabled) { 290 dev_info(&data->client->dev, "Out of spec USB host adapter with Vbus present, not enabling 5V output\n"); 291 status = STATUS_USB_ID_ACA; 292 } 293 294 switch (status & STATUS_USB_ID) { 295 case STATUS_USB_ID_ACA: 296 data->usb_type = POWER_SUPPLY_USB_TYPE_ACA; 297 data->cable = EXTCON_CHG_USB_ACA; 298 data->switch_control = SWITCH_USB_HOST; 299 break; 300 case STATUS_USB_ID_GND: 301 data->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 302 data->cable = EXTCON_USB_HOST; 303 data->switch_control = SWITCH_USB_HOST; 304 vbus_boost_enable = true; 305 break; 306 case STATUS_USB_ID_FLOAT: 307 /* When fast charging with Vbus > 5V, OVP will be set */ 308 if (data->fastcharge_over_miclr && 309 data->switch_control == SWITCH_STEREO_MIC && 310 (status & STATUS_OVP)) { 311 data->cable = EXTCON_CHG_USB_FAST; 312 break; 313 } 314 315 if (data->vbus_ok) { 316 lc824206xa_charger_detect(data); 317 } else { 318 data->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 319 data->cable = EXTCON_NONE; 320 data->switch_control = SWITCH_DISCONNECTED; 321 } 322 break; 323 } 324 325 lc824206xa_set_vbus_boost(data, vbus_boost_enable); 326 327 if (data->switch_control != data->previous_switch_control) { 328 lc824206xa_write_reg(data, REG_SWITCH_CONTROL, data->switch_control); 329 data->previous_switch_control = data->switch_control; 330 } 331 332 if (data->cable != data->previous_cable) { 333 extcon_set_state_sync(data->edev, data->previous_cable, false); 334 extcon_set_state_sync(data->edev, data->cable, true); 335 data->previous_cable = data->cable; 336 } 337 338 power_supply_changed(data->psy); 339 } 340 341 static irqreturn_t lc824206xa_irq(int irq, void *_data) 342 { 343 struct lc824206xa_data *data = _data; 344 int intr_status; 345 346 intr_status = lc824206xa_read_reg(data, REG_INTR_STATUS); 347 if (intr_status < 0) 348 intr_status = INTR_ALL; /* Should never happen, clear all */ 349 350 dev_dbg(&data->client->dev, "interrupt 0x%02x\n", intr_status); 351 352 lc824206xa_write_reg(data, REG_INTR_CLEAR, intr_status); 353 lc824206xa_write_reg(data, REG_INTR_CLEAR, 0); 354 355 schedule_work(&data->work); 356 return IRQ_HANDLED; 357 } 358 359 /* 360 * Newer charger (power_supply) drivers expect the max input current to be 361 * provided by a parent power_supply device for the charger chip. 362 */ 363 static int lc824206xa_psy_get_prop(struct power_supply *psy, 364 enum power_supply_property psp, 365 union power_supply_propval *val) 366 { 367 struct lc824206xa_data *data = power_supply_get_drvdata(psy); 368 369 switch (psp) { 370 case POWER_SUPPLY_PROP_ONLINE: 371 val->intval = data->vbus_ok && !data->vbus_boost_enabled; 372 break; 373 case POWER_SUPPLY_PROP_USB_TYPE: 374 val->intval = data->usb_type; 375 break; 376 case POWER_SUPPLY_PROP_CURRENT_MAX: 377 switch (data->usb_type) { 378 case POWER_SUPPLY_USB_TYPE_DCP: 379 case POWER_SUPPLY_USB_TYPE_ACA: 380 val->intval = 2000000; 381 break; 382 case POWER_SUPPLY_USB_TYPE_CDP: 383 val->intval = 1500000; 384 break; 385 default: 386 val->intval = 500000; 387 } 388 break; 389 default: 390 return -EINVAL; 391 } 392 393 return 0; 394 } 395 396 static const enum power_supply_property lc824206xa_psy_props[] = { 397 POWER_SUPPLY_PROP_ONLINE, 398 POWER_SUPPLY_PROP_USB_TYPE, 399 POWER_SUPPLY_PROP_CURRENT_MAX, 400 }; 401 402 static const struct power_supply_desc lc824206xa_psy_desc = { 403 .name = "lc824206xa-charger-detect", 404 .type = POWER_SUPPLY_TYPE_USB, 405 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | 406 BIT(POWER_SUPPLY_USB_TYPE_CDP) | 407 BIT(POWER_SUPPLY_USB_TYPE_DCP) | 408 BIT(POWER_SUPPLY_USB_TYPE_ACA) | 409 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), 410 .properties = lc824206xa_psy_props, 411 .num_properties = ARRAY_SIZE(lc824206xa_psy_props), 412 .get_property = lc824206xa_psy_get_prop, 413 }; 414 415 static int lc824206xa_probe(struct i2c_client *client) 416 { 417 struct power_supply_config psy_cfg = { }; 418 struct device *dev = &client->dev; 419 struct lc824206xa_data *data; 420 int ret; 421 422 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 423 if (!data) 424 return -ENOMEM; 425 426 data->client = client; 427 INIT_WORK(&data->work, lc824206xa_work); 428 data->cable = EXTCON_NONE; 429 data->previous_cable = EXTCON_NONE; 430 data->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 431 /* Some designs use a custom fast-charge protocol over the mic L/R inputs */ 432 data->fastcharge_over_miclr = 433 device_property_read_bool(dev, "onnn,enable-miclr-for-dcp"); 434 435 data->vbus_boost = devm_regulator_get(dev, "vbus"); 436 if (IS_ERR(data->vbus_boost)) 437 return dev_err_probe(dev, PTR_ERR(data->vbus_boost), 438 "getting regulator\n"); 439 440 /* Init */ 441 ret = lc824206xa_write_reg(data, REG00, REG00_INIT_VALUE); 442 ret |= lc824206xa_write_reg(data, REG10, REG10_INIT_VALUE); 443 msleep(100); 444 ret |= lc824206xa_write_reg(data, REG_INTR_CLEAR, INTR_ALL); 445 ret |= lc824206xa_write_reg(data, REG_INTR_CLEAR, 0); 446 ret |= lc824206xa_write_reg(data, REG_INTR_MASK, INTR_MASK); 447 ret |= lc824206xa_write_reg(data, REG_ID_PIN_ADC_CTRL, ID_PIN_ADC_AUTO); 448 ret |= lc824206xa_write_reg(data, REG_CHARGER_DET, CHARGER_DET_ON); 449 if (ret) 450 return -EIO; 451 452 /* Initialize extcon device */ 453 data->edev = devm_extcon_dev_allocate(dev, lc824206xa_cables); 454 if (IS_ERR(data->edev)) 455 return PTR_ERR(data->edev); 456 457 ret = devm_extcon_dev_register(dev, data->edev); 458 if (ret) 459 return dev_err_probe(dev, ret, "registering extcon device\n"); 460 461 psy_cfg.drv_data = data; 462 data->psy = devm_power_supply_register(dev, &lc824206xa_psy_desc, &psy_cfg); 463 if (IS_ERR(data->psy)) 464 return dev_err_probe(dev, PTR_ERR(data->psy), "registering power supply\n"); 465 466 ret = devm_request_threaded_irq(dev, client->irq, NULL, lc824206xa_irq, 467 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 468 KBUILD_MODNAME, data); 469 if (ret) 470 return dev_err_probe(dev, ret, "requesting IRQ\n"); 471 472 /* Sync initial state */ 473 schedule_work(&data->work); 474 return 0; 475 } 476 477 static const struct i2c_device_id lc824206xa_i2c_ids[] = { 478 { "lc824206xa" }, 479 { } 480 }; 481 MODULE_DEVICE_TABLE(i2c, lc824206xa_i2c_ids); 482 483 static struct i2c_driver lc824206xa_driver = { 484 .driver = { 485 .name = KBUILD_MODNAME, 486 }, 487 .probe = lc824206xa_probe, 488 .id_table = lc824206xa_i2c_ids, 489 }; 490 491 module_i2c_driver(lc824206xa_driver); 492 493 MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 494 MODULE_DESCRIPTION("LC824206XA Micro USB Switch driver"); 495 MODULE_LICENSE("GPL"); 496