xref: /dragonfly/sys/dev/drm/linux_i2c.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
1 /*
2  * Copyright (c) 2016-2020 François Tigeot <ftigeot@wolfpond.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <linux/i2c.h>
28 #include <linux/i2c-algo-bit.h>
29 
30 #include <linux/slab.h>
31 
32 static struct lock i2c_lock;
33 LOCK_SYSINIT(i2c_lock, &i2c_lock, "i2cl", LK_CANRECURSE);
34 
35 static void i2c_default_lock_bus(struct i2c_adapter *, unsigned int);
36 static int i2c_default_trylock_bus(struct i2c_adapter *, unsigned int);
37 static void i2c_default_unlock_bus(struct i2c_adapter *, unsigned int);
38 
39 static const struct i2c_lock_operations i2c_default_lock_ops = {
40           .lock_bus =    i2c_default_lock_bus,
41           .trylock_bus = i2c_default_trylock_bus,
42           .unlock_bus =  i2c_default_unlock_bus,
43 };
44 
45 int
i2c_add_adapter(struct i2c_adapter * adapter)46 i2c_add_adapter(struct i2c_adapter *adapter)
47 {
48           /* Linux registers a unique bus number here */
49 
50           /* Setup default locking functions */
51           if (!adapter->lock_ops)
52                     adapter->lock_ops = &i2c_default_lock_ops;
53 
54           return 0;
55 }
56 
57 void
i2c_del_adapter(struct i2c_adapter * adapter)58 i2c_del_adapter(struct i2c_adapter *adapter)
59 {
60           /* Linux deletes a unique bus number here */
61 }
62 
63 int
__i2c_transfer(struct i2c_adapter * adapter,struct i2c_msg * msgs,int num)64 __i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
65 {
66           uint64_t start_ticks;
67           int ret, tries = 0;
68 
69           start_ticks = ticks;
70           do {
71                     ret = adapter->algo->master_xfer(adapter, msgs, num);
72                     if (ticks > start_ticks + adapter->timeout)
73                               break;
74                     if (ret != -EAGAIN)
75                               break;
76                     tries++;
77           } while (tries < adapter->retries);
78 
79           return ret;
80 }
81 
82 /*
83  * i2c_transfer()
84  * The original Linux implementation does:
85  * 1. return -EOPNOTSUPP if adapter->algo->master_xfer is NULL
86  * 2. try to transfer msgs by calling adapter->algo->master_xfer()
87  * 3. if it took more ticks than adapter->timeout, fail
88  * 4. if the transfer failed, retry up to adapter->retries times
89  * 5. return the result of the last call of adapter->algo->master_xfer()
90  */
91 int
i2c_transfer(struct i2c_adapter * adapter,struct i2c_msg * msgs,int num)92 i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
93 {
94           int ret;
95 
96           if (adapter->algo->master_xfer == NULL)
97                     return -EOPNOTSUPP;
98 
99           adapter->lock_ops->lock_bus(adapter, I2C_LOCK_SEGMENT);
100           ret = __i2c_transfer(adapter, msgs, num);
101           adapter->lock_ops->unlock_bus(adapter, I2C_LOCK_SEGMENT);
102 
103           return ret;
104 }
105 
106 static int
bit_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msgs[],int num)107 bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
108 {
109           /* XXX Linux really does try to transfer some data here */
110           return 0;
111 }
112 
113 static uint32_t
bit_func(struct i2c_adapter * adap)114 bit_func(struct i2c_adapter *adap)
115 {
116           return (I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
117                     I2C_FUNC_SMBUS_READ_BLOCK_DATA |
118                     I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
119                     I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING);
120 }
121 
122 const struct i2c_algorithm i2c_bit_algo = {
123           .master_xfer        = bit_xfer,
124           .functionality      = bit_func,
125 };
126 
127 int
i2c_bit_add_bus(struct i2c_adapter * adapter)128 i2c_bit_add_bus(struct i2c_adapter *adapter)
129 {
130           adapter->algo = &i2c_bit_algo;
131           adapter->retries = 2;
132 
133           return 0;
134 }
135 
136 struct i2c_client *
i2c_new_device(struct i2c_adapter * adap,struct i2c_board_info const * info)137 i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
138 {
139           struct i2c_client *client;
140 
141           client = kzalloc(sizeof(*client), GFP_KERNEL);
142           if (client == NULL)
143                     goto done;
144 
145           client->adapter = adap;
146 
147           strlcpy(client->name, info->type, sizeof(client->name));
148           client->addr = info->addr;
149 
150 done:
151           return client;
152 }
153 
154 /* Default locking functions */
155 
156 static void
i2c_default_lock_bus(struct i2c_adapter * adapter,unsigned int flags)157 i2c_default_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
158 {
159           lockmgr(&i2c_lock, LK_EXCLUSIVE);
160 }
161 
162 static int
i2c_default_trylock_bus(struct i2c_adapter * adapter,unsigned int flags)163 i2c_default_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
164 {
165           return mutex_trylock(&i2c_lock);
166 }
167 
168 static void
i2c_default_unlock_bus(struct i2c_adapter * adapter,unsigned int flags)169 i2c_default_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
170 {
171           lockmgr(&i2c_lock, LK_RELEASE);
172 }
173