On Jun 30 2017 or thereabouts, Hans de Goede wrote: > Hi, > > On 29-06-17 16:22, Andy Shevchenko wrote: > > +Cc: Hans (he might give some advice regarding to the below) > > Thank you for the Cc, so here we have the opposite situation as > with the devices with the AXP288 PMIC and the Cherry Trail > Whiskey Cove PMIC combined with the TI bq24292i charger and max17042 > fuel-gauge. In those cases we have well working native drivers > for the used chips and we don't know the API of the custom ACPI > OpRegion the ACPI battery and ac interface implementing ACPI nodes > want. So for these devices we've disabled the ACPI battery and > ac drivers and are using power_supply drivers for the used chips > directly. > > Here we've a similar setup where the ACPI nodes implementing the > ACPI battery and ac interfaces require a custom OpRegion, but > Benjamin has more or less figured out what the expected Opregion > API is (and implemented it) and we do not know which chips are > actually used. Yeah, cracking open a Surface 3 voids the guarantee and it's a glue hell from what I can understand. So no idea which chip is used in the end :( > > Judging from the above I believe that implementing the ACPI > OpRegion support for the MSHW0011 devices is a good solution > in this case. Thanks :) > > > On Thu, Jun 29, 2017 at 3:10 PM, Benjamin Tissoires > > <benjamin.tissoires@xxxxxxxxxx> wrote: > > > MSHW0011 replaces the battery firmware by using ACPI operation regions. > > > The values have been obtained by reverse engineering, and are subject to > > > errors. Looks like it works on overall pretty well. > > <snip> > > > > +/* > > > + * 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. > > > > All of this sounds familiar if look at what Hans discovered while was > > doing INT33FE support. > > Hans, does above ring any bell to you? > > Familiar yes, but I actually already looked at this rev-eng driver while working > on my INT33FE support and it is for different chips, and I don't know for > which models exactly. > > <snip> > > > > +static int acpi_find_i2c(struct acpi_resource *ares, void *data) > > > +{ > > > + struct mshw0011_lookup *lookup = data; > > > + > > > + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) > > > + return 1; > > > + > > > + if (lookup->n++ == lookup->index && !lookup->addr) > > > + lookup->addr = ares->data.i2c_serial_bus.slave_address; > > > + > > > + return 1; > > > +} > > > + > > > +static int mshw0011_i2c_resource_lookup(struct mshw0011_data *cdata, > > > + unsigned int index) > > > +{ > > > + struct i2c_client *client = cdata->adp1; > > > + struct acpi_device *adev = ACPI_COMPANION(&client->dev); > > > + struct mshw0011_lookup lookup = { > > > + .cdata = cdata, > > > + .index = index, > > > + }; > > > + struct list_head res_list; > > > + int ret; > > > + > > > + INIT_LIST_HEAD(&res_list); > > > + > > > + ret = acpi_dev_get_resources(adev, &res_list, acpi_find_i2c, &lookup); > > > + if (ret < 0) > > > + return ret; > > > + > > > + acpi_dev_free_resource_list(&res_list); > > > + > > > + if (!lookup.addr) > > > + return -ENOENT; > > > + > > > + return lookup.addr; > > > +} > > > > Strange you have above functions here. It's a copy paste from I2C > core. Please, think about way of deduplicating it. > > Right, this is something I can actually help with. When implementing the > INT33FE support (*) I also was dealing with an ACPI node with more then 1 > I2cSerialBus type resource and I needed not just an i2c-client for the > first one (which the i2c-core gives us) but also for the others. > > In 4.12 there is an i2c_acpi_new_device function which you can use > to create an i2c-client for the second i2c address you want to communicate > with, here is an example usage: > > struct i2c_board_info board_info; > > memset(&board_info, 0, sizeof(board_info)); > strlcpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE); > bat0 = i2c_acpi_new_device(dev, 1, &board_info); > > And then you can use bat0 to communicate to the other address, > as before, while dropping a whole bunch of copy-pasted code :) Thanks for the tip. I wrote this code more than a year ago IIRC, and there might not be those facilities at the time. Anyway, I'll amend this in v3. Cheers, Benjamin > > Regards, > > Hans > > > > *) Well an implementation of INT33FE support really since there seem to be many > different INT33FE devices, each one for a different charger / fuel-gauge combi > and you can only differentiate which one you're actually dealing with by > checking the PTYPE APCI Object and my implementation only supports PTYPE 4 > -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html