.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Linux I2C core SMBus and SMBus emulation code |
---|
3 | 4 | * |
---|
4 | 5 | * This file contains the SMBus functions which are always included in the I2C |
---|
5 | 6 | * core because they can be emulated via I2C. SMBus specific extensions |
---|
6 | | - * (e.g. smbalert) are handled in a seperate i2c-smbus module. |
---|
| 7 | + * (e.g. smbalert) are handled in a separate i2c-smbus module. |
---|
7 | 8 | * |
---|
8 | 9 | * All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> |
---|
9 | 10 | * SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and |
---|
10 | 11 | * Jean Delvare <jdelvare@suse.de> |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify it |
---|
13 | | - * under the terms of the GNU General Public License as published by the Free |
---|
14 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
15 | | - * any later version. |
---|
16 | 12 | */ |
---|
17 | 13 | #include <linux/device.h> |
---|
18 | 14 | #include <linux/err.h> |
---|
19 | 15 | #include <linux/i2c.h> |
---|
20 | 16 | #include <linux/i2c-smbus.h> |
---|
21 | 17 | #include <linux/slab.h> |
---|
| 18 | + |
---|
| 19 | +#include "i2c-core.h" |
---|
22 | 20 | |
---|
23 | 21 | #define CREATE_TRACE_POINTS |
---|
24 | 22 | #include <trace/events/smbus.h> |
---|
.. | .. |
---|
537 | 535 | { |
---|
538 | 536 | s32 res; |
---|
539 | 537 | |
---|
540 | | - i2c_lock_bus(adapter, I2C_LOCK_SEGMENT); |
---|
| 538 | + res = __i2c_lock_bus_helper(adapter); |
---|
| 539 | + if (res) |
---|
| 540 | + return res; |
---|
| 541 | + |
---|
541 | 542 | res = __i2c_smbus_xfer(adapter, addr, flags, read_write, |
---|
542 | 543 | command, protocol, data); |
---|
543 | 544 | i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); |
---|
.. | .. |
---|
550 | 551 | unsigned short flags, char read_write, |
---|
551 | 552 | u8 command, int protocol, union i2c_smbus_data *data) |
---|
552 | 553 | { |
---|
| 554 | + int (*xfer_func)(struct i2c_adapter *adap, u16 addr, |
---|
| 555 | + unsigned short flags, char read_write, |
---|
| 556 | + u8 command, int size, union i2c_smbus_data *data); |
---|
553 | 557 | unsigned long orig_jiffies; |
---|
554 | 558 | int try; |
---|
555 | 559 | s32 res; |
---|
| 560 | + |
---|
| 561 | + res = __i2c_check_suspended(adapter); |
---|
| 562 | + if (res) |
---|
| 563 | + return res; |
---|
556 | 564 | |
---|
557 | 565 | /* If enabled, the following two tracepoints are conditional on |
---|
558 | 566 | * read_write and protocol. |
---|
.. | .. |
---|
564 | 572 | |
---|
565 | 573 | flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; |
---|
566 | 574 | |
---|
567 | | - if (adapter->algo->smbus_xfer) { |
---|
| 575 | + xfer_func = adapter->algo->smbus_xfer; |
---|
| 576 | + if (i2c_in_atomic_xfer_mode()) { |
---|
| 577 | + if (adapter->algo->smbus_xfer_atomic) |
---|
| 578 | + xfer_func = adapter->algo->smbus_xfer_atomic; |
---|
| 579 | + else if (adapter->algo->master_xfer_atomic) |
---|
| 580 | + xfer_func = NULL; /* fallback to I2C emulation */ |
---|
| 581 | + } |
---|
| 582 | + |
---|
| 583 | + if (xfer_func) { |
---|
568 | 584 | /* Retry automatically on arbitration loss */ |
---|
569 | 585 | orig_jiffies = jiffies; |
---|
570 | 586 | for (res = 0, try = 0; try <= adapter->retries; try++) { |
---|
571 | | - res = adapter->algo->smbus_xfer(adapter, addr, flags, |
---|
572 | | - read_write, command, |
---|
573 | | - protocol, data); |
---|
| 587 | + res = xfer_func(adapter, addr, flags, read_write, |
---|
| 588 | + command, protocol, data); |
---|
574 | 589 | if (res != -EAGAIN) |
---|
575 | 590 | break; |
---|
576 | 591 | if (time_after(jiffies, |
---|
.. | .. |
---|
592 | 607 | trace: |
---|
593 | 608 | /* If enabled, the reply tracepoint is conditional on read_write. */ |
---|
594 | 609 | trace_smbus_reply(adapter, addr, flags, read_write, |
---|
595 | | - command, protocol, data); |
---|
| 610 | + command, protocol, data, res); |
---|
596 | 611 | trace_smbus_result(adapter, addr, flags, read_write, |
---|
597 | 612 | command, protocol, res); |
---|
598 | 613 | |
---|
.. | .. |
---|
658 | 673 | EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); |
---|
659 | 674 | |
---|
660 | 675 | /** |
---|
661 | | - * i2c_setup_smbus_alert - Setup SMBus alert support |
---|
| 676 | + * i2c_new_smbus_alert_device - get ara client for SMBus alert support |
---|
662 | 677 | * @adapter: the target adapter |
---|
663 | 678 | * @setup: setup data for the SMBus alert handler |
---|
664 | 679 | * Context: can sleep |
---|
.. | .. |
---|
668 | 683 | * Handling can be done either through our IRQ handler, or by the |
---|
669 | 684 | * adapter (from its handler, periodic polling, or whatever). |
---|
670 | 685 | * |
---|
671 | | - * NOTE that if we manage the IRQ, we *MUST* know if it's level or |
---|
672 | | - * edge triggered in order to hand it to the workqueue correctly. |
---|
673 | | - * If triggering the alert seems to wedge the system, you probably |
---|
674 | | - * should have said it's level triggered. |
---|
675 | | - * |
---|
676 | 686 | * This returns the ara client, which should be saved for later use with |
---|
677 | | - * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL |
---|
678 | | - * to indicate an error. |
---|
| 687 | + * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or an |
---|
| 688 | + * ERRPTR to indicate an error. |
---|
679 | 689 | */ |
---|
680 | | -struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, |
---|
681 | | - struct i2c_smbus_alert_setup *setup) |
---|
| 690 | +struct i2c_client *i2c_new_smbus_alert_device(struct i2c_adapter *adapter, |
---|
| 691 | + struct i2c_smbus_alert_setup *setup) |
---|
682 | 692 | { |
---|
683 | 693 | struct i2c_board_info ara_board_info = { |
---|
684 | 694 | I2C_BOARD_INFO("smbus_alert", 0x0c), |
---|
685 | 695 | .platform_data = setup, |
---|
686 | 696 | }; |
---|
687 | 697 | |
---|
688 | | - return i2c_new_device(adapter, &ara_board_info); |
---|
| 698 | + return i2c_new_client_device(adapter, &ara_board_info); |
---|
689 | 699 | } |
---|
690 | | -EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); |
---|
| 700 | +EXPORT_SYMBOL_GPL(i2c_new_smbus_alert_device); |
---|
691 | 701 | |
---|
692 | 702 | #if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) |
---|
693 | 703 | int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter) |
---|
694 | 704 | { |
---|
695 | | - struct i2c_client *client; |
---|
696 | 705 | int irq; |
---|
697 | 706 | |
---|
698 | 707 | irq = of_property_match_string(adapter->dev.of_node, "interrupt-names", |
---|
.. | .. |
---|
702 | 711 | else if (irq < 0) |
---|
703 | 712 | return irq; |
---|
704 | 713 | |
---|
705 | | - client = i2c_setup_smbus_alert(adapter, NULL); |
---|
706 | | - if (!client) |
---|
707 | | - return -ENODEV; |
---|
708 | | - |
---|
709 | | - return 0; |
---|
| 714 | + return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); |
---|
710 | 715 | } |
---|
711 | 716 | EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert); |
---|
712 | 717 | #endif |
---|