diff mbox series

[v2,2/6] platform/x86: dell-smo8800: Move instantiation of lis3lv02d i2c_client from i2c-i801 to dell-smo8800

Message ID 20240106160935.45487-3-hdegoede@redhat.com
State New
Headers show
Series i2c-i801 / dell-smo8800: Move instantiation of lis3lv02d i2c_client from i2c-i801 to dell-smo8800 | expand

Commit Message

Hans de Goede Jan. 6, 2024, 4:09 p.m. UTC
It is not necessary to handle the Dell specific instantiation of
i2c_client-s for SMO8xxx ACPI devices without an ACPI I2cResource
inside the generic i801 I2C adapter driver.

The kernel already instantiates platform_device-s for these ACPI devices
and the drivers/platform/x86/dell/dell-smo8800.c driver binds to these
platform drivers.

Move the i2c_client instantiation from the generic i2c-i801 driver to
the Dell specific dell-smo8800 driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
- Use a pci_device_id table to check for IDF (non main) i2c-i801 SMBusses
- Add a comment documenting the IDF PCI device ids
---
 drivers/i2c/busses/i2c-i801.c            | 126 +----------------------
 drivers/platform/x86/dell/dell-smo8800.c | 121 +++++++++++++++++++++-
 2 files changed, 123 insertions(+), 124 deletions(-)

Comments

