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