Skip to content

Commit 9ced933

Browse files
author
CKI KWF Bot
committed
Merge: i2c: i801: updates
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1481 Description: updates for i2c: i801 JIRA: https://issues.redhat.com/browse/RHEL-113184 Build Info: 68955562 Tested: Successful platform test results on Intel (intel-birchstream-gnr-cwf-ap-02) system. Signed-off-by: Steve Best <sbest@redhat.com> Approved-by: David Arcari <darcari@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents d96f565 + 84c091e commit 9ced933

File tree

9 files changed

+397
-289
lines changed

9 files changed

+397
-289
lines changed

drivers/i2c/busses/i2c-i801.c

Lines changed: 139 additions & 269 deletions
Large diffs are not rendered by default.

drivers/i2c/busses/i2c-piix4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
989989
* This would allow the ee1004 to be probed incorrectly.
990990
*/
991991
if (port == 0)
992-
i2c_register_spd(adap);
992+
i2c_register_spd_write_enable(adap);
993993

994994
*padap = adap;
995995
return 0;

drivers/i2c/i2c-smbus.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,13 @@ EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device);
362362
* - Only works on systems with 1 to 8 memory slots
363363
*/
364364
#if IS_ENABLED(CONFIG_DMI)
365-
void i2c_register_spd(struct i2c_adapter *adap)
365+
static void i2c_register_spd(struct i2c_adapter *adap, bool write_disabled)
366366
{
367367
int n, slot_count = 0, dimm_count = 0;
368368
u16 handle;
369369
u8 common_mem_type = 0x0, mem_type;
370370
u64 mem_size;
371+
bool instantiate = true;
371372
const char *name;
372373

373374
while ((handle = dmi_memdev_handle(slot_count)) != 0xffff) {
@@ -428,6 +429,7 @@ void i2c_register_spd(struct i2c_adapter *adap)
428429
case 0x22: /* DDR5 */
429430
case 0x23: /* LPDDR5 */
430431
name = "spd5118";
432+
instantiate = !write_disabled;
431433
break;
432434
default:
433435
dev_info(&adap->dev,
@@ -451,6 +453,9 @@ void i2c_register_spd(struct i2c_adapter *adap)
451453
addr_list[0] = 0x50 + n;
452454
addr_list[1] = I2C_CLIENT_END;
453455

456+
if (!instantiate)
457+
continue;
458+
454459
if (!IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL))) {
455460
dev_info(&adap->dev,
456461
"Successfully instantiated SPD at 0x%hx\n",
@@ -459,7 +464,19 @@ void i2c_register_spd(struct i2c_adapter *adap)
459464
}
460465
}
461466
}
462-
EXPORT_SYMBOL_GPL(i2c_register_spd);
467+
468+
void i2c_register_spd_write_disable(struct i2c_adapter *adap)
469+
{
470+
i2c_register_spd(adap, true);
471+
}
472+
EXPORT_SYMBOL_GPL(i2c_register_spd_write_disable);
473+
474+
void i2c_register_spd_write_enable(struct i2c_adapter *adap)
475+
{
476+
i2c_register_spd(adap, false);
477+
}
478+
EXPORT_SYMBOL_GPL(i2c_register_spd_write_enable);
479+
463480
#endif
464481

465482
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");

drivers/platform/x86/dell/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ config DELL_SMBIOS_SMM
151151
config DELL_SMO8800
152152
tristate "Dell Latitude freefall driver (ACPI SMO88XX)"
153153
default m
154+
depends on I2C
154155
depends on ACPI || COMPILE_TEST
155156
help
156157
Say Y here if you want to support SMO88XX freefall devices

