// SPDX-License-Identifier: GPL-2.0-or-later /* * ON Semiconductor LC824206XA Micro USB Switch driver * * Copyright (c) 2024 Hans de Goede <hansg@kernel.org> * * ON Semiconductor has an "Advance Information" datasheet available * (ENA2222-D.PDF), but no full datasheet. So there is no documentation * available for the registers. * * This driver is based on the register info from the extcon-fsa9285.c driver, * from the Lollipop Android sources for the Lenovo Yoga Tablet 2 (Pro) * 830 / 1050 / 1380 models. Note despite the name this is actually a driver * for the LC824206XA not the FSA9285. The Android sources can be downloaded * from Lenovo's support page for these tablets, filename: * yoga_tab_2_osc_android_to_lollipop_201505.rar.
*/
/* * Register defines as mentioned above there is no datasheet with register * info, so this may not be 100% accurate.
*/ #define REG00 0x00 #define REG00_INIT_VALUE 0x01
/* Masks for all 3 interrupt registers */ #define INTR_ID_PIN_CHANGE BIT(0) #define INTR_VBUS_CHANGE BIT(1) /* Both of these get set after a continuous mode ADC conversion */ #define INTR_ID_PIN_ADC_INT1 BIT(2) #define INTR_ID_PIN_ADC_INT2 BIT(3) /* Charger type available in reg 0x09 */ #define INTR_CHARGER_DET_DONE BIT(4) #define INTR_OVP BIT(5)
/* There are 7 interrupt sources, bit 6 use is unknown (OCP?) */ #define INTR_ALL GENMASK(6, 0)
/* Unmask interrupts this driver cares about */ #define INTR_MASK \
(INTR_ALL & ~(INTR_ID_PIN_CHANGE | INTR_VBUS_CHANGE | INTR_CHARGER_DET_DONE))
/* Active (event happened and not cleared yet) interrupts */ #define REG_INTR_STATUS 0x04
/* * Writing a 1 to a bit here clears it in INTR_STATUS. These bits do NOT * auto-reset to 0, so these must be set to 0 manually after clearing.
*/ #define REG_INTR_CLEAR 0x05
/* Interrupts which bit is set to 1 here will not raise the HW IRQ */ #define REG_INTR_MASK 0x06
/* ID pin ADC control, meaning of individual bits is unknown */ #define REG_ID_PIN_ADC_CTRL 0x07 #define ID_PIN_ADC_AUTO 0x40 #define ID_PIN_ADC_CONTINUOUS 0x44
/* Read id pin ADC if necessary */ switch (status & STATUS_USB_ID) { case STATUS_USB_ID_GND: case STATUS_USB_ID_FLOAT: break; default: /* Happens when the connector is inserted slowly, log at dbg level */
dev_dbg(&data->client->dev, "Unknown status 0x%02x\n", status);
fallthrough; case STATUS_USB_ID_ACA:
id = lc824206xa_get_id(data);
dev_dbg(&data->client->dev, "RID 0x%02x\n", id); switch (id) { case 0x10:
status = STATUS_USB_ID_GND; break; case 0x18 ... 0x1e:
status = STATUS_USB_ID_ACA; break; case 0x1f:
status = STATUS_USB_ID_FLOAT; break; default:
dev_warn(&data->client->dev, "Unknown RID 0x%02x\n", id); return;
}
}
/* Check for out of spec OTG charging hubs, treat as ACA */ if ((status & STATUS_USB_ID) == STATUS_USB_ID_GND &&
data->vbus_ok && !data->vbus_boost_enabled) {
dev_info(&data->client->dev, "Out of spec USB host adapter with Vbus present, not enabling 5V output\n");
status = STATUS_USB_ID_ACA;
}
switch (status & STATUS_USB_ID) { case STATUS_USB_ID_ACA:
data->usb_type = POWER_SUPPLY_USB_TYPE_ACA;
data->cable = EXTCON_CHG_USB_ACA;
data->switch_control = SWITCH_USB_HOST; break; case STATUS_USB_ID_GND:
data->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
data->cable = EXTCON_USB_HOST;
data->switch_control = SWITCH_USB_HOST;
vbus_boost_enable = true; break; case STATUS_USB_ID_FLOAT: /* When fast charging with Vbus > 5V, OVP will be set */ if (data->fastcharge_over_miclr &&
data->switch_control == SWITCH_STEREO_MIC &&
(status & STATUS_OVP)) {
data->cable = EXTCON_CHG_USB_FAST; break;
}
/* * Newer charger (power_supply) drivers expect the max input current to be * provided by a parent power_supply device for the charger chip.
*/ staticint lc824206xa_psy_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{ struct lc824206xa_data *data = power_supply_get_drvdata(psy);
switch (psp) { case POWER_SUPPLY_PROP_ONLINE:
val->intval = data->vbus_ok && !data->vbus_boost_enabled; break; case POWER_SUPPLY_PROP_USB_TYPE:
val->intval = data->usb_type; break; case POWER_SUPPLY_PROP_CURRENT_MAX: switch (data->usb_type) { case POWER_SUPPLY_USB_TYPE_DCP: case POWER_SUPPLY_USB_TYPE_ACA:
val->intval = 2000000; break; case POWER_SUPPLY_USB_TYPE_CDP:
val->intval = 1500000; break; default:
val->intval = 500000;
} break; default: return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.