xref: /openbmc/linux/drivers/i2c/i2c-smbus.c (revision c005e2f62f8421b13b9a31adb9db7281f1a19e68)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b5527a77SJean Delvare /*
3b5527a77SJean Delvare  * i2c-smbus.c - SMBus extensions to the I2C protocol
4b5527a77SJean Delvare  *
5b5527a77SJean Delvare  * Copyright (C) 2008 David Brownell
65ace6085SJean Delvare  * Copyright (C) 2010-2019 Jean Delvare <jdelvare@suse.de>
7b5527a77SJean Delvare  */
8b5527a77SJean Delvare 
9b5527a77SJean Delvare #include <linux/device.h>
105ace6085SJean Delvare #include <linux/dmi.h>
11b5527a77SJean Delvare #include <linux/i2c.h>
12b5527a77SJean Delvare #include <linux/i2c-smbus.h>
1362c874abSWolfram Sang #include <linux/interrupt.h>
1462c874abSWolfram Sang #include <linux/kernel.h>
1562c874abSWolfram Sang #include <linux/module.h>
16a263a840SAkhil R #include <linux/property.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
1862c874abSWolfram Sang #include <linux/workqueue.h>
19b5527a77SJean Delvare 
20b5527a77SJean Delvare struct i2c_smbus_alert {
21b5527a77SJean Delvare 	struct work_struct	alert;
22b5527a77SJean Delvare 	struct i2c_client	*ara;		/* Alert response address */
23b5527a77SJean Delvare };
24b5527a77SJean Delvare 
25b5527a77SJean Delvare struct alert_data {
26b5527a77SJean Delvare 	unsigned short		addr;
27e456cd37SBenjamin Tissoires 	enum i2c_alert_protocol	type;
28e456cd37SBenjamin Tissoires 	unsigned int		data;
29b5527a77SJean Delvare };
30b5527a77SJean Delvare 
31b5527a77SJean Delvare /* If this is the alerting device, notify its driver */
smbus_do_alert(struct device * dev,void * addrp)32b5527a77SJean Delvare static int smbus_do_alert(struct device *dev, void *addrp)
33b5527a77SJean Delvare {
34b5527a77SJean Delvare 	struct i2c_client *client = i2c_verify_client(dev);
35b5527a77SJean Delvare 	struct alert_data *data = addrp;
360acc2b32SLars-Peter Clausen 	struct i2c_driver *driver;
371534b112SGuenter Roeck 	int ret;
38b5527a77SJean Delvare 
39b5527a77SJean Delvare 	if (!client || client->addr != data->addr)
40b5527a77SJean Delvare 		return 0;
41b5527a77SJean Delvare 	if (client->flags & I2C_CLIENT_TEN)
42b5527a77SJean Delvare 		return 0;
43b5527a77SJean Delvare 
44b5527a77SJean Delvare 	/*
45b5527a77SJean Delvare 	 * Drivers should either disable alerts, or provide at least
460acc2b32SLars-Peter Clausen 	 * a minimal handler.  Lock so the driver won't change.
47b5527a77SJean Delvare 	 */
48f635a1e7SStephen Rothwell 	device_lock(dev);
490acc2b32SLars-Peter Clausen 	if (client->dev.driver) {
500acc2b32SLars-Peter Clausen 		driver = to_i2c_driver(client->dev.driver);
511534b112SGuenter Roeck 		if (driver->alert) {
521534b112SGuenter Roeck 			/* Stop iterating after we find the device */
53e456cd37SBenjamin Tissoires 			driver->alert(client, data->type, data->data);
541534b112SGuenter Roeck 			ret = -EBUSY;
551534b112SGuenter Roeck 		} else {
56b5527a77SJean Delvare 			dev_warn(&client->dev, "no driver alert()!\n");
571534b112SGuenter Roeck 			ret = -EOPNOTSUPP;
581534b112SGuenter Roeck 		}
591534b112SGuenter Roeck 	} else {
60b5527a77SJean Delvare 		dev_dbg(&client->dev, "alert with no driver\n");
611534b112SGuenter Roeck 		ret = -ENODEV;
621534b112SGuenter Roeck 	}
63f635a1e7SStephen Rothwell 	device_unlock(dev);
64b5527a77SJean Delvare 
651534b112SGuenter Roeck 	return ret;
66b5527a77SJean Delvare }
67b5527a77SJean Delvare 
68*ae68eee1SGuenter Roeck /* Same as above, but call back all drivers with alert handler */
69*ae68eee1SGuenter Roeck 
smbus_do_alert_force(struct device * dev,void * addrp)70*ae68eee1SGuenter Roeck static int smbus_do_alert_force(struct device *dev, void *addrp)
71*ae68eee1SGuenter Roeck {
72*ae68eee1SGuenter Roeck 	struct i2c_client *client = i2c_verify_client(dev);
73*ae68eee1SGuenter Roeck 	struct alert_data *data = addrp;
74*ae68eee1SGuenter Roeck 	struct i2c_driver *driver;
75*ae68eee1SGuenter Roeck 
76*ae68eee1SGuenter Roeck 	if (!client || (client->flags & I2C_CLIENT_TEN))
77*ae68eee1SGuenter Roeck 		return 0;
78*ae68eee1SGuenter Roeck 
79*ae68eee1SGuenter Roeck 	/*
80*ae68eee1SGuenter Roeck 	 * Drivers should either disable alerts, or provide at least
81*ae68eee1SGuenter Roeck 	 * a minimal handler. Lock so the driver won't change.
82*ae68eee1SGuenter Roeck 	 */
83*ae68eee1SGuenter Roeck 	device_lock(dev);
84*ae68eee1SGuenter Roeck 	if (client->dev.driver) {
85*ae68eee1SGuenter Roeck 		driver = to_i2c_driver(client->dev.driver);
86*ae68eee1SGuenter Roeck 		if (driver->alert)
87*ae68eee1SGuenter Roeck 			driver->alert(client, data->type, data->data);
88*ae68eee1SGuenter Roeck 	}
89*ae68eee1SGuenter Roeck 	device_unlock(dev);
90*ae68eee1SGuenter Roeck 
91*ae68eee1SGuenter Roeck 	return 0;
92*ae68eee1SGuenter Roeck }
93*ae68eee1SGuenter Roeck 
94b5527a77SJean Delvare /*
95b5527a77SJean Delvare  * The alert IRQ handler needs to hand work off to a task which can issue
96b5527a77SJean Delvare  * SMBus calls, because those sleeping calls can't be made in IRQ context.
97b5527a77SJean Delvare  */
smbus_alert(int irq,void * d)989b9f2b8bSPhil Reid static irqreturn_t smbus_alert(int irq, void *d)
99b5527a77SJean Delvare {
1009b9f2b8bSPhil Reid 	struct i2c_smbus_alert *alert = d;
101b5527a77SJean Delvare 	struct i2c_client *ara;
1021534b112SGuenter Roeck 	unsigned short prev_addr = I2C_CLIENT_END; /* Not a valid address */
103b5527a77SJean Delvare 
104b5527a77SJean Delvare 	ara = alert->ara;
105b5527a77SJean Delvare 
106b5527a77SJean Delvare 	for (;;) {
107b5527a77SJean Delvare 		s32 status;
108b5527a77SJean Delvare 		struct alert_data data;
109b5527a77SJean Delvare 
110b5527a77SJean Delvare 		/*
111b5527a77SJean Delvare 		 * Devices with pending alerts reply in address order, low
112b5527a77SJean Delvare 		 * to high, because of slave transmit arbitration.  After
113b5527a77SJean Delvare 		 * responding, an SMBus device stops asserting SMBALERT#.
114b5527a77SJean Delvare 		 *
115edc9102aSShailendra Verma 		 * Note that SMBus 2.0 reserves 10-bit addresses for future
116b5527a77SJean Delvare 		 * use.  We neither handle them, nor try to use PEC here.
117b5527a77SJean Delvare 		 */
118b5527a77SJean Delvare 		status = i2c_smbus_read_byte(ara);
119b5527a77SJean Delvare 		if (status < 0)
120b5527a77SJean Delvare 			break;
121b5527a77SJean Delvare 
122e456cd37SBenjamin Tissoires 		data.data = status & 1;
123b5527a77SJean Delvare 		data.addr = status >> 1;
124e456cd37SBenjamin Tissoires 		data.type = I2C_PROTOCOL_SMBUS_ALERT;
125b5527a77SJean Delvare 
126b5527a77SJean Delvare 		dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
127e456cd37SBenjamin Tissoires 			data.addr, data.data);
128b5527a77SJean Delvare 
129b5527a77SJean Delvare 		/* Notify driver for the device which issued the alert */
1301534b112SGuenter Roeck 		status = device_for_each_child(&ara->adapter->dev, &data,
131b5527a77SJean Delvare 					       smbus_do_alert);
1321534b112SGuenter Roeck 		/*
1331534b112SGuenter Roeck 		 * If we read the same address more than once, and the alert
1341534b112SGuenter Roeck 		 * was not handled by a driver, it won't do any good to repeat
135*ae68eee1SGuenter Roeck 		 * the loop because it will never terminate. Try again, this
136*ae68eee1SGuenter Roeck 		 * time calling the alert handlers of all devices connected to
137*ae68eee1SGuenter Roeck 		 * the bus, and abort the loop afterwards. If this helps, we
138*ae68eee1SGuenter Roeck 		 * are all set. If it doesn't, there is nothing else we can do,
139*ae68eee1SGuenter Roeck 		 * so we might as well abort the loop.
1401534b112SGuenter Roeck 		 * Note: This assumes that a driver with alert handler handles
1411534b112SGuenter Roeck 		 * the alert properly and clears it if necessary.
1421534b112SGuenter Roeck 		 */
143*ae68eee1SGuenter Roeck 		if (data.addr == prev_addr && status != -EBUSY) {
144*ae68eee1SGuenter Roeck 			device_for_each_child(&ara->adapter->dev, &data,
145*ae68eee1SGuenter Roeck 					      smbus_do_alert_force);
1461534b112SGuenter Roeck 			break;
147*ae68eee1SGuenter Roeck 		}
1481534b112SGuenter Roeck 		prev_addr = data.addr;
149b5527a77SJean Delvare 	}
150b5527a77SJean Delvare 
1519b9f2b8bSPhil Reid 	return IRQ_HANDLED;
152b5527a77SJean Delvare }
153b5527a77SJean Delvare 
smbalert_work(struct work_struct * work)1549b9f2b8bSPhil Reid static void smbalert_work(struct work_struct *work)
155b5527a77SJean Delvare {
1569b9f2b8bSPhil Reid 	struct i2c_smbus_alert *alert;
157b5527a77SJean Delvare 
1589b9f2b8bSPhil Reid 	alert = container_of(work, struct i2c_smbus_alert, alert);
159b5527a77SJean Delvare 
1609b9f2b8bSPhil Reid 	smbus_alert(0, alert);
1619b9f2b8bSPhil Reid 
162b5527a77SJean Delvare }
163b5527a77SJean Delvare 
164b5527a77SJean Delvare /* Setup SMBALERT# infrastructure */
smbalert_probe(struct i2c_client * ara)165a00f6d37SStephen Kitt static int smbalert_probe(struct i2c_client *ara)
166b5527a77SJean Delvare {
1676d4028c6SJingoo Han 	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
168b5527a77SJean Delvare 	struct i2c_smbus_alert *alert;
169b5527a77SJean Delvare 	struct i2c_adapter *adapter = ara->adapter;
1709b9f2b8bSPhil Reid 	int res, irq;
171b5527a77SJean Delvare 
17271b57845SJulia Lawall 	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
17371b57845SJulia Lawall 			     GFP_KERNEL);
174b5527a77SJean Delvare 	if (!alert)
175b5527a77SJean Delvare 		return -ENOMEM;
176b5527a77SJean Delvare 
17769d17246SPhil Reid 	if (setup) {
1789b9f2b8bSPhil Reid 		irq = setup->irq;
17969d17246SPhil Reid 	} else {
180a263a840SAkhil R 		irq = fwnode_irq_get_byname(dev_fwnode(adapter->dev.parent),
181a263a840SAkhil R 					    "smbus_alert");
18269d17246SPhil Reid 		if (irq <= 0)
18369d17246SPhil Reid 			return irq;
18469d17246SPhil Reid 	}
18569d17246SPhil Reid 
1869b9f2b8bSPhil Reid 	INIT_WORK(&alert->alert, smbalert_work);
187b5527a77SJean Delvare 	alert->ara = ara;
188b5527a77SJean Delvare 
1899b9f2b8bSPhil Reid 	if (irq > 0) {
1909b9f2b8bSPhil Reid 		res = devm_request_threaded_irq(&ara->dev, irq,
1919b9f2b8bSPhil Reid 						NULL, smbus_alert,
1929b9f2b8bSPhil Reid 						IRQF_SHARED | IRQF_ONESHOT,
1939b9f2b8bSPhil Reid 						"smbus_alert", alert);
19471b57845SJulia Lawall 		if (res)
195b5527a77SJean Delvare 			return res;
196b5527a77SJean Delvare 	}
197b5527a77SJean Delvare 
198b5527a77SJean Delvare 	i2c_set_clientdata(ara, alert);
1999b9f2b8bSPhil Reid 	dev_info(&adapter->dev, "supports SMBALERT#\n");
200b5527a77SJean Delvare 
201b5527a77SJean Delvare 	return 0;
202b5527a77SJean Delvare }
203b5527a77SJean Delvare 
20471b57845SJulia Lawall /* IRQ and memory resources are managed so they are freed automatically */
smbalert_remove(struct i2c_client * ara)205ed5c2f5fSUwe Kleine-König static void smbalert_remove(struct i2c_client *ara)
206b5527a77SJean Delvare {
207b5527a77SJean Delvare 	struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
208b5527a77SJean Delvare 
209b5527a77SJean Delvare 	cancel_work_sync(&alert->alert);
210b5527a77SJean Delvare }
211b5527a77SJean Delvare 
212b5527a77SJean Delvare static const struct i2c_device_id smbalert_ids[] = {
213b5527a77SJean Delvare 	{ "smbus_alert", 0 },
214b5527a77SJean Delvare 	{ /* LIST END */ }
215b5527a77SJean Delvare };
216b5527a77SJean Delvare MODULE_DEVICE_TABLE(i2c, smbalert_ids);
217b5527a77SJean Delvare 
218b5527a77SJean Delvare static struct i2c_driver smbalert_driver = {
219b5527a77SJean Delvare 	.driver = {
220b5527a77SJean Delvare 		.name	= "smbus_alert",
221b5527a77SJean Delvare 	},
222834a9dc4SUwe Kleine-König 	.probe		= smbalert_probe,
223b5527a77SJean Delvare 	.remove		= smbalert_remove,
224b5527a77SJean Delvare 	.id_table	= smbalert_ids,
225b5527a77SJean Delvare };
226b5527a77SJean Delvare 
227b5527a77SJean Delvare /**
228b5527a77SJean Delvare  * i2c_handle_smbus_alert - Handle an SMBus alert
229b5527a77SJean Delvare  * @ara: the ARA client on the relevant adapter
230b5527a77SJean Delvare  * Context: can't sleep
231b5527a77SJean Delvare  *
232b5527a77SJean Delvare  * Helper function to be called from an I2C bus driver's interrupt
233b5527a77SJean Delvare  * handler. It will schedule the alert work, in turn calling the
234b5527a77SJean Delvare  * corresponding I2C device driver's alert function.
235b5527a77SJean Delvare  *
236b5527a77SJean Delvare  * It is assumed that ara is a valid i2c client previously returned by
237ed680522SWolfram Sang  * i2c_new_smbus_alert_device().
238b5527a77SJean Delvare  */
i2c_handle_smbus_alert(struct i2c_client * ara)239b5527a77SJean Delvare int i2c_handle_smbus_alert(struct i2c_client *ara)
240b5527a77SJean Delvare {
241b5527a77SJean Delvare 	struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
242b5527a77SJean Delvare 
243b5527a77SJean Delvare 	return schedule_work(&alert->alert);
244b5527a77SJean Delvare }
245b5527a77SJean Delvare EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
246b5527a77SJean Delvare 
247fda2f4afSFabio Estevam module_i2c_driver(smbalert_driver);
248b5527a77SJean Delvare 
2492a71593dSAlain Volmat #if IS_ENABLED(CONFIG_I2C_SLAVE)
2502a71593dSAlain Volmat #define SMBUS_HOST_NOTIFY_LEN	3
2512a71593dSAlain Volmat struct i2c_slave_host_notify_status {
2522a71593dSAlain Volmat 	u8 index;
2532a71593dSAlain Volmat 	u8 addr;
2542a71593dSAlain Volmat };
2552a71593dSAlain Volmat 
i2c_slave_host_notify_cb(struct i2c_client * client,enum i2c_slave_event event,u8 * val)2562a71593dSAlain Volmat static int i2c_slave_host_notify_cb(struct i2c_client *client,
2572a71593dSAlain Volmat 				    enum i2c_slave_event event, u8 *val)
2582a71593dSAlain Volmat {
2592a71593dSAlain Volmat 	struct i2c_slave_host_notify_status *status = client->dev.platform_data;
2602a71593dSAlain Volmat 
2612a71593dSAlain Volmat 	switch (event) {
2622a71593dSAlain Volmat 	case I2C_SLAVE_WRITE_RECEIVED:
2632a71593dSAlain Volmat 		/* We only retrieve the first byte received (addr)
2642a71593dSAlain Volmat 		 * since there is currently no support to retrieve the data
2652a71593dSAlain Volmat 		 * parameter from the client.
2662a71593dSAlain Volmat 		 */
2672a71593dSAlain Volmat 		if (status->index == 0)
2682a71593dSAlain Volmat 			status->addr = *val;
2692a71593dSAlain Volmat 		if (status->index < U8_MAX)
2702a71593dSAlain Volmat 			status->index++;
2712a71593dSAlain Volmat 		break;
2722a71593dSAlain Volmat 	case I2C_SLAVE_STOP:
2732a71593dSAlain Volmat 		if (status->index == SMBUS_HOST_NOTIFY_LEN)
2742a71593dSAlain Volmat 			i2c_handle_smbus_host_notify(client->adapter,
2752a71593dSAlain Volmat 						     status->addr);
2762a71593dSAlain Volmat 		fallthrough;
2772a71593dSAlain Volmat 	case I2C_SLAVE_WRITE_REQUESTED:
2782a71593dSAlain Volmat 		status->index = 0;
2792a71593dSAlain Volmat 		break;
2802a71593dSAlain Volmat 	case I2C_SLAVE_READ_REQUESTED:
2812a71593dSAlain Volmat 	case I2C_SLAVE_READ_PROCESSED:
2822a71593dSAlain Volmat 		*val = 0xff;
2832a71593dSAlain Volmat 		break;
2842a71593dSAlain Volmat 	}
2852a71593dSAlain Volmat 
2862a71593dSAlain Volmat 	return 0;
2872a71593dSAlain Volmat }
2882a71593dSAlain Volmat 
2892a71593dSAlain Volmat /**
2902a71593dSAlain Volmat  * i2c_new_slave_host_notify_device - get a client for SMBus host-notify support
2912a71593dSAlain Volmat  * @adapter: the target adapter
2922a71593dSAlain Volmat  * Context: can sleep
2932a71593dSAlain Volmat  *
2942a71593dSAlain Volmat  * Setup handling of the SMBus host-notify protocol on a given I2C bus segment.
2952a71593dSAlain Volmat  *
2962a71593dSAlain Volmat  * Handling is done by creating a device and its callback and handling data
2972a71593dSAlain Volmat  * received via the SMBus host-notify address (0x8)
2982a71593dSAlain Volmat  *
2992a71593dSAlain Volmat  * This returns the client, which should be ultimately freed using
3002a71593dSAlain Volmat  * i2c_free_slave_host_notify_device(); or an ERRPTR to indicate an error.
3012a71593dSAlain Volmat  */
i2c_new_slave_host_notify_device(struct i2c_adapter * adapter)3022a71593dSAlain Volmat struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter)
3032a71593dSAlain Volmat {
3042a71593dSAlain Volmat 	struct i2c_board_info host_notify_board_info = {
3052a71593dSAlain Volmat 		I2C_BOARD_INFO("smbus_host_notify", 0x08),
3062a71593dSAlain Volmat 		.flags  = I2C_CLIENT_SLAVE,
3072a71593dSAlain Volmat 	};
3082a71593dSAlain Volmat 	struct i2c_slave_host_notify_status *status;
3092a71593dSAlain Volmat 	struct i2c_client *client;
3102a71593dSAlain Volmat 	int ret;
3112a71593dSAlain Volmat 
3122a71593dSAlain Volmat 	status = kzalloc(sizeof(struct i2c_slave_host_notify_status),
3132a71593dSAlain Volmat 			 GFP_KERNEL);
3142a71593dSAlain Volmat 	if (!status)
3152a71593dSAlain Volmat 		return ERR_PTR(-ENOMEM);
3162a71593dSAlain Volmat 
3172a71593dSAlain Volmat 	host_notify_board_info.platform_data = status;
3182a71593dSAlain Volmat 
3192a71593dSAlain Volmat 	client = i2c_new_client_device(adapter, &host_notify_board_info);
3202a71593dSAlain Volmat 	if (IS_ERR(client)) {
3212a71593dSAlain Volmat 		kfree(status);
3222a71593dSAlain Volmat 		return client;
3232a71593dSAlain Volmat 	}
3242a71593dSAlain Volmat 
3252a71593dSAlain Volmat 	ret = i2c_slave_register(client, i2c_slave_host_notify_cb);
3262a71593dSAlain Volmat 	if (ret) {
3272a71593dSAlain Volmat 		i2c_unregister_device(client);
3282a71593dSAlain Volmat 		kfree(status);
3292a71593dSAlain Volmat 		return ERR_PTR(ret);
3302a71593dSAlain Volmat 	}
3312a71593dSAlain Volmat 
3322a71593dSAlain Volmat 	return client;
3332a71593dSAlain Volmat }
3342a71593dSAlain Volmat EXPORT_SYMBOL_GPL(i2c_new_slave_host_notify_device);
3352a71593dSAlain Volmat 
3362a71593dSAlain Volmat /**
3372a71593dSAlain Volmat  * i2c_free_slave_host_notify_device - free the client for SMBus host-notify
3382a71593dSAlain Volmat  * support
3392a71593dSAlain Volmat  * @client: the client to free
3402a71593dSAlain Volmat  * Context: can sleep
3412a71593dSAlain Volmat  *
3422a71593dSAlain Volmat  * Free the i2c_client allocated via i2c_new_slave_host_notify_device
3432a71593dSAlain Volmat  */
i2c_free_slave_host_notify_device(struct i2c_client * client)3442a71593dSAlain Volmat void i2c_free_slave_host_notify_device(struct i2c_client *client)
3452a71593dSAlain Volmat {
3462a71593dSAlain Volmat 	if (IS_ERR_OR_NULL(client))
3472a71593dSAlain Volmat 		return;
3482a71593dSAlain Volmat 
3492a71593dSAlain Volmat 	i2c_slave_unregister(client);
3502a71593dSAlain Volmat 	kfree(client->dev.platform_data);
3512a71593dSAlain Volmat 	i2c_unregister_device(client);
3522a71593dSAlain Volmat }
3532a71593dSAlain Volmat EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device);
3542a71593dSAlain Volmat #endif
3552a71593dSAlain Volmat 
3565ace6085SJean Delvare /*
3575ace6085SJean Delvare  * SPD is not part of SMBus but we include it here for convenience as the
3585ace6085SJean Delvare  * target systems are the same.
3595ace6085SJean Delvare  * Restrictions to automatic SPD instantiation:
3605ace6085SJean Delvare  *  - Only works if all filled slots have the same memory type
3615ace6085SJean Delvare  *  - Only works for DDR2, DDR3 and DDR4 for now
3625ace6085SJean Delvare  *  - Only works on systems with 1 to 4 memory slots
3635ace6085SJean Delvare  */
3645ace6085SJean Delvare #if IS_ENABLED(CONFIG_DMI)
i2c_register_spd(struct i2c_adapter * adap)3655ace6085SJean Delvare void i2c_register_spd(struct i2c_adapter *adap)
3665ace6085SJean Delvare {
3675ace6085SJean Delvare 	int n, slot_count = 0, dimm_count = 0;
3685ace6085SJean Delvare 	u16 handle;
3695ace6085SJean Delvare 	u8 common_mem_type = 0x0, mem_type;
3705ace6085SJean Delvare 	u64 mem_size;
3715ace6085SJean Delvare 	const char *name;
3725ace6085SJean Delvare 
3735ace6085SJean Delvare 	while ((handle = dmi_memdev_handle(slot_count)) != 0xffff) {
3745ace6085SJean Delvare 		slot_count++;
3755ace6085SJean Delvare 
3765ace6085SJean Delvare 		/* Skip empty slots */
3775ace6085SJean Delvare 		mem_size = dmi_memdev_size(handle);
3785ace6085SJean Delvare 		if (!mem_size)
3795ace6085SJean Delvare 			continue;
3805ace6085SJean Delvare 
3815ace6085SJean Delvare 		/* Skip undefined memory type */
3825ace6085SJean Delvare 		mem_type = dmi_memdev_type(handle);
3835ace6085SJean Delvare 		if (mem_type <= 0x02)		/* Invalid, Other, Unknown */
3845ace6085SJean Delvare 			continue;
3855ace6085SJean Delvare 
3865ace6085SJean Delvare 		if (!common_mem_type) {
3875ace6085SJean Delvare 			/* First filled slot */
3885ace6085SJean Delvare 			common_mem_type = mem_type;
3895ace6085SJean Delvare 		} else {
3905ace6085SJean Delvare 			/* Check that all filled slots have the same type */
3915ace6085SJean Delvare 			if (mem_type != common_mem_type) {
3925ace6085SJean Delvare 				dev_warn(&adap->dev,
3935ace6085SJean Delvare 					 "Different memory types mixed, not instantiating SPD\n");
3945ace6085SJean Delvare 				return;
3955ace6085SJean Delvare 			}
3965ace6085SJean Delvare 		}
3975ace6085SJean Delvare 		dimm_count++;
3985ace6085SJean Delvare 	}
3995ace6085SJean Delvare 
4005ace6085SJean Delvare 	/* No useful DMI data, bail out */
4015ace6085SJean Delvare 	if (!dimm_count)
4025ace6085SJean Delvare 		return;
4035ace6085SJean Delvare 
4045ace6085SJean Delvare 	dev_info(&adap->dev, "%d/%d memory slots populated (from DMI)\n",
4055ace6085SJean Delvare 		 dimm_count, slot_count);
4065ace6085SJean Delvare 
4075ace6085SJean Delvare 	if (slot_count > 4) {
4085ace6085SJean Delvare 		dev_warn(&adap->dev,
4095ace6085SJean Delvare 			 "Systems with more than 4 memory slots not supported yet, not instantiating SPD\n");
4105ace6085SJean Delvare 		return;
4115ace6085SJean Delvare 	}
4125ace6085SJean Delvare 
4133d50b95bSCorentin Labbe 	/*
4143d50b95bSCorentin Labbe 	 * Memory types could be found at section 7.18.2 (Memory Device — Type), table 78
4153d50b95bSCorentin Labbe 	 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.6.0.pdf
4163d50b95bSCorentin Labbe 	 */
4175ace6085SJean Delvare 	switch (common_mem_type) {
4183d50b95bSCorentin Labbe 	case 0x12:	/* DDR */
4195ace6085SJean Delvare 	case 0x13:	/* DDR2 */
4205ace6085SJean Delvare 	case 0x18:	/* DDR3 */
4213d50b95bSCorentin Labbe 	case 0x1B:	/* LPDDR */
4225ace6085SJean Delvare 	case 0x1C:	/* LPDDR2 */
4235ace6085SJean Delvare 	case 0x1D:	/* LPDDR3 */
4245ace6085SJean Delvare 		name = "spd";
4255ace6085SJean Delvare 		break;
4265ace6085SJean Delvare 	case 0x1A:	/* DDR4 */
4275ace6085SJean Delvare 	case 0x1E:	/* LPDDR4 */
4285ace6085SJean Delvare 		name = "ee1004";
4295ace6085SJean Delvare 		break;
4305ace6085SJean Delvare 	default:
4315ace6085SJean Delvare 		dev_info(&adap->dev,
4325ace6085SJean Delvare 			 "Memory type 0x%02x not supported yet, not instantiating SPD\n",
4335ace6085SJean Delvare 			 common_mem_type);
4345ace6085SJean Delvare 		return;
4355ace6085SJean Delvare 	}
4365ace6085SJean Delvare 
4375ace6085SJean Delvare 	/*
4385ace6085SJean Delvare 	 * We don't know in which slots the memory modules are. We could
4395ace6085SJean Delvare 	 * try to guess from the slot names, but that would be rather complex
4405ace6085SJean Delvare 	 * and unreliable, so better probe all possible addresses until we
4415ace6085SJean Delvare 	 * have found all memory modules.
4425ace6085SJean Delvare 	 */
4435ace6085SJean Delvare 	for (n = 0; n < slot_count && dimm_count; n++) {
4445ace6085SJean Delvare 		struct i2c_board_info info;
4455ace6085SJean Delvare 		unsigned short addr_list[2];
4465ace6085SJean Delvare 
4475ace6085SJean Delvare 		memset(&info, 0, sizeof(struct i2c_board_info));
4480b0221d9SWolfram Sang 		strscpy(info.type, name, I2C_NAME_SIZE);
4495ace6085SJean Delvare 		addr_list[0] = 0x50 + n;
4505ace6085SJean Delvare 		addr_list[1] = I2C_CLIENT_END;
4515ace6085SJean Delvare 
4525ace6085SJean Delvare 		if (!IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL))) {
4535ace6085SJean Delvare 			dev_info(&adap->dev,
4545ace6085SJean Delvare 				 "Successfully instantiated SPD at 0x%hx\n",
4555ace6085SJean Delvare 				 addr_list[0]);
4565ace6085SJean Delvare 			dimm_count--;
4575ace6085SJean Delvare 		}
4585ace6085SJean Delvare 	}
4595ace6085SJean Delvare }
4605ace6085SJean Delvare EXPORT_SYMBOL_GPL(i2c_register_spd);
4615ace6085SJean Delvare #endif
4625ace6085SJean Delvare 
4637c81c60fSJean Delvare MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
464b5527a77SJean Delvare MODULE_DESCRIPTION("SMBus protocol extensions support");
465b5527a77SJean Delvare MODULE_LICENSE("GPL");
466