Joe Perches Jan. 6, 2024, 7:54 p.m. UTC | #1
On Sat, 2024-01-06 at 18:24 +0200, Andy Shevchenko wrote:
> + Cc people from tags of 72921427d46b ("string.h: Add str_has_prefix() helper
> function"). See below why.
> > +	if (!strstarts(adap->name, "SMBus I801 adapter"))
> > +		return 0;
> 
> Bah, we have str_has_prefix() and this, much older one...
> Steven? Others? I mean we can do something about this duplication, right?

coccinelle?

@@
expression a, b;
@@

-	strstarts(a, b)
+	str_has_prefix(a, b)
kernel test robot Jan. 13, 2024, 4:42 a.m. UTC | #2
Hi Hans,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.7]
[cannot apply to wsa/i2c/for-next next-20240112]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Hans-de-Goede/platform-x86-dell-smo8800-Change-probe-ordering-a-bit/20240107-001715
base:   linus/master
patch link:    https://lore.kernel.org/r/20240106160935.45487-3-hdegoede%40redhat.com
patch subject: [PATCH v2 2/6] platform/x86: dell-smo8800: Move instantiation of lis3lv02d i2c_client from i2c-i801 to dell-smo8800
config: x86_64-buildonly-randconfig-001-20240113 (https://download.01.org/0day-ci/archive/20240113/202401131227.HL4y41DY-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240113/202401131227.HL4y41DY-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401131227.HL4y41DY-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In function 'smo8800_instantiate_i2c_client',
       inlined from 'smo8800_probe' at drivers/platform/x86/dell/dell-smo8800.c:240:2:
>> drivers/platform/x86/dell/dell-smo8800.c:188:21: warning: argument 1 null where non-null expected [-Wnonnull]
     188 |                 if (strcmp(dmi_product_name,
         |                     ^~~~~~~~~~~~~~~~~~~~~~~~
     189 |                            dell_lis3lv02d_devices[i].dmi_product_name) == 0) {
         |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from include/linux/bitmap.h:12,
                    from include/linux/cpumask.h:12,
                    from include/linux/smp.h:13,
                    from include/linux/lockdep.h:14,
                    from include/linux/mutex.h:17,
                    from include/linux/kernfs.h:11,
                    from include/linux/sysfs.h:16,
                    from include/linux/kobject.h:20,
                    from include/linux/device/bus.h:17,
                    from drivers/platform/x86/dell/dell-smo8800.c:14:
   include/linux/string.h: In function 'smo8800_probe':
   include/linux/string.h:89:12: note: in a call to function 'strcmp' declared 'nonnull'
      89 | extern int strcmp(const char *,const char *);
         |            ^~~~~~


vim +188 drivers/platform/x86/dell/dell-smo8800.c

   173	
   174	static void smo8800_instantiate_i2c_client(struct smo8800_device *smo8800)
   175	{
   176		struct i2c_board_info info = { };
   177		struct i2c_adapter *adap = NULL;
   178		const char *dmi_product_name;
   179		u8 addr = 0;
   180		int i;
   181	
   182		bus_for_each_dev(&i2c_bus_type, NULL, &adap, smo8800_find_i801);
   183		if (!adap)
   184			return;
   185	
   186		dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
   187		for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
 > 188			if (strcmp(dmi_product_name,
   189				   dell_lis3lv02d_devices[i].dmi_product_name) == 0) {
   190				addr = dell_lis3lv02d_devices[i].i2c_addr;
   191				break;
   192			}
   193		}
   194	
   195		if (!addr) {
   196			dev_warn(smo8800->dev,
   197				 "Accelerometer lis3lv02d is present on SMBus but its address is unknown, skipping registration\n");
   198			goto put_adapter;
   199		}
   200	
   201		info.addr = addr;
   202		strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
   203	
   204		smo8800->i2c_dev = i2c_new_client_device(adap, &info);
   205		if (IS_ERR(smo8800->i2c_dev)) {
   206			dev_err_probe(smo8800->dev, PTR_ERR(smo8800->i2c_dev),
   207				      "registering accel i2c_client\n");
   208			smo8800->i2c_dev = NULL;
   209		} else {
   210			dev_info(smo8800->dev, "Registered %s accelerometer on address 0x%02x\n",
   211				 info.type, info.addr);
   212		}
   213	put_adapter:
   214		i2c_put_adapter(adap);
   215	}
   216
kernel test robot Jan. 13, 2024, 7:46 a.m. UTC | #3
Hi Hans,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.7]
[cannot apply to wsa/i2c/for-next next-20240112]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Hans-de-Goede/platform-x86-dell-smo8800-Change-probe-ordering-a-bit/20240107-001715
base:   linus/master
patch link:    https://lore.kernel.org/r/20240106160935.45487-3-hdegoede%40redhat.com
patch subject: [PATCH v2 2/6] platform/x86: dell-smo8800: Move instantiation of lis3lv02d i2c_client from i2c-i801 to dell-smo8800
config: i386-buildonly-randconfig-005-20240113 (https://download.01.org/0day-ci/archive/20240113/202401131552.PbjGXHjA-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240113/202401131552.PbjGXHjA-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401131552.PbjGXHjA-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   drivers/platform/x86/dell/dell-smo8800.c: In function 'smo8800_find_i801':
>> drivers/platform/x86/dell/dell-smo8800.c:144:21: error: implicit declaration of function 'i2c_get_adapter'; did you mean 'i2c_get_adapdata'? [-Werror=implicit-function-declaration]
     144 |         *adap_ret = i2c_get_adapter(adap->nr);
         |                     ^~~~~~~~~~~~~~~
         |                     i2c_get_adapdata
>> drivers/platform/x86/dell/dell-smo8800.c:144:19: warning: assignment to 'struct i2c_adapter *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     144 |         *adap_ret = i2c_get_adapter(adap->nr);
         |                   ^
   drivers/platform/x86/dell/dell-smo8800.c: In function 'smo8800_instantiate_i2c_client':
>> drivers/platform/x86/dell/dell-smo8800.c:204:28: error: implicit declaration of function 'i2c_new_client_device' [-Werror=implicit-function-declaration]
     204 |         smo8800->i2c_dev = i2c_new_client_device(adap, &info);
         |                            ^~~~~~~~~~~~~~~~~~~~~
>> drivers/platform/x86/dell/dell-smo8800.c:204:26: warning: assignment to 'struct i2c_client *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     204 |         smo8800->i2c_dev = i2c_new_client_device(adap, &info);
         |                          ^
>> drivers/platform/x86/dell/dell-smo8800.c:214:9: error: implicit declaration of function 'i2c_put_adapter' [-Werror=implicit-function-declaration]
     214 |         i2c_put_adapter(adap);
         |         ^~~~~~~~~~~~~~~
   drivers/platform/x86/dell/dell-smo8800.c: In function 'smo8800_probe':
>> drivers/platform/x86/dell/dell-smo8800.c:267:9: error: implicit declaration of function 'i2c_unregister_device'; did you mean 'pci_unregister_driver'? [-Werror=implicit-function-declaration]
     267 |         i2c_unregister_device(smo8800->i2c_dev);
         |         ^~~~~~~~~~~~~~~~~~~~~
         |         pci_unregister_driver
   cc1: some warnings being treated as errors


vim +144 drivers/platform/x86/dell/dell-smo8800.c

   129	
   130	static int smo8800_find_i801(struct device *dev, void *data)
   131	{
   132		struct i2c_adapter *adap, **adap_ret = data;
   133	
   134		adap = i2c_verify_adapter(dev);
   135		if (!adap)
   136			return 0;
   137	
   138		if (!strstarts(adap->name, "SMBus I801 adapter"))
   139			return 0;
   140	
   141		if (pci_match_id(i801_idf_ids, to_pci_dev(adap->dev.parent)))
   142			return 0; /* Only register client on main SMBus channel */
   143	
 > 144		*adap_ret = i2c_get_adapter(adap->nr);
   145		return 1;
   146	}
   147	
   148	/*
   149	 * Accelerometer's I2C address is not specified in DMI nor ACPI,
   150	 * so it is needed to define mapping table based on DMI product names.
   151	 */
   152	static const struct {
   153		const char *dmi_product_name;
   154		unsigned short i2c_addr;
   155	} dell_lis3lv02d_devices[] = {
   156		/*
   157		 * Dell platform team told us that these Latitude devices have
   158		 * ST microelectronics accelerometer at I2C address 0x29.
   159		 */
   160		{ "Latitude E5250",     0x29 },
   161		{ "Latitude E5450",     0x29 },
   162		{ "Latitude E5550",     0x29 },
   163		{ "Latitude E6440",     0x29 },
   164		{ "Latitude E6440 ATG", 0x29 },
   165		{ "Latitude E6540",     0x29 },
   166		/*
   167		 * Additional individual entries were added after verification.
   168		 */
   169		{ "Latitude 5480",      0x29 },
   170		{ "Vostro V131",        0x1d },
   171		{ "Vostro 5568",        0x29 },
   172	};
   173	
   174	static void smo8800_instantiate_i2c_client(struct smo8800_device *smo8800)
   175	{
   176		struct i2c_board_info info = { };
   177		struct i2c_adapter *adap = NULL;
   178		const char *dmi_product_name;
   179		u8 addr = 0;
   180		int i;
   181	
   182		bus_for_each_dev(&i2c_bus_type, NULL, &adap, smo8800_find_i801);
   183		if (!adap)
   184			return;
   185	
   186		dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
   187		for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
   188			if (strcmp(dmi_product_name,
   189				   dell_lis3lv02d_devices[i].dmi_product_name) == 0) {
   190				addr = dell_lis3lv02d_devices[i].i2c_addr;
   191				break;
   192			}
   193		}
   194	
   195		if (!addr) {
   196			dev_warn(smo8800->dev,
   197				 "Accelerometer lis3lv02d is present on SMBus but its address is unknown, skipping registration\n");
   198			goto put_adapter;
   199		}
   200	
   201		info.addr = addr;
   202		strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
   203	
 > 204		smo8800->i2c_dev = i2c_new_client_device(adap, &info);
   205		if (IS_ERR(smo8800->i2c_dev)) {
   206			dev_err_probe(smo8800->dev, PTR_ERR(smo8800->i2c_dev),
   207				      "registering accel i2c_client\n");
   208			smo8800->i2c_dev = NULL;
   209		} else {
   210			dev_info(smo8800->dev, "Registered %s accelerometer on address 0x%02x\n",
   211				 info.type, info.addr);
   212		}
   213	put_adapter:
 > 214		i2c_put_adapter(adap);
   215	}
   216	
   217	static int smo8800_probe(struct platform_device *device)
   218	{
   219		int err;
   220		struct smo8800_device *smo8800;
   221	
   222		smo8800 = devm_kzalloc(&device->dev, sizeof(*smo8800), GFP_KERNEL);
   223		if (!smo8800) {
   224			dev_err(&device->dev, "failed to allocate device data\n");
   225			return -ENOMEM;
   226		}
   227	
   228		smo8800->dev = &device->dev;
   229		smo8800->miscdev.minor = MISC_DYNAMIC_MINOR;
   230		smo8800->miscdev.name = "freefall";
   231		smo8800->miscdev.fops = &smo8800_misc_fops;
   232	
   233		init_waitqueue_head(&smo8800->misc_wait);
   234	
   235		err = platform_get_irq(device, 0);
   236		if (err < 0)
   237			return err;
   238		smo8800->irq = err;
   239	
   240		smo8800_instantiate_i2c_client(smo8800);
   241	
   242		err = misc_register(&smo8800->miscdev);
   243		if (err) {
   244			dev_err(&device->dev, "failed to register misc dev: %d\n", err);
   245			goto error_unregister_i2c_client;
   246		}
   247	
   248		err = request_threaded_irq(smo8800->irq, smo8800_interrupt_quick,
   249					   smo8800_interrupt_thread,
   250					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
   251					   DRIVER_NAME, smo8800);
   252		if (err) {
   253			dev_err(&device->dev,
   254				"failed to request thread for IRQ %d: %d\n",
   255				smo8800->irq, err);
   256			goto error;
   257		}
   258	
   259		dev_dbg(&device->dev, "device /dev/freefall registered with IRQ %d\n",
   260			 smo8800->irq);
   261		platform_set_drvdata(device, smo8800);
   262		return 0;
   263	
   264	error:
   265		misc_deregister(&smo8800->miscdev);
   266	error_unregister_i2c_client:
 > 267		i2c_unregister_device(smo8800->i2c_dev);
   268		return err;
   269	}
   270
