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#include "subdev/i2c.h"
26
27#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
28#define T_TIMEOUT 2200000
29#define T_RISEFALL 1000
30#define T_HOLD 5000
31
32static inline void
33i2c_drive_scl(struct nouveau_i2c_port *port, int state)
34{
35 nouveau_i2c_drive_scl(port, state);
36}
37
38static inline void
39i2c_drive_sda(struct nouveau_i2c_port *port, int state)
40{
41 nouveau_i2c_drive_sda(port, state);
42}
43
44static inline int
45i2c_sense_scl(struct nouveau_i2c_port *port)
46{
47 return nouveau_i2c_sense_scl(port);
48}
49
50static inline int
51i2c_sense_sda(struct nouveau_i2c_port *port)
52{
53 return nouveau_i2c_sense_sda(port);
54}
55
56static void
57i2c_delay(struct nouveau_i2c_port *port, u32 nsec)
58{
59 udelay((nsec + 500) / 1000);
60}
61
62static bool
63i2c_raise_scl(struct nouveau_i2c_port *port)
64{
65 u32 timeout = T_TIMEOUT / T_RISEFALL;
66
67 i2c_drive_scl(port, 1);
68 do {
69 i2c_delay(port, T_RISEFALL);
70 } while (!i2c_sense_scl(port) && --timeout);
71
72 return timeout != 0;
73}
74
75static int
76i2c_start(struct nouveau_i2c_port *port)
77{
78 int ret = 0;
79
80 port->state = i2c_sense_scl(port);
81 port->state |= i2c_sense_sda(port) << 1;
82 if (port->state != 3) {
83 i2c_drive_scl(port, 0);
84 i2c_drive_sda(port, 1);
85 if (!i2c_raise_scl(port))
86 ret = -EBUSY;
87 }
88
89 i2c_drive_sda(port, 0);
90 i2c_delay(port, T_HOLD);
91 i2c_drive_scl(port, 0);
92 i2c_delay(port, T_HOLD);
93 return ret;
94}
95
96static void
97i2c_stop(struct nouveau_i2c_port *port)
98{
99 i2c_drive_scl(port, 0);
100 i2c_drive_sda(port, 0);
101 i2c_delay(port, T_RISEFALL);
102
103 i2c_drive_scl(port, 1);
104 i2c_delay(port, T_HOLD);
105 i2c_drive_sda(port, 1);
106 i2c_delay(port, T_HOLD);
107}
108
109static int
110i2c_bitw(struct nouveau_i2c_port *port, int sda)
111{
112 i2c_drive_sda(port, sda);
113 i2c_delay(port, T_RISEFALL);
114
115 if (!i2c_raise_scl(port))
116 return -ETIMEDOUT;
117 i2c_delay(port, T_HOLD);
118
119 i2c_drive_scl(port, 0);
120 i2c_delay(port, T_HOLD);
121 return 0;
122}
123
124static int
125i2c_bitr(struct nouveau_i2c_port *port)
126{
127 int sda;
128
129 i2c_drive_sda(port, 1);
130 i2c_delay(port, T_RISEFALL);
131
132 if (!i2c_raise_scl(port))
133 return -ETIMEDOUT;
134 i2c_delay(port, T_HOLD);
135
136 sda = i2c_sense_sda(port);
137
138 i2c_drive_scl(port, 0);
139 i2c_delay(port, T_HOLD);
140 return sda;
141}
142
143static int
144i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last)
145{
146 int i, bit;
147
148 *byte = 0;
149 for (i = 7; i >= 0; i--) {
150 bit = i2c_bitr(port);
151 if (bit < 0)
152 return bit;
153 *byte |= bit << i;
154 }
155
156 return i2c_bitw(port, last ? 1 : 0);
157}
158
159static int
160i2c_put_byte(struct nouveau_i2c_port *port, u8 byte)
161{
162 int i, ret;
163 for (i = 7; i >= 0; i--) {
164 ret = i2c_bitw(port, !!(byte & (1 << i)));
165 if (ret < 0)
166 return ret;
167 }
168
169 ret = i2c_bitr(port);
170 if (ret == 1)
171 ret = -EIO;
172 return ret;
173}
174
175static int
176i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg)
177{
178 u32 addr = msg->addr << 1;
179 if (msg->flags & I2C_M_RD)
180 addr |= 1;
181 return i2c_put_byte(port, addr);
182}
183
184static int
185i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
186{
187 struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap;
188 struct i2c_msg *msg = msgs;
189 int ret = 0, mcnt = num;
190
191 while (!ret && mcnt--) {
192 u8 remaining = msg->len;
193 u8 *ptr = msg->buf;
194
195 ret = i2c_start(port);
196 if (ret == 0)
197 ret = i2c_addr(port, msg);
198
199 if (msg->flags & I2C_M_RD) {
200 while (!ret && remaining--)
201 ret = i2c_get_byte(port, ptr++, !remaining);
202 } else {
203 while (!ret && remaining--)
204 ret = i2c_put_byte(port, *ptr++);
205 }
206
207 msg++;
208 }
209
210 i2c_stop(port);
211 return (ret < 0) ? ret : num;
212}
213#else
214static int
215i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
216{
217 return -ENODEV;
218}
219#endif
220
221static u32
222i2c_bit_func(struct i2c_adapter *adap)
223{
224 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
225}
226
227const struct i2c_algorithm nouveau_i2c_bit_algo = {
228 .master_xfer = i2c_bit_xfer,
229 .functionality = i2c_bit_func
230};
231