Merge tag 'icc-5.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/djakov...
[linux-2.6-microblaze.git] / drivers / i2c / i2c-core-slave.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Linux I2C core slave support code
4  *
5  * Copyright (C) 2014 by Wolfram Sang <wsa@sang-engineering.com>
6  */
7
8 #include <dt-bindings/i2c/i2c.h>
9 #include <linux/acpi.h>
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/i2c.h>
13 #include <linux/of.h>
14
15 #include "i2c-core.h"
16
17 int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
18 {
19         int ret;
20
21         if (WARN(IS_ERR_OR_NULL(client) || !slave_cb, "insufficient data\n"))
22                 return -EINVAL;
23
24         if (!(client->flags & I2C_CLIENT_SLAVE))
25                 dev_warn(&client->dev, "%s: client slave flag not set. You might see address collisions\n",
26                          __func__);
27
28         if (!(client->flags & I2C_CLIENT_TEN)) {
29                 /* Enforce stricter address checking */
30                 ret = i2c_check_7bit_addr_validity_strict(client->addr);
31                 if (ret) {
32                         dev_err(&client->dev, "%s: invalid address\n", __func__);
33                         return ret;
34                 }
35         }
36
37         if (!client->adapter->algo->reg_slave) {
38                 dev_err(&client->dev, "%s: not supported by adapter\n", __func__);
39                 return -EOPNOTSUPP;
40         }
41
42         client->slave_cb = slave_cb;
43
44         i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
45         ret = client->adapter->algo->reg_slave(client);
46         i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
47
48         if (ret) {
49                 client->slave_cb = NULL;
50                 dev_err(&client->dev, "%s: adapter returned error %d\n", __func__, ret);
51         }
52
53         return ret;
54 }
55 EXPORT_SYMBOL_GPL(i2c_slave_register);
56
57 int i2c_slave_unregister(struct i2c_client *client)
58 {
59         int ret;
60
61         if (IS_ERR_OR_NULL(client))
62                 return -EINVAL;
63
64         if (!client->adapter->algo->unreg_slave) {
65                 dev_err(&client->dev, "%s: not supported by adapter\n", __func__);
66                 return -EOPNOTSUPP;
67         }
68
69         i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
70         ret = client->adapter->algo->unreg_slave(client);
71         i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
72
73         if (ret == 0)
74                 client->slave_cb = NULL;
75         else
76                 dev_err(&client->dev, "%s: adapter returned error %d\n", __func__, ret);
77
78         return ret;
79 }
80 EXPORT_SYMBOL_GPL(i2c_slave_unregister);
81
82 /**
83  * i2c_detect_slave_mode - detect operation mode
84  * @dev: The device owning the bus
85  *
86  * This checks the device nodes for an I2C slave by checking the address
87  * used in the reg property. If the address match the I2C_OWN_SLAVE_ADDRESS
88  * flag this means the device is configured to act as a I2C slave and it will
89  * be listening at that address.
90  *
91  * Returns true if an I2C own slave address is detected, otherwise returns
92  * false.
93  */
94 bool i2c_detect_slave_mode(struct device *dev)
95 {
96         if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
97                 struct device_node *child;
98                 u32 reg;
99
100                 for_each_child_of_node(dev->of_node, child) {
101                         of_property_read_u32(child, "reg", &reg);
102                         if (reg & I2C_OWN_SLAVE_ADDRESS) {
103                                 of_node_put(child);
104                                 return true;
105                         }
106                 }
107         } else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
108                 dev_dbg(dev, "ACPI slave is not supported yet\n");
109         }
110         return false;
111 }
112 EXPORT_SYMBOL_GPL(i2c_detect_slave_mode);