drivers/platform/x86/dell/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dell-smbios-objs := dell-smbios-base.o
1515
dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
1616
dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
1717
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
18+
obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o
1819
obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o
1920
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
2021
dell-wmi-objs := dell-wmi-base.o
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* lis3lv02d i2c-client instantiation for ACPI SMO88xx devices without I2C resources.
4+
*
5+
* Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
6+
*/
7+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8+
9+
#include <linux/device/bus.h>
10+
#include <linux/dmi.h>
11+
#include <linux/i2c.h>
12+
#include <linux/module.h>
13+
#include <linux/notifier.h>
14+
#include <linux/platform_device.h>
15+
#include <linux/workqueue.h>
16+
#include "dell-smo8800-ids.h"
17+
18+
#define DELL_LIS3LV02D_DMI_ENTRY(product_name, i2c_addr) \
19+
{ \
20+
.matches = { \
21+
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), \
22+
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, product_name), \
23+
}, \
24+
.driver_data = (void *)(uintptr_t)(i2c_addr), \
25+
}
26+
27+
/*
28+
* Accelerometer's I2C address is not specified in DMI nor ACPI,
29+
* so it is needed to define mapping table based on DMI product names.
30+
*/
31+
static const struct dmi_system_id lis3lv02d_devices[] __initconst = {
32+
/*
33+
* Dell platform team told us that these Latitude devices have
34+
* ST microelectronics accelerometer at I2C address 0x29.
35+
*/
36+
DELL_LIS3LV02D_DMI_ENTRY("Latitude E5250", 0x29),
37+
DELL_LIS3LV02D_DMI_ENTRY("Latitude E5450", 0x29),
38+
DELL_LIS3LV02D_DMI_ENTRY("Latitude E5550", 0x29),
39+
DELL_LIS3LV02D_DMI_ENTRY("Latitude E6440", 0x29),
40+
DELL_LIS3LV02D_DMI_ENTRY("Latitude E6440 ATG", 0x29),
41+
DELL_LIS3LV02D_DMI_ENTRY("Latitude E6540", 0x29),
42+
/*
43+
* Additional individual entries were added after verification.
44+
*/
45+
DELL_LIS3LV02D_DMI_ENTRY("Latitude 5480", 0x29),
46+
DELL_LIS3LV02D_DMI_ENTRY("Precision 3540", 0x29),
47+
DELL_LIS3LV02D_DMI_ENTRY("Vostro V131", 0x1d),
48+
DELL_LIS3LV02D_DMI_ENTRY("Vostro 5568", 0x29),
49+
DELL_LIS3LV02D_DMI_ENTRY("XPS 15 7590", 0x29),
50+
{ }
51+
};
52+
53+
static u8 i2c_addr;
54+
static struct i2c_client *i2c_dev;
55+
static bool notifier_registered;
56+
57+
static bool i2c_adapter_is_main_i801(struct i2c_adapter *adap)
58+
{
59+
/*
60+
* Only match the main I801 adapter and reject secondary adapters
61+
* which names start with "SMBus I801 IDF adapter".
62+
*/
63+
return strstarts(adap->name, "SMBus I801 adapter");
64+
}
65+
66+
static int find_i801(struct device *dev, void *data)
67+
{
68+
struct i2c_adapter *adap, **adap_ret = data;
69+
70+
adap = i2c_verify_adapter(dev);
71+
if (!adap)
72+
return 0;
73+
74+
if (!i2c_adapter_is_main_i801(adap))
75+
return 0;
76+
77+
*adap_ret = i2c_get_adapter(adap->nr);
78+
return 1;
79+
}
80+
81+
static void instantiate_i2c_client(struct work_struct *work)
82+
{
83+
struct i2c_board_info info = { };
84+
struct i2c_adapter *adap = NULL;
85+
86+
if (i2c_dev)
87+
return;
88+
89+
/*
90+
* bus_for_each_dev() and not i2c_for_each_dev() to avoid
91+
* a deadlock when find_i801() calls i2c_get_adapter().
92+
*/
93+
bus_for_each_dev(&i2c_bus_type, NULL, &adap, find_i801);
94+
if (!adap)
95+
return;
96+
97+
info.addr = i2c_addr;
98+
strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
99+
100+
i2c_dev = i2c_new_client_device(adap, &info);
101+
if (IS_ERR(i2c_dev)) {
102+
dev_err(&adap->dev, "error %ld registering i2c_client\n", PTR_ERR(i2c_dev));
103+
i2c_dev = NULL;
104+
} else {
105+
dev_dbg(&adap->dev, "registered lis3lv02d on address 0x%02x\n", info.addr);
106+
}
107+
108+
i2c_put_adapter(adap);
109+
}
110+
static DECLARE_WORK(i2c_work, instantiate_i2c_client);
111+
112+
static int i2c_bus_notify(struct notifier_block *nb, unsigned long action, void *data)
113+
{
114+
struct device *dev = data;
115+
struct i2c_client *client;
116+
struct i2c_adapter *adap;
117+
118+
switch (action) {
119+
case BUS_NOTIFY_ADD_DEVICE:
120+
adap = i2c_verify_adapter(dev);
121+
if (!adap)
122+
break;
123+
124+
if (i2c_adapter_is_main_i801(adap))
125+
queue_work(system_long_wq, &i2c_work);
126+
break;
127+
case BUS_NOTIFY_REMOVED_DEVICE:
128+
client = i2c_verify_client(dev);
129+
if (!client)
130+
break;
131+
132+
if (i2c_dev == client) {
133+
dev_dbg(&client->adapter->dev, "lis3lv02d i2c_client removed\n");
134+
i2c_dev = NULL;
135+
}
136+
break;
137+
default:
138+
break;
139+
}
140+
141+
return 0;
142+
}
143+
static struct notifier_block i2c_nb = { .notifier_call = i2c_bus_notify };
144+
145+
static int __init match_acpi_device_ids(struct device *dev, const void *data)
146+
{
147+
return acpi_match_device(data, dev) ? 1 : 0;
148+
}
149+
150+
static int __init dell_lis3lv02d_init(void)
151+
{
152+
const struct dmi_system_id *lis3lv02d_dmi_id;
153+
struct device *dev;
154+
int err;
155+
156+
/*
157+
* First check for a matching platform_device. This protects against
158+
* SMO88xx ACPI fwnodes which actually do have an I2C resource, which
159+
* will already have an i2c_client instantiated (not a platform_device).
160+
*/
161+
dev = bus_find_device(&platform_bus_type, NULL, smo8800_ids, match_acpi_device_ids);
162+
if (!dev) {
163+
pr_debug("No SMO88xx platform-device found\n");
164+
return 0;
165+
}
166+
put_device(dev);
167+
168+
lis3lv02d_dmi_id = dmi_first_match(lis3lv02d_devices);
169+
if (!lis3lv02d_dmi_id) {
170+
pr_warn("accelerometer is present on SMBus but its address is unknown, skipping registration\n");
171+
return 0;
172+
}
173+
174+
i2c_addr = (long)lis3lv02d_dmi_id->driver_data;
175+
176+
/*
177+
* Register i2c-bus notifier + queue initial scan for lis3lv02d
178+
* i2c_client instantiation.
179+
*/
180+
err = bus_register_notifier(&i2c_bus_type, &i2c_nb);
181+
if (err)
182+
return err;
183+
184+
notifier_registered = true;
185+
186+
queue_work(system_long_wq, &i2c_work);
187+
return 0;
188+
}
189+
module_init(dell_lis3lv02d_init);
190+
191+
static void __exit dell_lis3lv02d_module_exit(void)
192+
{
193+
if (!notifier_registered)
194+
return;
195+
196+
bus_unregister_notifier(&i2c_bus_type, &i2c_nb);
197+
cancel_work_sync(&i2c_work);
198+
i2c_unregister_device(i2c_dev);
199+
}
200+
module_exit(dell_lis3lv02d_module_exit);
201+
202+
MODULE_DESCRIPTION("lis3lv02d i2c-client instantiation for ACPI SMO88xx devices");
203+
MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
204+
MODULE_LICENSE("GPL");
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* ACPI SMO88XX lis3lv02d freefall / accelerometer device-ids.
4+
*
5+
* Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com>
6+
* Copyright (C) 2014 Pali Rohár <pali@kernel.org>
7+
*/
8+
#ifndef _DELL_SMO8800_IDS_H_
9+
#define _DELL_SMO8800_IDS_H_
10+
11+
#include <linux/mod_devicetable.h>
12+
#include <linux/module.h>
13+
14+
static const struct acpi_device_id smo8800_ids[] = {
15+
{ "SMO8800" },
16+
{ "SMO8801" },
17+
{ "SMO8810" },
18+
{ "SMO8811" },
19+
{ "SMO8820" },
20+
{ "SMO8821" },
21+
{ "SMO8830" },
22+
{ "SMO8831" },
23+
{ }
24+
};
25+
MODULE_DEVICE_TABLE(acpi, smo8800_ids);
26+
27+
#endif

