Re: [PATCH] i2c: i801: Register optional lis3lv02d i2c device on Dell machines

From: Pali RohÃr
Date: Thu Dec 29 2016 - 04:01:09 EST


On Thursday 29 December 2016 09:29:36 MichaÅ KÄpieÅ wrote:
> > Dell platform team told us that some (DMI whitelisted) Dell
> > Latitude machines have ST microelectronics accelerometer at i2c
> > address 0x29. That i2c address is not specified in DMI or ACPI, so
> > runtime detection without whitelist which is below is not
> > possible.
> >
> > Presence of that ST microelectronics accelerometer is verified by
> > existence of SMO88xx ACPI device which represent that
> > accelerometer. Unfortunately without i2c address.
>
> This part of the commit message sounded a bit confusing to me at
> first because there is already an ACPI driver which handles SMO88xx
> devices (dell-smo8800). My understanding is that:
>
> * the purpose of this patch is to expose a richer interface (as
> provided by lis3lv02d) to these devices on some machines,
>
> * on whitelisted machines, dell-smo8800 and lis3lv02d can work
> simultaneously (even though dell-smo8800 effectively duplicates
> the work that lis3lv02d does).

No. dell-smo8800 reads from ACPI irq number and exports /dev/freefall
device which notify userspace about falls. lis3lv02d is i2c driver which
exports axes of accelerometer. Additionaly lis3lv02d can export also
/dev/freefall if registerer of i2c device provides irq number -- which
is not case of this patch.

So both drivers are doing different things and both are useful.

IIRC both dell-smo8800 and lis3lv02d represent one HW device (that ST
microelectronics accelerometer) but due to complicated HW abstraction
and layers on Dell laptops it is handled by two drivers, one ACPI and
one i2c.

Yes, in ideal world irq number should be passed to lis3lv02d driver and
that would export whole device (with /dev/freefall too), but due to HW
abstraction it is too much complicated...

