// SPDX-License-Identifier: GPL-2.0+ /* * Supports for the power IC on the Surface 3 tablet. * * (C) Copyright 2016-2018 Red Hat, Inc * (C) Copyright 2016-2018 Benjamin Tissoires <benjamin.tissoires@gmail.com> * (C) Copyright 2016 Stephen Just <stephenjust@gmail.com> * * This driver has been reverse-engineered by parsing the DSDT of the Surface 3 * and looking at the registers of the chips. * * The DSDT allowed to find out that: * - the driver is required for the ACPI BAT0 device to communicate to the chip * through an operation region. * - the various defines for the operation region functions to communicate with * this driver * - the DSM 3f99e367-6220-4955-8b0f-06ef2ae79412 allows to trigger ACPI * events to BAT0 (the code is all available in the DSDT). * * Further findings regarding the 2 chips declared in the MSHW0011 are: * - there are 2 chips declared: * . 0x22 seems to control the ADP1 line status (and probably the charger) * . 0x55 controls the battery directly * - the battery chip uses a SMBus protocol (using plain SMBus allows non * destructive commands): * . the commands/registers used are in the range 0x00..0x7F * . if bit 8 (0x80) is set in the SMBus command, the returned value is the * same as when it is not set. There is a high chance this bit is the * read/write * . the various registers semantic as been deduced by observing the register * dumps.
*/
/* get design capacity */
ret = i2c_smbus_read_word_data(client,
MSHW0011_BAT0_REG_DESIGN_CAPACITY); if (ret < 0) {
dev_err(&client->dev, "Error reading design capacity: %d\n",
ret); return ret;
}
bix->design_capacity = ret;
/* get last full charge capacity */
ret = i2c_smbus_read_word_data(client,
MSHW0011_BAT0_REG_FULL_CHG_CAPACITY); if (ret < 0) {
dev_err(&client->dev, "Error reading last full charge capacity: %d\n", ret); return ret;
}
bix->last_full_charg_capacity = ret;
/* * Get serial number, on some devices (with unofficial replacement * battery?) reading any of the serial number range addresses gets * nacked in this case just leave the serial number empty.
*/
ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_SERIAL_NO, sizeof(buf), buf); if (ret == -EREMOTEIO) { /* no serial number available */
} elseif (ret != sizeof(buf)) {
dev_err(&client->dev, "Error reading serial no: %d\n", ret); return ret;
} else {
snprintf(bix->serial, ARRAY_SIZE(bix->serial), "%3pE%6pE", buf + 7, buf);
}
/* get cycle count */
ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CYCLE_CNT); if (ret < 0) {
dev_err(&client->dev, "Error reading cycle count: %d\n", ret); return ret;
}
bix->cycle_count = ret;
/* get OEM name */
ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_OEM,
4, buf); if (ret != 4) {
dev_err(&client->dev, "Error reading cycle count: %d\n", ret); return ret;
}
snprintf(bix->OEM, ARRAY_SIZE(bix->OEM), "%3pE", buf);
ret = acpi_buffer_to_resource(info->connection, info->length, &ares); if (ACPI_FAILURE(ret)) return ret;
if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) {
ret = AE_BAD_PARAMETER; goto err;
}
if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {
ret = AE_BAD_PARAMETER; goto err;
}
if (gsb->cmd.arg0 == MSHW0011_CMD_DEST_ADP1 &&
gsb->cmd.arg1 == MSHW0011_CMD_ADP1_PSR) {
status = mshw0011_adp_psr(cdata); if (status >= 0) {
ret = AE_OK; goto out;
} else {
ret = AE_ERROR; goto err;
}
}
if (gsb->cmd.arg0 != MSHW0011_CMD_DEST_BAT0) {
ret = AE_BAD_PARAMETER; goto err;
}
switch (gsb->cmd.arg1) { case MSHW0011_CMD_BAT0_STA: break; case MSHW0011_CMD_BAT0_BIX:
ret = mshw0011_bix(cdata, &gsb->bix); break; case MSHW0011_CMD_BAT0_BTP:
cdata->trip_point = gsb->cmd.arg2; break; case MSHW0011_CMD_BAT0_BST:
ret = mshw0011_bst(cdata, &gsb->bst); break; default:
dev_info(&cdata->bat0->dev, "command(0x%02x) is not supported.\n", gsb->cmd.arg1);
ret = AE_BAD_PARAMETER; goto err;
}
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.