Merge branch 'vendor/OPENSSH'
[dragonfly.git] / sys / dev / drm / linux_i2c.c
1 /*
2  * Copyright (c) 2016 François Tigeot
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 static struct lock i2c_lock;
31 LOCK_SYSINIT(i2c_lock, &i2c_lock, "i2cl", LK_CANRECURSE);
32
33 int
34 i2c_add_adapter(struct i2c_adapter *adapter)
35 {
36         /* Linux registers a unique bus number here */
37         return 0;
38 }
39
40 void
41 i2c_del_adapter(struct i2c_adapter *adapter)
42 {
43         /* Linux deletes a unique bus number here */
44 }
45
46 /*
47  * i2c_transfer()
48  * The original Linux implementation does:
49  * 1. return -EOPNOTSUPP if adapter->algo->master_xfer is NULL
50  * 2. try to transfer msgs by calling adapter->algo->master_xfer()
51  * 3. if it took more ticks than adapter->timeout, fail
52  * 4. if the transfer failed, retry up to adapter->retries times
53  * 5. return the result of the last call of adapter->algo->master_xfer()
54  */
55 int
56 i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
57 {
58         uint64_t start_ticks;
59         int ret, tries = 0;
60
61         if (adapter->algo->master_xfer == NULL)
62                 return -EOPNOTSUPP;
63
64         lockmgr(&i2c_lock, LK_EXCLUSIVE);
65         start_ticks = ticks;
66         do {
67                 ret = adapter->algo->master_xfer(adapter, msgs, num);
68                 if (ticks > start_ticks + adapter->timeout)
69                         break;
70                 if (ret != -EAGAIN)
71                         break;
72                 tries++;
73         } while (tries < adapter->retries);
74         lockmgr(&i2c_lock, LK_RELEASE);
75
76         return ret;
77 }
78
79 static int
80 bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
81 {
82         /* XXX Linux really does try to transfer some data here */
83         return 0;
84 }
85
86 static uint32_t
87 bit_func(struct i2c_adapter *adap)
88 {
89         return (I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
90                 I2C_FUNC_SMBUS_READ_BLOCK_DATA |
91                 I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
92                 I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING);
93 }
94
95 const struct i2c_algorithm i2c_bit_algo = {
96         .master_xfer    = bit_xfer,
97         .functionality  = bit_func,
98 };