diff mbox series

Patch

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 070999139c6d..595e263ba623 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -975,6 +975,10 @@  static const struct i2c_algorithm smbus_algorithm = {
 #define FEATURES_ICH4	(FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER | \
 			 FEATURE_HOST_NOTIFY)
 
+/*
+ * NOTE: If new models with FEATURE_IDF are added please also update
+ * i801_idf_ids[] in drivers/platform/x86/dell-smo8800.c
+ */
 static const struct pci_device_id i801_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, 82801AA_3,			0)				 },
 	{ PCI_DEVICE_DATA(INTEL, 82801AB_3,			0)				 },
@@ -1141,125 +1145,6 @@  static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
 	}
 }
 
-/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */
-static const char *const acpi_smo8800_ids[] = {
-	"SMO8800",
-	"SMO8801",
-	"SMO8810",
-	"SMO8811",
-	"SMO8820",
-	"SMO8821",
-	"SMO8830",
-	"SMO8831",
-};
-
-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;
-	int i;
-
-	status = acpi_get_object_info(obj_handle, &info);
-	if (ACPI_FAILURE(status))
-		return AE_OK;
-
-	if (!(info->valid & ACPI_VALID_HID))
-		goto smo88xx_not_found;
-
-	hid = info->hardware_id.string;
-	if (!hid)
-		goto smo88xx_not_found;
-
-	i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid);
-	if (i < 0)
-		goto smo88xx_not_found;
-
-	kfree(info);
-
-	*return_value = NULL;
-	return AE_CTRL_TERMINATE;
-
-smo88xx_not_found:
-	kfree(info);
-	return AE_OK;
-}
-
-static bool is_dell_system_with_lis3lv02d(void)
-{
-	void *err = ERR_PTR(-ENOENT);
-
-	if (!dmi_match(DMI_SYS_VENDOR, "Dell Inc."))
-		return false;
-
-	/*
-	 * Check that ACPI device SMO88xx is present and is functioning.
-	 * Function acpi_get_devices() already filters all ACPI devices
-	 * which are not present or are not functioning.
-	 * ACPI device SMO88xx represents our ST microelectronics lis3lv02d
-	 * accelerometer but unfortunately ACPI does not provide any other
-	 * information (like I2C address).
-	 */
-	acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, &err);
-
-	return !IS_ERR(err);
-}
-
-/*
- * Accelerometer's I2C address is not specified in DMI nor ACPI,
- * so it is needed to define mapping table based on DMI product names.
- */
-static const struct {
-	const char *dmi_product_name;
-	unsigned short i2c_addr;
-} dell_lis3lv02d_devices[] = {
-	/*
-	 * Dell platform team told us that these Latitude devices have
-	 * ST microelectronics accelerometer at I2C address 0x29.
-	 */
-	{ "Latitude E5250",     0x29 },
-	{ "Latitude E5450",     0x29 },
-	{ "Latitude E5550",     0x29 },
-	{ "Latitude E6440",     0x29 },
-	{ "Latitude E6440 ATG", 0x29 },
-	{ "Latitude E6540",     0x29 },
-	/*
-	 * Additional individual entries were added after verification.
-	 */
-	{ "Latitude 5480",      0x29 },
-	{ "Vostro V131",        0x1d },
-	{ "Vostro 5568",        0x29 },
-};
-
-static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
-{
-	struct i2c_board_info info;
-	const char *dmi_product_name;
-	int i;
-
-	dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
-	for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
-		if (strcmp(dmi_product_name,
-			   dell_lis3lv02d_devices[i].dmi_product_name) == 0)
-			break;
-	}
-
-	if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) {
-		dev_warn(&priv->pci_dev->dev,
-			 "Accelerometer lis3lv02d is present on SMBus but its"
-			 " address is unknown, skipping registration\n");
-		return;
-	}
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = dell_lis3lv02d_devices[i].i2c_addr;
-	strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
-	i2c_new_client_device(&priv->adapter, &info);
-}
-
 /* Register optional slaves */
 static void i801_probe_optional_slaves(struct i801_priv *priv)
 {
@@ -1279,9 +1164,6 @@  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);
-
 	/* Instantiate SPD EEPROMs unless the SMBus is multiplexed */
 #if IS_ENABLED(CONFIG_I2C_MUX_GPIO)
 	if (!priv->mux_pdev)
