// SPDX-License-Identifier: GPL-2.0-or-later /* * Intel CHT Whiskey Cove PMIC I2C controller driver * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> * * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: * Copyright (C) 2011 - 2014 Intel Corporation. All rights reserved.
*/
/* Reads must be acked after reading the received data. */
ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, &adap->read_data); if (ret)
adap->io_error = true;
/* * Immediately ack IRQs, so that if new IRQs arrives while we're * handling the previous ones our irq will re-trigger when we're done.
*/
ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg); if (ret)
dev_err(&adap->adapter.dev, "Error writing extchgrirq reg\n");
if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK)
wake_up(&adap->wait);
/* * Do NOT use handle_nested_irq here, the client irq handler will * likely want to do i2c transfers and the i2c controller uses this * interrupt handler as well, so running the client irq handler from * this thread will cause things to lock up.
*/ if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ)
generic_handle_irq_safe(adap->client_irq);
return IRQ_HANDLED;
}
static u32 cht_wc_i2c_adap_func(struct i2c_adapter *adap)
{ /* This i2c adapter only supports SMBUS byte transfers */ return I2C_FUNC_SMBUS_BYTE_DATA;
}
staticint cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr, unsignedshort flags, char read_write,
u8 command, int size, union i2c_smbus_data *data)
{ struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap); int ret;
ret = regmap_write(adap->regmap, CHT_WC_I2C_CLIENT_ADDR, addr); if (ret) return ret;
if (read_write == I2C_SMBUS_WRITE) {
ret = regmap_write(adap->regmap, CHT_WC_I2C_WRDATA, data->byte); if (ret) return ret;
}
ret = regmap_write(adap->regmap, CHT_WC_I2C_REG_OFFSET, command); if (ret) return ret;
ret = regmap_write(adap->regmap, CHT_WC_I2C_CTRL,
(read_write == I2C_SMBUS_WRITE) ?
CHT_WC_I2C_CTRL_WR : CHT_WC_I2C_CTRL_RD); if (ret) return ret;
ret = wait_event_timeout(adap->wait, adap->done, msecs_to_jiffies(30)); if (ret == 0) { /* * The CHT GPIO controller serializes all IRQs, sometimes * causing significant delays, check status manually.
*/
cht_wc_i2c_adap_thread_handler(0, adap); if (!adap->done) return -ETIMEDOUT;
}
ret = 0;
mutex_lock(&adap->adap_lock); if (adap->io_error)
ret = -EIO; elseif (read_write == I2C_SMBUS_READ)
data->byte = adap->read_data;
mutex_unlock(&adap->adap_lock);
/* * We are an i2c-adapter which itself is part of an i2c-client. This means that * transfers done through us take adapter->bus_lock twice, once for our parent * i2c-adapter and once to take our own bus_lock. Lockdep does not like this * nested locking, to make lockdep happy in the case of busses with muxes, the * i2c-core's i2c_adapter_lock_bus function calls: * rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter)); * * But i2c_adapter_depth only works when the direct parent of the adapter is * another adapter, as it is only meant for muxes. In our case there is an * i2c-client and MFD instantiated platform_device in the parent->child chain * between the 2 devices. * * So we override the default i2c_lock_operations and pass a hardcoded * depth of 1 to rt_mutex_lock_nested, to make lockdep happy. * * Note that if there were to be a mux attached to our adapter, this would * break things again since the i2c-mux code expects the root-adapter to have * a locking depth of 0. But we always have only 1 client directly attached * in the form of the Charger IC paired with the CHT Whiskey Cove PMIC.
*/ staticvoid cht_wc_i2c_adap_lock_bus(struct i2c_adapter *adapter, unsignedint flags)
{
rt_mutex_lock_nested(&adapter->bus_lock, 1);
}
staticstruct regulator_consumer_supply fusb302_consumer = {
.supply = "vbus", /* Must match fusb302 dev_name in intel_cht_int33fe.c */
.dev_name = "i2c-fusb302",
};
staticconststruct regulator_init_data bq24190_vbus_init_data = {
.constraints = { /* The name is used in intel_cht_int33fe.c do not change. */
.name = "cht_wc_usb_typec_vbus",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.consumer_supplies = &fusb302_consumer,
.num_consumer_supplies = 1,
};
staticconststruct property_entry lenovo_yb1_bq25892_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from",
lenovo_yb1_bq25892_suppliers),
PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000),
PROPERTY_ENTRY_BOOL("linux,skip-reset"), /* * The firmware sets everything to the defaults, which leads to a * somewhat low charge-current of 2048mA and worse to a battery-voltage * of 4.2V instead of 4.35V (when booted without a charger connected). * Use our own values instead of "linux,read-back-settings" to fix this.
*/
PROPERTY_ENTRY_U32("ti,charge-current", 4224000),
PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
PROPERTY_ENTRY_U32("ti,termination-current", 256000),
PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3500000),
PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
PROPERTY_ENTRY_U32("ti,boost-max-current", 1400000),
PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
{ }
};
/* * bq25892 charger settings for the round li-ion cells in the hinge, * this is the main / biggest battery.
*/ staticconststruct property_entry lenovo_yt3_bq25892_1_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_1_suppliers),
PROPERTY_ENTRY_STRING("linux,secondary-charger-name", "bq25890-charger-0"),
PROPERTY_ENTRY_U32("linux,iinlim-percentage", 60),
PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000),
PROPERTY_ENTRY_BOOL("linux,skip-reset"), /* * The firmware sets everything to the defaults, leading to a low(ish) * charge-current and battery-voltage of 2048mA resp 4.2V. Use the * Android values instead of "linux,read-back-settings" to fix this.
*/
PROPERTY_ENTRY_U32("ti,charge-current", 3072000),
PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
PROPERTY_ENTRY_U32("ti,termination-current", 128000),
PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000),
PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"), /* Set 5V boost current-limit to 1.2A (MAX/POR values are 2.45A/1.4A) */
PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
PROPERTY_ENTRY_U32("ti,boost-max-current", 1200000),
{ }
};
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.