1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for the Conexant CX23885 PCIe bridge |
4 | * |
5 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> |
6 | */ |
7 | |
8 | #include "cx23885.h" |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/init.h> |
12 | #include <linux/delay.h> |
13 | #include <asm/io.h> |
14 | |
15 | #include <media/v4l2-common.h> |
16 | |
17 | static unsigned int i2c_debug; |
18 | module_param(i2c_debug, int, 0644); |
19 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]" ); |
20 | |
21 | static unsigned int i2c_scan; |
22 | module_param(i2c_scan, int, 0444); |
23 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time" ); |
24 | |
25 | #define dprintk(level, fmt, arg...)\ |
26 | do { if (i2c_debug >= level)\ |
27 | printk(KERN_DEBUG pr_fmt("%s: i2c:" fmt), \ |
28 | __func__, ##arg); \ |
29 | } while (0) |
30 | |
31 | #define I2C_WAIT_DELAY 32 |
32 | #define I2C_WAIT_RETRY 64 |
33 | |
34 | #define I2C_EXTEND (1 << 3) |
35 | #define I2C_NOSTOP (1 << 4) |
36 | |
37 | static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) |
38 | { |
39 | struct cx23885_i2c *bus = i2c_adap->algo_data; |
40 | struct cx23885_dev *dev = bus->dev; |
41 | return cx_read(bus->reg_stat) & 0x01; |
42 | } |
43 | |
44 | static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) |
45 | { |
46 | struct cx23885_i2c *bus = i2c_adap->algo_data; |
47 | struct cx23885_dev *dev = bus->dev; |
48 | return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; |
49 | } |
50 | |
51 | static int i2c_wait_done(struct i2c_adapter *i2c_adap) |
52 | { |
53 | int count; |
54 | |
55 | for (count = 0; count < I2C_WAIT_RETRY; count++) { |
56 | if (!i2c_is_busy(i2c_adap)) |
57 | break; |
58 | udelay(I2C_WAIT_DELAY); |
59 | } |
60 | |
61 | if (I2C_WAIT_RETRY == count) |
62 | return 0; |
63 | |
64 | return 1; |
65 | } |
66 | |
67 | static int i2c_sendbytes(struct i2c_adapter *i2c_adap, |
68 | const struct i2c_msg *msg, int joined_rlen) |
69 | { |
70 | struct cx23885_i2c *bus = i2c_adap->algo_data; |
71 | struct cx23885_dev *dev = bus->dev; |
72 | u32 wdata, addr, ctrl; |
73 | int retval, cnt; |
74 | |
75 | if (joined_rlen) |
76 | dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n" , __func__, |
77 | msg->len, joined_rlen); |
78 | else |
79 | dprintk(1, "%s(msg->len=%d)\n" , __func__, msg->len); |
80 | |
81 | /* Deal with i2c probe functions with zero payload */ |
82 | if (msg->len == 0) { |
83 | cx_write(bus->reg_addr, msg->addr << 25); |
84 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); |
85 | if (!i2c_wait_done(i2c_adap)) |
86 | return -EIO; |
87 | if (!i2c_slave_did_ack(i2c_adap)) |
88 | return -ENXIO; |
89 | |
90 | dprintk(1, "%s() returns 0\n" , __func__); |
91 | return 0; |
92 | } |
93 | |
94 | |
95 | /* dev, reg + first byte */ |
96 | addr = (msg->addr << 25) | msg->buf[0]; |
97 | wdata = msg->buf[0]; |
98 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); |
99 | |
100 | if (msg->len > 1) |
101 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
102 | else if (joined_rlen) |
103 | ctrl |= I2C_NOSTOP; |
104 | |
105 | cx_write(bus->reg_addr, addr); |
106 | cx_write(bus->reg_wdata, wdata); |
107 | cx_write(bus->reg_ctrl, ctrl); |
108 | |
109 | if (!i2c_wait_done(i2c_adap)) |
110 | goto eio; |
111 | if (i2c_debug) { |
112 | printk(KERN_DEBUG " <W %02x %02x" , msg->addr << 1, msg->buf[0]); |
113 | if (!(ctrl & I2C_NOSTOP)) |
114 | pr_cont(" >\n" ); |
115 | } |
116 | |
117 | for (cnt = 1; cnt < msg->len; cnt++) { |
118 | /* following bytes */ |
119 | wdata = msg->buf[cnt]; |
120 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); |
121 | |
122 | if (cnt < msg->len - 1) |
123 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
124 | else if (joined_rlen) |
125 | ctrl |= I2C_NOSTOP; |
126 | |
127 | cx_write(bus->reg_addr, addr); |
128 | cx_write(bus->reg_wdata, wdata); |
129 | cx_write(bus->reg_ctrl, ctrl); |
130 | |
131 | if (!i2c_wait_done(i2c_adap)) |
132 | goto eio; |
133 | if (i2c_debug) { |
134 | pr_cont(" %02x" , msg->buf[cnt]); |
135 | if (!(ctrl & I2C_NOSTOP)) |
136 | pr_cont(" >\n" ); |
137 | } |
138 | } |
139 | return msg->len; |
140 | |
141 | eio: |
142 | retval = -EIO; |
143 | if (i2c_debug) |
144 | pr_err(" ERR: %d\n" , retval); |
145 | return retval; |
146 | } |
147 | |
148 | static int i2c_readbytes(struct i2c_adapter *i2c_adap, |
149 | const struct i2c_msg *msg, int joined) |
150 | { |
151 | struct cx23885_i2c *bus = i2c_adap->algo_data; |
152 | struct cx23885_dev *dev = bus->dev; |
153 | u32 ctrl, cnt; |
154 | int retval; |
155 | |
156 | |
157 | if (i2c_debug && !joined) |
158 | dprintk(1, "%s(msg->len=%d)\n" , __func__, msg->len); |
159 | |
160 | /* Deal with i2c probe functions with zero payload */ |
161 | if (msg->len == 0) { |
162 | cx_write(bus->reg_addr, msg->addr << 25); |
163 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); |
164 | if (!i2c_wait_done(i2c_adap)) |
165 | return -EIO; |
166 | if (!i2c_slave_did_ack(i2c_adap)) |
167 | return -ENXIO; |
168 | |
169 | |
170 | dprintk(1, "%s() returns 0\n" , __func__); |
171 | return 0; |
172 | } |
173 | |
174 | if (i2c_debug) { |
175 | if (joined) |
176 | dprintk(1, " R" ); |
177 | else |
178 | dprintk(1, " <R %02x" , (msg->addr << 1) + 1); |
179 | } |
180 | |
181 | for (cnt = 0; cnt < msg->len; cnt++) { |
182 | |
183 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; |
184 | |
185 | if (cnt < msg->len - 1) |
186 | ctrl |= I2C_NOSTOP | I2C_EXTEND; |
187 | |
188 | cx_write(bus->reg_addr, msg->addr << 25); |
189 | cx_write(bus->reg_ctrl, ctrl); |
190 | |
191 | if (!i2c_wait_done(i2c_adap)) |
192 | goto eio; |
193 | msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; |
194 | if (i2c_debug) { |
195 | dprintk(1, " %02x" , msg->buf[cnt]); |
196 | if (!(ctrl & I2C_NOSTOP)) |
197 | dprintk(1, " >\n" ); |
198 | } |
199 | } |
200 | return msg->len; |
201 | |
202 | eio: |
203 | retval = -EIO; |
204 | if (i2c_debug) |
205 | pr_err(" ERR: %d\n" , retval); |
206 | return retval; |
207 | } |
208 | |
209 | static int i2c_xfer(struct i2c_adapter *i2c_adap, |
210 | struct i2c_msg *msgs, int num) |
211 | { |
212 | int i, retval = 0; |
213 | |
214 | dprintk(1, "%s(num = %d)\n" , __func__, num); |
215 | |
216 | for (i = 0 ; i < num; i++) { |
217 | dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" , |
218 | __func__, num, msgs[i].addr, msgs[i].len); |
219 | if (msgs[i].flags & I2C_M_RD) { |
220 | /* read */ |
221 | retval = i2c_readbytes(i2c_adap, msg: &msgs[i], joined: 0); |
222 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && |
223 | msgs[i].addr == msgs[i + 1].addr) { |
224 | /* write then read from same address */ |
225 | retval = i2c_sendbytes(i2c_adap, msg: &msgs[i], |
226 | joined_rlen: msgs[i + 1].len); |
227 | if (retval < 0) |
228 | goto err; |
229 | i++; |
230 | retval = i2c_readbytes(i2c_adap, msg: &msgs[i], joined: 1); |
231 | } else { |
232 | /* write */ |
233 | retval = i2c_sendbytes(i2c_adap, msg: &msgs[i], joined_rlen: 0); |
234 | } |
235 | if (retval < 0) |
236 | goto err; |
237 | } |
238 | return num; |
239 | |
240 | err: |
241 | return retval; |
242 | } |
243 | |
244 | static u32 cx23885_functionality(struct i2c_adapter *adap) |
245 | { |
246 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; |
247 | } |
248 | |
249 | static const struct i2c_algorithm cx23885_i2c_algo_template = { |
250 | .master_xfer = i2c_xfer, |
251 | .functionality = cx23885_functionality, |
252 | }; |
253 | |
254 | /* ----------------------------------------------------------------------- */ |
255 | |
256 | static const struct i2c_adapter cx23885_i2c_adap_template = { |
257 | .name = "cx23885" , |
258 | .owner = THIS_MODULE, |
259 | .algo = &cx23885_i2c_algo_template, |
260 | }; |
261 | |
262 | static const struct i2c_client cx23885_i2c_client_template = { |
263 | .name = "cx23885 internal" , |
264 | }; |
265 | |
266 | static char *i2c_devs[128] = { |
267 | [0x10 >> 1] = "tda10048" , |
268 | [0x12 >> 1] = "dib7000pc" , |
269 | [0x1c >> 1] = "lgdt3303" , |
270 | [0x80 >> 1] = "cs3308" , |
271 | [0x82 >> 1] = "cs3308" , |
272 | [0x86 >> 1] = "tda9887" , |
273 | [0x32 >> 1] = "cx24227" , |
274 | [0x88 >> 1] = "cx25837" , |
275 | [0x84 >> 1] = "tda8295" , |
276 | [0x98 >> 1] = "flatiron" , |
277 | [0xa0 >> 1] = "eeprom" , |
278 | [0xc0 >> 1] = "tuner/mt2131/tda8275" , |
279 | [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028" , |
280 | [0xc8 >> 1] = "tuner/xc3028L" , |
281 | }; |
282 | |
283 | static void do_i2c_scan(char *name, struct i2c_client *c) |
284 | { |
285 | unsigned char buf; |
286 | int i, rc; |
287 | |
288 | for (i = 0; i < 128; i++) { |
289 | c->addr = i; |
290 | rc = i2c_master_recv(client: c, buf: &buf, count: 0); |
291 | if (rc < 0) |
292 | continue; |
293 | pr_info("%s: i2c scan: found device @ 0x%04x [%s]\n" , |
294 | name, i, i2c_devs[i] ? i2c_devs[i] : "???" ); |
295 | } |
296 | } |
297 | |
298 | /* init + register i2c adapter */ |
299 | int cx23885_i2c_register(struct cx23885_i2c *bus) |
300 | { |
301 | struct cx23885_dev *dev = bus->dev; |
302 | |
303 | dprintk(1, "%s(bus = %d)\n" , __func__, bus->nr); |
304 | |
305 | bus->i2c_adap = cx23885_i2c_adap_template; |
306 | bus->i2c_client = cx23885_i2c_client_template; |
307 | bus->i2c_adap.dev.parent = &dev->pci->dev; |
308 | |
309 | strscpy(bus->i2c_adap.name, bus->dev->name, |
310 | sizeof(bus->i2c_adap.name)); |
311 | |
312 | bus->i2c_adap.algo_data = bus; |
313 | i2c_set_adapdata(adap: &bus->i2c_adap, data: &dev->v4l2_dev); |
314 | i2c_add_adapter(adap: &bus->i2c_adap); |
315 | |
316 | bus->i2c_client.adapter = &bus->i2c_adap; |
317 | |
318 | if (0 == bus->i2c_rc) { |
319 | dprintk(1, "%s: i2c bus %d registered\n" , dev->name, bus->nr); |
320 | if (i2c_scan) { |
321 | pr_info("%s: scan bus %d:\n" , |
322 | dev->name, bus->nr); |
323 | do_i2c_scan(name: dev->name, c: &bus->i2c_client); |
324 | } |
325 | } else |
326 | pr_warn("%s: i2c bus %d register FAILED\n" , |
327 | dev->name, bus->nr); |
328 | |
329 | /* Instantiate the IR receiver device, if present */ |
330 | if (0 == bus->i2c_rc) { |
331 | struct i2c_board_info info; |
332 | static const unsigned short addr_list[] = { |
333 | 0x6b, I2C_CLIENT_END |
334 | }; |
335 | |
336 | memset(&info, 0, sizeof(struct i2c_board_info)); |
337 | strscpy(info.type, "ir_video" , I2C_NAME_SIZE); |
338 | /* Use quick read command for probe, some IR chips don't |
339 | * support writes */ |
340 | i2c_new_scanned_device(adap: &bus->i2c_adap, info: &info, addr_list, |
341 | probe: i2c_probe_func_quick_read); |
342 | } |
343 | |
344 | return bus->i2c_rc; |
345 | } |
346 | |
347 | int cx23885_i2c_unregister(struct cx23885_i2c *bus) |
348 | { |
349 | i2c_del_adapter(adap: &bus->i2c_adap); |
350 | return 0; |
351 | } |
352 | |
353 | void cx23885_av_clk(struct cx23885_dev *dev, int enable) |
354 | { |
355 | /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ |
356 | char buffer[3]; |
357 | struct i2c_msg msg; |
358 | dprintk(1, "%s(enabled = %d)\n" , __func__, enable); |
359 | |
360 | /* Register 0x144 */ |
361 | buffer[0] = 0x01; |
362 | buffer[1] = 0x44; |
363 | if (enable == 1) |
364 | buffer[2] = 0x05; |
365 | else |
366 | buffer[2] = 0x00; |
367 | |
368 | msg.addr = 0x44; |
369 | msg.flags = I2C_M_TEN; |
370 | msg.len = 3; |
371 | msg.buf = buffer; |
372 | |
373 | i2c_xfer(i2c_adap: &dev->i2c_bus[2].i2c_adap, msgs: &msg, num: 1); |
374 | } |
375 | |