diff --git a/drivers/platform/x86/dell/dell-smo8800.c b/drivers/platform/x86/dell/dell-smo8800.c
index 87339cc78880..c674e3392270 100644
--- a/drivers/platform/x86/dell/dell-smo8800.c
+++ b/drivers/platform/x86/dell/dell-smo8800.c
@@ -4,18 +4,23 @@ 
  *
  *  Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com>
  *  Copyright (C) 2014 Pali Rohár <pali@kernel.org>
+ *  Copyright (C) 2023 Hans de Goede <hansg@kernel.org>
  *
  *  This is loosely based on lis3lv02d driver.
  */
 
 #define DRIVER_NAME "smo8800"
 
+#include <linux/device/bus.h>
+#include <linux/dmi.h>
 #include <linux/fs.h>
+#include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
 
@@ -26,6 +31,7 @@  struct smo8800_device {
 	unsigned long misc_opened;   /* whether the device is open */
 	wait_queue_head_t misc_wait; /* Wait queue for the misc dev */
 	struct device *dev;          /* acpi device */
+	struct i2c_client *i2c_dev;  /* i2c_client for lis3lv02d */
 };
 
 static irqreturn_t smo8800_interrupt_quick(int irq, void *data)
@@ -103,6 +109,111 @@  static const struct file_operations smo8800_misc_fops = {
 	.release = smo8800_misc_release,
 };
 
