hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/i2c/i2c-smbus.c
....@@ -1,21 +1,13 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * i2c-smbus.c - SMBus extensions to the I2C protocol
34 *
45 * Copyright (C) 2008 David Brownell
5
- * Copyright (C) 2010 Jean Delvare <jdelvare@suse.de>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version.
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
6
+ * Copyright (C) 2010-2019 Jean Delvare <jdelvare@suse.de>
167 */
178
189 #include <linux/device.h>
10
+#include <linux/dmi.h>
1911 #include <linux/i2c.h>
2012 #include <linux/i2c-smbus.h>
2113 #include <linux/interrupt.h>
....@@ -75,7 +67,6 @@
7567 {
7668 struct i2c_smbus_alert *alert = d;
7769 struct i2c_client *ara;
78
- unsigned short prev_addr = 0; /* Not a valid address */
7970
8071 ara = alert->ara;
8172
....@@ -99,18 +90,12 @@
9990 data.addr = status >> 1;
10091 data.type = I2C_PROTOCOL_SMBUS_ALERT;
10192
102
- if (data.addr == prev_addr) {
103
- dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
104
- "0x%02x, skipping\n", data.addr);
105
- break;
106
- }
10793 dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
10894 data.addr, data.data);
10995
11096 /* Notify driver for the device which issued the alert */
11197 device_for_each_child(&ara->adapter->dev, &data,
11298 smbus_do_alert);
113
- prev_addr = data.addr;
11499 }
115100
116101 return IRQ_HANDLED;
....@@ -200,7 +185,7 @@
200185 * corresponding I2C device driver's alert function.
201186 *
202187 * It is assumed that ara is a valid i2c client previously returned by
203
- * i2c_setup_smbus_alert().
188
+ * i2c_new_smbus_alert_device().
204189 */
205190 int i2c_handle_smbus_alert(struct i2c_client *ara)
206191 {
....@@ -212,6 +197,214 @@
212197
213198 module_i2c_driver(smbalert_driver);
214199
200
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
201
+#define SMBUS_HOST_NOTIFY_LEN 3
202
+struct i2c_slave_host_notify_status {
203
+ u8 index;
204
+ u8 addr;
205
+};
206
+
207
+static int i2c_slave_host_notify_cb(struct i2c_client *client,
208
+ enum i2c_slave_event event, u8 *val)
209
+{
210
+ struct i2c_slave_host_notify_status *status = client->dev.platform_data;
211
+
212
+ switch (event) {
213
+ case I2C_SLAVE_WRITE_RECEIVED:
214
+ /* We only retrieve the first byte received (addr)
215
+ * since there is currently no support to retrieve the data
216
+ * parameter from the client.
217
+ */
218
+ if (status->index == 0)
219
+ status->addr = *val;
220
+ if (status->index < U8_MAX)
221
+ status->index++;
222
+ break;
223
+ case I2C_SLAVE_STOP:
224
+ if (status->index == SMBUS_HOST_NOTIFY_LEN)
225
+ i2c_handle_smbus_host_notify(client->adapter,
226
+ status->addr);
227
+ fallthrough;
228
+ case I2C_SLAVE_WRITE_REQUESTED:
229
+ status->index = 0;
230
+ break;
231
+ case I2C_SLAVE_READ_REQUESTED:
232
+ case I2C_SLAVE_READ_PROCESSED:
233
+ *val = 0xff;
234
+ break;
235
+ }
236
+
237
+ return 0;
238
+}
239
+
240
+/**
241
+ * i2c_new_slave_host_notify_device - get a client for SMBus host-notify support
242
+ * @adapter: the target adapter
243
+ * Context: can sleep
244
+ *
245
+ * Setup handling of the SMBus host-notify protocol on a given I2C bus segment.
246
+ *
247
+ * Handling is done by creating a device and its callback and handling data
248
+ * received via the SMBus host-notify address (0x8)
249
+ *
250
+ * This returns the client, which should be ultimately freed using
251
+ * i2c_free_slave_host_notify_device(); or an ERRPTR to indicate an error.
252
+ */
253
+struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter)
254
+{
255
+ struct i2c_board_info host_notify_board_info = {
256
+ I2C_BOARD_INFO("smbus_host_notify", 0x08),
257
+ .flags = I2C_CLIENT_SLAVE,
258
+ };
259
+ struct i2c_slave_host_notify_status *status;
260
+ struct i2c_client *client;
261
+ int ret;
262
+
263
+ status = kzalloc(sizeof(struct i2c_slave_host_notify_status),
264
+ GFP_KERNEL);
265
+ if (!status)
266
+ return ERR_PTR(-ENOMEM);
267
+
268
+ host_notify_board_info.platform_data = status;
269
+
270
+ client = i2c_new_client_device(adapter, &host_notify_board_info);
271
+ if (IS_ERR(client)) {
272
+ kfree(status);
273
+ return client;
274
+ }
275
+
276
+ ret = i2c_slave_register(client, i2c_slave_host_notify_cb);
277
+ if (ret) {
278
+ i2c_unregister_device(client);
279
+ kfree(status);
280
+ return ERR_PTR(ret);
281
+ }
282
+
283
+ return client;
284
+}
285
+EXPORT_SYMBOL_GPL(i2c_new_slave_host_notify_device);
286
+
287
+/**
288
+ * i2c_free_slave_host_notify_device - free the client for SMBus host-notify
289
+ * support
290
+ * @client: the client to free
291
+ * Context: can sleep
292
+ *
293
+ * Free the i2c_client allocated via i2c_new_slave_host_notify_device
294
+ */
295
+void i2c_free_slave_host_notify_device(struct i2c_client *client)
296
+{
297
+ if (IS_ERR_OR_NULL(client))
298
+ return;
299
+
300
+ i2c_slave_unregister(client);
301
+ kfree(client->dev.platform_data);
302
+ i2c_unregister_device(client);
303
+}
304
+EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device);
305
+#endif
306
+
307
+/*
308
+ * SPD is not part of SMBus but we include it here for convenience as the
309
+ * target systems are the same.
310
+ * Restrictions to automatic SPD instantiation:
311
+ * - Only works if all filled slots have the same memory type
312
+ * - Only works for DDR2, DDR3 and DDR4 for now
313
+ * - Only works on systems with 1 to 4 memory slots
314
+ */
315
+#if IS_ENABLED(CONFIG_DMI)
316
+void i2c_register_spd(struct i2c_adapter *adap)
317
+{
318
+ int n, slot_count = 0, dimm_count = 0;
319
+ u16 handle;
320
+ u8 common_mem_type = 0x0, mem_type;
321
+ u64 mem_size;
322
+ const char *name;
323
+
324
+ while ((handle = dmi_memdev_handle(slot_count)) != 0xffff) {
325
+ slot_count++;
326
+
327
+ /* Skip empty slots */
328
+ mem_size = dmi_memdev_size(handle);
329
+ if (!mem_size)
330
+ continue;
331
+
332
+ /* Skip undefined memory type */
333
+ mem_type = dmi_memdev_type(handle);
334
+ if (mem_type <= 0x02) /* Invalid, Other, Unknown */
335
+ continue;
336
+
337
+ if (!common_mem_type) {
338
+ /* First filled slot */
339
+ common_mem_type = mem_type;
340
+ } else {
341
+ /* Check that all filled slots have the same type */
342
+ if (mem_type != common_mem_type) {
343
+ dev_warn(&adap->dev,
344
+ "Different memory types mixed, not instantiating SPD\n");
345
+ return;
346
+ }
347
+ }
348
+ dimm_count++;
349
+ }
350
+
351
+ /* No useful DMI data, bail out */
352
+ if (!dimm_count)
353
+ return;
354
+
355
+ dev_info(&adap->dev, "%d/%d memory slots populated (from DMI)\n",
356
+ dimm_count, slot_count);
357
+
358
+ if (slot_count > 4) {
359
+ dev_warn(&adap->dev,
360
+ "Systems with more than 4 memory slots not supported yet, not instantiating SPD\n");
361
+ return;
362
+ }
363
+
364
+ switch (common_mem_type) {
365
+ case 0x13: /* DDR2 */
366
+ case 0x18: /* DDR3 */
367
+ case 0x1C: /* LPDDR2 */
368
+ case 0x1D: /* LPDDR3 */
369
+ name = "spd";
370
+ break;
371
+ case 0x1A: /* DDR4 */
372
+ case 0x1E: /* LPDDR4 */
373
+ name = "ee1004";
374
+ break;
375
+ default:
376
+ dev_info(&adap->dev,
377
+ "Memory type 0x%02x not supported yet, not instantiating SPD\n",
378
+ common_mem_type);
379
+ return;
380
+ }
381
+
382
+ /*
383
+ * We don't know in which slots the memory modules are. We could
384
+ * try to guess from the slot names, but that would be rather complex
385
+ * and unreliable, so better probe all possible addresses until we
386
+ * have found all memory modules.
387
+ */
388
+ for (n = 0; n < slot_count && dimm_count; n++) {
389
+ struct i2c_board_info info;
390
+ unsigned short addr_list[2];
391
+
392
+ memset(&info, 0, sizeof(struct i2c_board_info));
393
+ strlcpy(info.type, name, I2C_NAME_SIZE);
394
+ addr_list[0] = 0x50 + n;
395
+ addr_list[1] = I2C_CLIENT_END;
396
+
397
+ if (!IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL))) {
398
+ dev_info(&adap->dev,
399
+ "Successfully instantiated SPD at 0x%hx\n",
400
+ addr_list[0]);
401
+ dimm_count--;
402
+ }
403
+ }
404
+}
405
+EXPORT_SYMBOL_GPL(i2c_register_spd);
406
+#endif
407
+
215408 MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
216409 MODULE_DESCRIPTION("SMBus protocol extensions support");
217410 MODULE_LICENSE("GPL");