drivers/platform/x86/dell/dell-smo8800.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
#include <linux/interrupt.h>
1515
#include <linux/kernel.h>
1616
#include <linux/miscdevice.h>
17-
#include <linux/mod_devicetable.h>
1817
#include <linux/module.h>
1918
#include <linux/platform_device.h>
2019
#include <linux/uaccess.h>
20+
#include "dell-smo8800-ids.h"
2121

2222
struct smo8800_device {
2323
u32 irq; /* acpi device irq */
@@ -163,20 +163,6 @@ static void smo8800_remove(struct platform_device *device)
163163
dev_dbg(&device->dev, "device /dev/freefall unregistered\n");
164164
}
165165

166-
/* NOTE: Keep this list in sync with drivers/i2c/busses/i2c-i801.c */
167-
static const struct acpi_device_id smo8800_ids[] = {
168-
{ "SMO8800", 0 },
169-
{ "SMO8801", 0 },
170-
{ "SMO8810", 0 },
171-
{ "SMO8811", 0 },
172-
{ "SMO8820", 0 },
173-
{ "SMO8821", 0 },
174-
{ "SMO8830", 0 },
175-
{ "SMO8831", 0 },
176-
{ "", 0 },
177-
};
178-
MODULE_DEVICE_TABLE(acpi, smo8800_ids);
179-
180166
static struct platform_driver smo8800_driver = {
181167
.probe = smo8800_probe,
182168
.remove = smo8800_remove,

include/linux/i2c-smbus.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ static inline void i2c_free_slave_host_notify_device(struct i2c_client *client)
4444
#endif
4545

4646
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_DMI)
47-
void i2c_register_spd(struct i2c_adapter *adap);
47+
void i2c_register_spd_write_disable(struct i2c_adapter *adap);
48+
void i2c_register_spd_write_enable(struct i2c_adapter *adap);
4849
#else
49-
static inline void i2c_register_spd(struct i2c_adapter *adap) { }
50+
static inline void i2c_register_spd_write_disable(struct i2c_adapter *adap) { }
51+
static inline void i2c_register_spd_write_enable(struct i2c_adapter *adap) { }
5052
#endif
5153

5254
#endif /* _LINUX_I2C_SMBUS_H */

0 commit comments

Comments
 (0)