+/*
+ * On 2 older PCH generations, Patsburg (for Sandy Bridge and Ivybridge) and
+ * Wellsburg (for Haswell and Broadwell), the PCH has 3 extra i2c-i801
+ * compatible SMBusses called 'Integrated Device Function' busses. These have
+ * FEATURE_IDF set in the i801_ids[] table in i2c-i801.c.
+ * The ST microelectronics accelerometer is connected to the main SMBus
+ * so the IDF controllers should be skipped.
+ */
+static const struct pci_device_id i801_idf_ids[] = {
+	{ PCI_VDEVICE(INTEL, 0x1d70) }, /* Patsburg IFD0 */
+	{ PCI_VDEVICE(INTEL, 0x1d71) }, /* Patsburg IFD1 */
+	{ PCI_VDEVICE(INTEL, 0x1d72) }, /* Patsburg IFD2 */
+	{ PCI_VDEVICE(INTEL, 0x8d7d) }, /* Wellsburg MS0 */
+	{ PCI_VDEVICE(INTEL, 0x8d7e) }, /* Wellsburg MS1 */
+	{ PCI_VDEVICE(INTEL, 0x8d7f) }, /* Wellsburg MS2 */
+	{}
+};
+
+static int smo8800_find_i801(struct device *dev, void *data)
+{
+	struct i2c_adapter *adap, **adap_ret = data;
+
+	adap = i2c_verify_adapter(dev);
+	if (!adap)
+		return 0;
+
+	if (!strstarts(adap->name, "SMBus I801 adapter"))
+		return 0;
+
+	if (pci_match_id(i801_idf_ids, to_pci_dev(adap->dev.parent)))
+		return 0; /* Only register client on main SMBus channel */
+
+	*adap_ret = i2c_get_adapter(adap->nr);
+	return 1;
+}
+
+/*
+ * Accelerometer's I2C address is not specified in DMI nor ACPI,
+ * so it is needed to define mapping table based on DMI product names.
+ */
+static const struct {
+	const char *dmi_product_name;
+	unsigned short i2c_addr;
+} dell_lis3lv02d_devices[] = {
+	/*
+	 * Dell platform team told us that these Latitude devices have
+	 * ST microelectronics accelerometer at I2C address 0x29.
+	 */
+	{ "Latitude E5250",     0x29 },
+	{ "Latitude E5450",     0x29 },
+	{ "Latitude E5550",     0x29 },
+	{ "Latitude E6440",     0x29 },
+	{ "Latitude E6440 ATG", 0x29 },
+	{ "Latitude E6540",     0x29 },
+	/*
+	 * Additional individual entries were added after verification.
+	 */
+	{ "Latitude 5480",      0x29 },
+	{ "Vostro V131",        0x1d },
+	{ "Vostro 5568",        0x29 },
+};
+
+static void smo8800_instantiate_i2c_client(struct smo8800_device *smo8800)
+{
+	struct i2c_board_info info = { };
+	struct i2c_adapter *adap = NULL;
+	const char *dmi_product_name;
+	u8 addr = 0;
+	int i;
+
+	bus_for_each_dev(&i2c_bus_type, NULL, &adap, smo8800_find_i801);
+	if (!adap)
+		return;
+
+	dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
+	for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
+		if (strcmp(dmi_product_name,
+			   dell_lis3lv02d_devices[i].dmi_product_name) == 0) {
+			addr = dell_lis3lv02d_devices[i].i2c_addr;
+			break;
+		}
+	}
+
+	if (!addr) {
+		dev_warn(smo8800->dev,
+			 "Accelerometer lis3lv02d is present on SMBus but its address is unknown, skipping registration\n");
+		goto put_adapter;
+	}
+
+	info.addr = addr;
+	strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
+
+	smo8800->i2c_dev = i2c_new_client_device(adap, &info);
+	if (IS_ERR(smo8800->i2c_dev)) {
+		dev_err_probe(smo8800->dev, PTR_ERR(smo8800->i2c_dev),
+			      "registering accel i2c_client\n");
+		smo8800->i2c_dev = NULL;
+	} else {
+		dev_info(smo8800->dev, "Registered %s accelerometer on address 0x%02x\n",
+			 info.type, info.addr);
+	}
+put_adapter:
+	i2c_put_adapter(adap);
+}
+
 static int smo8800_probe(struct platform_device *device)
 {
 	int err;
@@ -126,10 +237,12 @@  static int smo8800_probe(struct platform_device *device)
 		return err;
 	smo8800->irq = err;
 
+	smo8800_instantiate_i2c_client(smo8800);
+
 	err = misc_register(&smo8800->miscdev);
 	if (err) {
 		dev_err(&device->dev, "failed to register misc dev: %d\n", err);
-		return err;
+		goto error_unregister_i2c_client;
 	}
 
 	err = request_threaded_irq(smo8800->irq, smo8800_interrupt_quick,
@@ -150,6 +263,8 @@  static int smo8800_probe(struct platform_device *device)
 
 error:
 	misc_deregister(&smo8800->miscdev);
+error_unregister_i2c_client:
+	i2c_unregister_device(smo8800->i2c_dev);
 	return err;
 }
 
@@ -160,9 +275,9 @@  static void smo8800_remove(struct platform_device *device)
 	free_irq(smo8800->irq, smo8800);
 	misc_deregister(&smo8800->miscdev);
 	dev_dbg(&device->dev, "device /dev/freefall unregistered\n");
+	i2c_unregister_device(smo8800->i2c_dev);
 }
 
-/* NOTE: Keep this list in sync with drivers/i2c/busses/i2c-i801.c */
 static const struct acpi_device_id smo8800_ids[] = {
 	{ "SMO8800", 0 },
 	{ "SMO8801", 0 },
@@ -189,3 +304,5 @@  module_platform_driver(smo8800_driver);
 MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO88XX)");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sonal Santan, Pali Rohár");
+/* Ensure the i2c-801 driver is loaded for i2c_client instantiation */
+MODULE_SOFTDEP("pre: i2c-i801");