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