1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for the Conexant CX25821 PCIe bridge |
4 | * |
5 | * Copyright (C) 2009 Conexant Systems Inc. |
6 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> |
7 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver |
8 | */ |
9 | |
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/i2c.h> |
14 | #include "cx25821.h" |
15 | |
16 | static unsigned int i2c_debug; |
17 | module_param(i2c_debug, int, 0644); |
18 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]" ); |
19 | |
20 | static unsigned int i2c_scan; |
21 | module_param(i2c_scan, int, 0444); |
22 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time" ); |
23 | |
24 | #define dprintk(level, fmt, arg...) \ |
25 | do { \ |
26 | if (i2c_debug >= level) \ |
27 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ |
28 | } while (0) |
29 | |
30 | #define I2C_WAIT_DELAY 32 |
31 | #define I2C_WAIT_RETRY 64 |
32 | |
33 | #define I2C_EXTEND (1 << 3) |
34 | #define I2C_NOSTOP (1 << 4) |
35 | |
36 | static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) |
37 | { |
38 | struct cx25821_i2c *bus = i2c_adap->algo_data; |
39 | struct cx25821_dev *dev = bus->dev; |
40 | return cx_read(bus->reg_stat) & 0x01; |
41 | } |
42 | |
43 | static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) |
44 | { |
45 | struct cx25821_i2c *bus = i2c_adap->algo_data; |
46 | struct cx25821_dev *dev = bus->dev; |
47 | return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; |
48 | } |
49 | |
50 | static int i2c_wait_done(struct i2c_adapter *i2c_adap) |
51 | { |
52 | int count; |
53 | |
54 | for (count = 0; count < I2C_WAIT_RETRY; count++) { |
55 | if (!i2c_is_busy(i2c_adap)) |
56 | break; |
57 | udelay(I2C_WAIT_DELAY); |
58 | } |
59 | |
60 | if (I2C_WAIT_RETRY == count) |
61 | return 0; |
62 | |
63 | return 1; |
64 | } |
65 | |
66 | static int i2c_sendbytes(struct i2c_adapter *i2c_adap, |
67 | const struct i2c_msg *msg, int joined_rlen) |
68 | { |
69 | struct cx25821_i2c *bus = i2c_adap->algo_data; |
70 | struct cx25821_dev *dev = bus->dev; |
71 | u32 wdata, addr, ctrl; |
72 | int retval, cnt; |
73 | |
74 | if (joined_rlen) |
75 | dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n" , __func__, |
76 | msg->len, joined_rlen); |
77 | else |
78 | dprintk(1, "%s(msg->len=%d)\n" , __func__, msg->len); |
79 | |
80 | /* Deal with i2c probe functions with zero payload */ |
81 | if (msg->len == 0) { |
82 | cx_write(bus->reg_addr, msg->addr << 25); |
83 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); |
84 | |
85 | if (!i2c_wait_done(i2c_adap)) |
86 | return -EIO; |
87 | |
88 | if (!i2c_slave_did_ack(i2c_adap)) |
89 | return -EIO; |
90 | |
91 | dprintk(1, "%s(): returns 0\n" , __func__); |
92 | return 0; |
93 | } |
94 | |
95 | /* dev, reg + first byte */ |
96 | addr = (msg->addr << 25) | msg->buf[0]; |
97 | wdata = msg->buf[0]; |
98 | |
99 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); |
100 | |
101 | if (msg->len > 1) |
102 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
103 | else if (joined_rlen) |
104 | ctrl |= I2C_NOSTOP; |
105 | |
106 | cx_write(bus->reg_addr, addr); |
107 | cx_write(bus->reg_wdata, wdata); |
108 | cx_write(bus->reg_ctrl, ctrl); |
109 | |
110 | retval = i2c_wait_done(i2c_adap); |
111 | if (retval < 0) |
112 | goto err; |
113 | |
114 | if (retval == 0) |
115 | goto eio; |
116 | |
117 | if (i2c_debug) { |
118 | if (!(ctrl & I2C_NOSTOP)) |
119 | printk(" >\n" ); |
120 | } |
121 | |
122 | for (cnt = 1; cnt < msg->len; cnt++) { |
123 | /* following bytes */ |
124 | wdata = msg->buf[cnt]; |
125 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); |
126 | |
127 | if (cnt < msg->len - 1) |
128 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
129 | else if (joined_rlen) |
130 | ctrl |= I2C_NOSTOP; |
131 | |
132 | cx_write(bus->reg_addr, addr); |
133 | cx_write(bus->reg_wdata, wdata); |
134 | cx_write(bus->reg_ctrl, ctrl); |
135 | |
136 | retval = i2c_wait_done(i2c_adap); |
137 | if (retval < 0) |
138 | goto err; |
139 | |
140 | if (retval == 0) |
141 | goto eio; |
142 | |
143 | if (i2c_debug) { |
144 | dprintk(1, " %02x" , msg->buf[cnt]); |
145 | if (!(ctrl & I2C_NOSTOP)) |
146 | dprintk(1, " >\n" ); |
147 | } |
148 | } |
149 | |
150 | return msg->len; |
151 | |
152 | eio: |
153 | retval = -EIO; |
154 | err: |
155 | if (i2c_debug) |
156 | pr_err(" ERR: %d\n" , retval); |
157 | return retval; |
158 | } |
159 | |
160 | static int i2c_readbytes(struct i2c_adapter *i2c_adap, |
161 | const struct i2c_msg *msg, int joined) |
162 | { |
163 | struct cx25821_i2c *bus = i2c_adap->algo_data; |
164 | struct cx25821_dev *dev = bus->dev; |
165 | u32 ctrl, cnt; |
166 | int retval; |
167 | |
168 | if (i2c_debug && !joined) |
169 | dprintk(1, "6-%s(msg->len=%d)\n" , __func__, msg->len); |
170 | |
171 | /* Deal with i2c probe functions with zero payload */ |
172 | if (msg->len == 0) { |
173 | cx_write(bus->reg_addr, msg->addr << 25); |
174 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); |
175 | if (!i2c_wait_done(i2c_adap)) |
176 | return -EIO; |
177 | if (!i2c_slave_did_ack(i2c_adap)) |
178 | return -EIO; |
179 | |
180 | dprintk(1, "%s(): returns 0\n" , __func__); |
181 | return 0; |
182 | } |
183 | |
184 | if (i2c_debug) { |
185 | if (joined) |
186 | dprintk(1, " R" ); |
187 | else |
188 | dprintk(1, " <R %02x" , (msg->addr << 1) + 1); |
189 | } |
190 | |
191 | for (cnt = 0; cnt < msg->len; cnt++) { |
192 | |
193 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; |
194 | |
195 | if (cnt < msg->len - 1) |
196 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
197 | |
198 | cx_write(bus->reg_addr, msg->addr << 25); |
199 | cx_write(bus->reg_ctrl, ctrl); |
200 | |
201 | retval = i2c_wait_done(i2c_adap); |
202 | if (retval < 0) |
203 | goto err; |
204 | if (retval == 0) |
205 | goto eio; |
206 | msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; |
207 | |
208 | if (i2c_debug) { |
209 | dprintk(1, " %02x" , msg->buf[cnt]); |
210 | if (!(ctrl & I2C_NOSTOP)) |
211 | dprintk(1, " >\n" ); |
212 | } |
213 | } |
214 | |
215 | return msg->len; |
216 | eio: |
217 | retval = -EIO; |
218 | err: |
219 | if (i2c_debug) |
220 | pr_err(" ERR: %d\n" , retval); |
221 | return retval; |
222 | } |
223 | |
224 | static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) |
225 | { |
226 | struct cx25821_i2c *bus = i2c_adap->algo_data; |
227 | struct cx25821_dev *dev = bus->dev; |
228 | int i, retval = 0; |
229 | |
230 | dprintk(1, "%s(num = %d)\n" , __func__, num); |
231 | |
232 | for (i = 0; i < num; i++) { |
233 | dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" , |
234 | __func__, num, msgs[i].addr, msgs[i].len); |
235 | |
236 | if (msgs[i].flags & I2C_M_RD) { |
237 | /* read */ |
238 | retval = i2c_readbytes(i2c_adap, msg: &msgs[i], joined: 0); |
239 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && |
240 | msgs[i].addr == msgs[i + 1].addr) { |
241 | /* write then read from same address */ |
242 | retval = i2c_sendbytes(i2c_adap, msg: &msgs[i], |
243 | joined_rlen: msgs[i + 1].len); |
244 | |
245 | if (retval < 0) |
246 | goto err; |
247 | i++; |
248 | retval = i2c_readbytes(i2c_adap, msg: &msgs[i], joined: 1); |
249 | } else { |
250 | /* write */ |
251 | retval = i2c_sendbytes(i2c_adap, msg: &msgs[i], joined_rlen: 0); |
252 | } |
253 | |
254 | if (retval < 0) |
255 | goto err; |
256 | } |
257 | return num; |
258 | |
259 | err: |
260 | return retval; |
261 | } |
262 | |
263 | |
264 | static u32 cx25821_functionality(struct i2c_adapter *adap) |
265 | { |
266 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA | |
267 | I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; |
268 | } |
269 | |
270 | static const struct i2c_algorithm cx25821_i2c_algo_template = { |
271 | .master_xfer = i2c_xfer, |
272 | .functionality = cx25821_functionality, |
273 | #ifdef NEED_ALGO_CONTROL |
274 | .algo_control = dummy_algo_control, |
275 | #endif |
276 | }; |
277 | |
278 | static const struct i2c_adapter cx25821_i2c_adap_template = { |
279 | .name = "cx25821" , |
280 | .owner = THIS_MODULE, |
281 | .algo = &cx25821_i2c_algo_template, |
282 | }; |
283 | |
284 | static const struct i2c_client cx25821_i2c_client_template = { |
285 | .name = "cx25821 internal" , |
286 | }; |
287 | |
288 | /* init + register i2c adapter */ |
289 | int cx25821_i2c_register(struct cx25821_i2c *bus) |
290 | { |
291 | struct cx25821_dev *dev = bus->dev; |
292 | |
293 | dprintk(1, "%s(bus = %d)\n" , __func__, bus->nr); |
294 | |
295 | bus->i2c_adap = cx25821_i2c_adap_template; |
296 | bus->i2c_client = cx25821_i2c_client_template; |
297 | bus->i2c_adap.dev.parent = &dev->pci->dev; |
298 | |
299 | strscpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); |
300 | |
301 | bus->i2c_adap.algo_data = bus; |
302 | i2c_set_adapdata(adap: &bus->i2c_adap, data: &dev->v4l2_dev); |
303 | i2c_add_adapter(adap: &bus->i2c_adap); |
304 | |
305 | bus->i2c_client.adapter = &bus->i2c_adap; |
306 | |
307 | /* set up the I2c */ |
308 | bus->i2c_client.addr = (0x88 >> 1); |
309 | |
310 | return bus->i2c_rc; |
311 | } |
312 | |
313 | int cx25821_i2c_unregister(struct cx25821_i2c *bus) |
314 | { |
315 | i2c_del_adapter(adap: &bus->i2c_adap); |
316 | return 0; |
317 | } |
318 | |
319 | #if 0 /* Currently unused */ |
320 | static void cx25821_av_clk(struct cx25821_dev *dev, int enable) |
321 | { |
322 | /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ |
323 | char buffer[3]; |
324 | struct i2c_msg msg; |
325 | dprintk(1, "%s(enabled = %d)\n" , __func__, enable); |
326 | |
327 | /* Register 0x144 */ |
328 | buffer[0] = 0x01; |
329 | buffer[1] = 0x44; |
330 | if (enable == 1) |
331 | buffer[2] = 0x05; |
332 | else |
333 | buffer[2] = 0x00; |
334 | |
335 | msg.addr = 0x44; |
336 | msg.flags = I2C_M_TEN; |
337 | msg.len = 3; |
338 | msg.buf = buffer; |
339 | |
340 | i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1); |
341 | } |
342 | #endif |
343 | |
344 | int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value) |
345 | { |
346 | struct i2c_client *client = &bus->i2c_client; |
347 | int v = 0; |
348 | u8 addr[2] = { 0, 0 }; |
349 | u8 buf[4] = { 0, 0, 0, 0 }; |
350 | |
351 | struct i2c_msg msgs[2] = { |
352 | { |
353 | .addr = client->addr, |
354 | .flags = 0, |
355 | .len = 2, |
356 | .buf = addr, |
357 | }, { |
358 | .addr = client->addr, |
359 | .flags = I2C_M_RD, |
360 | .len = 4, |
361 | .buf = buf, |
362 | } |
363 | }; |
364 | |
365 | addr[0] = (reg_addr >> 8); |
366 | addr[1] = (reg_addr & 0xff); |
367 | msgs[0].addr = 0x44; |
368 | msgs[1].addr = 0x44; |
369 | |
370 | i2c_xfer(i2c_adap: client->adapter, msgs, num: 2); |
371 | |
372 | v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; |
373 | *value = v; |
374 | |
375 | return v; |
376 | } |
377 | |
378 | int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value) |
379 | { |
380 | struct i2c_client *client = &bus->i2c_client; |
381 | int retval = 0; |
382 | u8 buf[6] = { 0, 0, 0, 0, 0, 0 }; |
383 | |
384 | struct i2c_msg msgs[1] = { |
385 | { |
386 | .addr = client->addr, |
387 | .flags = 0, |
388 | .len = 6, |
389 | .buf = buf, |
390 | } |
391 | }; |
392 | |
393 | buf[0] = reg_addr >> 8; |
394 | buf[1] = reg_addr & 0xff; |
395 | buf[5] = (value >> 24) & 0xff; |
396 | buf[4] = (value >> 16) & 0xff; |
397 | buf[3] = (value >> 8) & 0xff; |
398 | buf[2] = value & 0xff; |
399 | client->flags = 0; |
400 | msgs[0].addr = 0x44; |
401 | |
402 | retval = i2c_xfer(i2c_adap: client->adapter, msgs, num: 1); |
403 | |
404 | return retval; |
405 | } |
406 | |