> If I got something wrong, please correct me. If I got it right, it
> might make sense to rephrase the commit message a bit so that the
> first bullet point above is immediately clear to the reader.
>
> > This patch registers lis3lv02d device at i2c address 0x29 if is
> > detected.
> >
> > Finally commit a7ae81952cda ("i2c: i801: Allow ACPI SystemIO
> > OpRegion to conflict with PCI BAR") allowed to use i2c-i801 driver
> > on Dell machines so lis3lv02d correctly initialize accelerometer.
> >
> > Tested on Dell Latitude E6440.
> >
> > Signed-off-by: Pali RohÃr <pali.rohar@xxxxxxxxx>
> > ---
> >
> > drivers/i2c/busses/i2c-i801.c | 98
> > +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98
> > insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-i801.c
> > b/drivers/i2c/busses/i2c-i801.c index eb3627f..188cfd4 100644
> > --- a/drivers/i2c/busses/i2c-i801.c
> > +++ b/drivers/i2c/busses/i2c-i801.c
> > @@ -1118,6 +1118,101 @@ static void dmi_check_onboard_devices(const
> > struct dmi_header *dm, void *adap)
> >
> > }
> >
> > }
> >
> > +static acpi_status check_acpi_smo88xx_device(acpi_handle
> > obj_handle, + u32 nesting_level,
> > + void *context,
> > + void **return_value)
> > +{
> > + struct acpi_device_info *info;
> > + acpi_status status;
> > + char *hid;
> > +
> > + status = acpi_get_object_info(obj_handle, &info);
>
> acpi_get_object_info() allocates the returned buffer, which the
> caller has to free.

Ok, I will fix it in next patch iteration.

> > + if (!ACPI_SUCCESS(status) || !(info->valid & ACPI_VALID_HID))
> > + return AE_OK;
> > +
> > + hid = info->hardware_id.string;
> > + if (!hid)
> > + return AE_OK;
> > +
> > + if (strlen(hid) < 7)
> > + return AE_OK;
> > +
> > + if (memcmp(hid, "SMO88", 5) != 0)
> > + return AE_OK;
> > +
> > + *((bool *)return_value) = true;
> > + return AE_CTRL_TERMINATE;
> > +}
> > +
> > +static bool is_dell_system_with_lis3lv02d(void)
> > +{
> > + bool found;
> > + acpi_status status;
> > + const char *vendor;
> > +
> > + vendor = dmi_get_system_info(DMI_SYS_VENDOR);
> > + if (strcmp(vendor, "Dell Inc.") != 0)
> > + return false;
> > +
> > + /*
> > + * Check if ACPI device SMO88xx exists and if is enabled. That
> > ACPI + * device represent our ST microelectronics lis3lv02d
> > accelerometer but + * unfortunately without any other additional
> > information. + */
> > + found = false;
> > + status = acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL,
> > + (void **)&found);
> > + if (!ACPI_SUCCESS(status) || !found)
> > + return false;
> > +
> > + return true;
> > +}
> > +
> > +/*
> > + * Dell platform team told us that these Latitude devices have
> > + * ST microelectronics accelerometer at i2c address 0x29.
> > + * That i2c address is not specified in DMI or ACPI, so runtime
> > + * detection without whitelist which is below is not possible.
> > + */
> > +static const char * const dmi_dell_product_names[] = {
> > + "Latitude E5250",
> > + "Latitude E5450",
> > + "Latitude E5550",
> > + "Latitude E6440",
> > + "Latitude E6440 ATG",
> > + "Latitude E6540",
> > +};
> > +
> > +static void register_dell_lis3lv02d_i2c_device(struct i801_priv
> > *priv) +{
> > + struct i2c_board_info info;
> > + const char *product_name;
> > + bool known_i2c_address;
> > + int i;
> > +
> > + known_i2c_address = false;
> > + product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
> > + for (i = 0; i < ARRAY_SIZE(dmi_dell_product_names); ++i) {
> > + if (strcmp(product_name, dmi_dell_product_names[i]) == 0) {
> > + known_i2c_address = true;
> > + break;
> > + }
> > + }
> > +
> > + if (!known_i2c_address) {
> > + dev_warn(&priv->pci_dev->dev,
> > + "Accelerometer lis3lv02d i2c device is present "
> > + "but its i2c address is unknown, skipping ...\n");
>
> You are probably well aware of this, but checkpatch prefers keeping
> long log messages in one line. I am pointing it out just in case.

Yes, but I do not know how to fix it. Splitting message into two lines
generates warning. Having long line generates warning too.

> > + return;
> > + }
> > +
> > + memset(&info, 0, sizeof(struct i2c_board_info));
>
> How about just doing "struct i2c_board_info info = { 0 };" instead?

Ok.

> > + info.addr = 0x29;
> > + strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
> > + i2c_new_device(&priv->adapter, &info);
> > +}
> > +
> >
> > /* Register optional slaves */
> > static void i801_probe_optional_slaves(struct i801_priv *priv)
> > {
> >
> > @@ -1136,6 +1231,9 @@ static void i801_probe_optional_slaves(struct
> > i801_priv *priv)
> >
> > if (dmi_name_in_vendors("FUJITSU"))
> >
> > dmi_walk(dmi_check_onboard_devices, &priv->adapter);
> >
> > +
> > + if (is_dell_system_with_lis3lv02d())
> > + register_dell_lis3lv02d_i2c_device(priv);
> >
> > }
> > #else
> > static void __init input_apanel_init(void) {}
>
> I tested this patch on a Vostro V131, which is not on the whitelist,
> so all I got was the warning message, but to this extent, it works
> for me.

Hm... That means your notebook has ST microelectronics accelerometer
too. You could try to find it on i2c-i801 bus with userspace i2cdetect
program (part of i2c-tools) and get i2c address. If it will work we can
extend DMI name --> i2c address mapping and include your notebook too.

I have that list of confirmed Latitude devices since April 2015 but due
to problem with ACPI resource conflicts it was not possible to load i2c-
i801.ko bus driver. It was fixed only this year by commit a7ae81952cda.
So list of devices is probably not up-to-date and new appeared.

--
Pali RohÃr
pali.rohar@xxxxxxxxx

Attachment: signature.asc
Description: This is a digitally signed message part.