Commit | Line | Data |
---|---|---|
42afd061 | 1 | #include <linux/i2c.h> |
79fcce32 | 2 | #include <linux/mutex.h> |
7a707b89 | 3 | #include <linux/module.h> |
42afd061 PB |
4 | |
5 | #include "dibx000_common.h" | |
6 | ||
7 | static int debug; | |
8 | module_param(debug, int, 0644); | |
9 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | |
10 | ||
03245a5e | 11 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) |
42afd061 PB |
12 | |
13 | static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) | |
14 | { | |
79fcce32 PB |
15 | int ret; |
16 | ||
17 | if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { | |
18 | dprintk("could not acquire lock"); | |
19 | return -EINVAL; | |
20 | } | |
21 | ||
5a0deeed OG |
22 | mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; |
23 | mst->i2c_write_buffer[1] = reg & 0xff; | |
24 | mst->i2c_write_buffer[2] = (val >> 8) & 0xff; | |
25 | mst->i2c_write_buffer[3] = val & 0xff; | |
26 | ||
27 | memset(mst->msg, 0, sizeof(struct i2c_msg)); | |
28 | mst->msg[0].addr = mst->i2c_addr; | |
29 | mst->msg[0].flags = 0; | |
30 | mst->msg[0].buf = mst->i2c_write_buffer; | |
31 | mst->msg[0].len = 4; | |
32 | ||
79fcce32 PB |
33 | ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; |
34 | mutex_unlock(&mst->i2c_buffer_lock); | |
35 | ||
36 | return ret; | |
42afd061 PB |
37 | } |
38 | ||
b994d192 OG |
39 | static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) |
40 | { | |
79fcce32 PB |
41 | u16 ret; |
42 | ||
43 | if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { | |
44 | dprintk("could not acquire lock"); | |
45 | return 0; | |
46 | } | |
47 | ||
5a0deeed OG |
48 | mst->i2c_write_buffer[0] = reg >> 8; |
49 | mst->i2c_write_buffer[1] = reg & 0xff; | |
50 | ||
51 | memset(mst->msg, 0, 2 * sizeof(struct i2c_msg)); | |
52 | mst->msg[0].addr = mst->i2c_addr; | |
53 | mst->msg[0].flags = 0; | |
54 | mst->msg[0].buf = mst->i2c_write_buffer; | |
55 | mst->msg[0].len = 2; | |
56 | mst->msg[1].addr = mst->i2c_addr; | |
57 | mst->msg[1].flags = I2C_M_RD; | |
58 | mst->msg[1].buf = mst->i2c_read_buffer; | |
59 | mst->msg[1].len = 2; | |
60 | ||
61 | if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) | |
b994d192 OG |
62 | dprintk("i2c read error on %d", reg); |
63 | ||
79fcce32 PB |
64 | ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; |
65 | mutex_unlock(&mst->i2c_buffer_lock); | |
66 | ||
67 | return ret; | |
b994d192 OG |
68 | } |
69 | ||
70 | static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) | |
71 | { | |
b4d6046e | 72 | int i = 100; |
b994d192 OG |
73 | u16 status; |
74 | ||
b4d6046e OG |
75 | while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0) |
76 | ; | |
b994d192 OG |
77 | |
78 | /* i2c timed out */ | |
79 | if (i == 0) | |
80 | return -EREMOTEIO; | |
81 | ||
82 | /* no acknowledge */ | |
83 | if ((status & 0x0080) == 0) | |
84 | return -EREMOTEIO; | |
85 | ||
86 | return 0; | |
87 | } | |
88 | ||
89 | static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop) | |
90 | { | |
91 | u16 data; | |
92 | u16 da; | |
93 | u16 i; | |
94 | u16 txlen = msg->len, len; | |
95 | const u8 *b = msg->buf; | |
96 | ||
97 | while (txlen) { | |
b4d6046e | 98 | dibx000_read_word(mst, mst->base_reg + 2); |
b994d192 OG |
99 | |
100 | len = txlen > 8 ? 8 : txlen; | |
101 | for (i = 0; i < len; i += 2) { | |
102 | data = *b++ << 8; | |
103 | if (i+1 < len) | |
104 | data |= *b++; | |
105 | dibx000_write_word(mst, mst->base_reg, data); | |
106 | } | |
b4d6046e OG |
107 | da = (((u8) (msg->addr)) << 9) | |
108 | (1 << 8) | | |
109 | (1 << 7) | | |
110 | (0 << 6) | | |
111 | (0 << 5) | | |
112 | ((len & 0x7) << 2) | | |
113 | (0 << 1) | | |
114 | (0 << 0); | |
b994d192 OG |
115 | |
116 | if (txlen == msg->len) | |
117 | da |= 1 << 5; /* start */ | |
118 | ||
119 | if (txlen-len == 0 && stop) | |
120 | da |= 1 << 6; /* stop */ | |
121 | ||
122 | dibx000_write_word(mst, mst->base_reg+1, da); | |
123 | ||
124 | if (dibx000_is_i2c_done(mst) != 0) | |
125 | return -EREMOTEIO; | |
126 | txlen -= len; | |
127 | } | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg) | |
133 | { | |
134 | u16 da; | |
135 | u8 *b = msg->buf; | |
136 | u16 rxlen = msg->len, len; | |
137 | ||
138 | while (rxlen) { | |
139 | len = rxlen > 8 ? 8 : rxlen; | |
b4d6046e OG |
140 | da = (((u8) (msg->addr)) << 9) | |
141 | (1 << 8) | | |
142 | (1 << 7) | | |
143 | (0 << 6) | | |
144 | (0 << 5) | | |
145 | ((len & 0x7) << 2) | | |
146 | (1 << 1) | | |
147 | (0 << 0); | |
b994d192 OG |
148 | |
149 | if (rxlen == msg->len) | |
150 | da |= 1 << 5; /* start */ | |
151 | ||
152 | if (rxlen-len == 0) | |
153 | da |= 1 << 6; /* stop */ | |
154 | dibx000_write_word(mst, mst->base_reg+1, da); | |
155 | ||
156 | if (dibx000_is_i2c_done(mst) != 0) | |
157 | return -EREMOTEIO; | |
158 | ||
159 | rxlen -= len; | |
160 | ||
161 | while (len) { | |
162 | da = dibx000_read_word(mst, mst->base_reg); | |
163 | *b++ = (da >> 8) & 0xff; | |
164 | len--; | |
165 | if (len >= 1) { | |
166 | *b++ = da & 0xff; | |
167 | len--; | |
168 | } | |
169 | } | |
170 | } | |
171 | ||
172 | return 0; | |
173 | } | |
174 | ||
175 | int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed) | |
176 | { | |
177 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); | |
178 | ||
179 | if (mst->device_rev < DIB7000MC && speed < 235) | |
180 | speed = 235; | |
181 | return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed)); | |
182 | ||
183 | } | |
184 | EXPORT_SYMBOL(dibx000_i2c_set_speed); | |
185 | ||
186 | static u32 dibx000_i2c_func(struct i2c_adapter *adapter) | |
187 | { | |
188 | return I2C_FUNC_I2C; | |
189 | } | |
42afd061 | 190 | |
77e2c0f5 PB |
191 | static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, |
192 | enum dibx000_i2c_interface intf) | |
42afd061 PB |
193 | { |
194 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { | |
03245a5e | 195 | dprintk("selecting interface: %d", intf); |
42afd061 PB |
196 | mst->selected_interface = intf; |
197 | return dibx000_write_word(mst, mst->base_reg + 4, intf); | |
198 | } | |
199 | return 0; | |
200 | } | |
201 | ||
b994d192 OG |
202 | static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) |
203 | { | |
204 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); | |
205 | int msg_index; | |
206 | int ret = 0; | |
207 | ||
208 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2); | |
b4d6046e OG |
209 | for (msg_index = 0; msg_index < num; msg_index++) { |
210 | if (msg[msg_index].flags & I2C_M_RD) { | |
b994d192 OG |
211 | ret = dibx000_master_i2c_read(mst, &msg[msg_index]); |
212 | if (ret != 0) | |
213 | return 0; | |
b4d6046e | 214 | } else { |
b994d192 OG |
215 | ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); |
216 | if (ret != 0) | |
217 | return 0; | |
218 | } | |
219 | } | |
220 | ||
221 | return num; | |
222 | } | |
223 | ||
224 | static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) | |
225 | { | |
226 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); | |
227 | int msg_index; | |
228 | int ret = 0; | |
229 | ||
230 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4); | |
b4d6046e OG |
231 | for (msg_index = 0; msg_index < num; msg_index++) { |
232 | if (msg[msg_index].flags & I2C_M_RD) { | |
b994d192 OG |
233 | ret = dibx000_master_i2c_read(mst, &msg[msg_index]); |
234 | if (ret != 0) | |
235 | return 0; | |
b4d6046e | 236 | } else { |
b994d192 OG |
237 | ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); |
238 | if (ret != 0) | |
239 | return 0; | |
240 | } | |
241 | } | |
242 | ||
243 | return num; | |
244 | } | |
245 | ||
246 | static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = { | |
247 | .master_xfer = dibx000_i2c_master_xfer_gpio12, | |
248 | .functionality = dibx000_i2c_func, | |
249 | }; | |
250 | ||
251 | static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = { | |
252 | .master_xfer = dibx000_i2c_master_xfer_gpio34, | |
253 | .functionality = dibx000_i2c_func, | |
254 | }; | |
255 | ||
77e2c0f5 PB |
256 | static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], |
257 | u8 addr, int onoff) | |
42afd061 PB |
258 | { |
259 | u16 val; | |
260 | ||
261 | ||
262 | if (onoff) | |
77e2c0f5 | 263 | val = addr << 8; // bit 7 = use master or not, if 0, the gate is open |
42afd061 PB |
264 | else |
265 | val = 1 << 7; | |
266 | ||
267 | if (mst->device_rev > DIB7000) | |
268 | val <<= 1; | |
269 | ||
270 | tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); | |
77e2c0f5 | 271 | tx[1] = ((mst->base_reg + 1) & 0xff); |
42afd061 PB |
272 | tx[2] = val >> 8; |
273 | tx[3] = val & 0xff; | |
274 | ||
275 | return 0; | |
276 | } | |
277 | ||
b994d192 OG |
278 | static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, |
279 | struct i2c_msg msg[], int num) | |
42afd061 | 280 | { |
b994d192 | 281 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); |
79fcce32 | 282 | int ret; |
b994d192 | 283 | |
5a0deeed OG |
284 | if (num > 32) { |
285 | dprintk("%s: too much I2C message to be transmitted (%i).\ | |
286 | Maximum is 32", __func__, num); | |
287 | return -ENOMEM; | |
288 | } | |
289 | ||
b994d192 OG |
290 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); |
291 | ||
79fcce32 PB |
292 | if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { |
293 | dprintk("could not acquire lock"); | |
294 | return -EINVAL; | |
295 | } | |
296 | ||
297 | memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); | |
298 | ||
5a0deeed OG |
299 | /* open the gate */ |
300 | dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); | |
301 | mst->msg[0].addr = mst->i2c_addr; | |
302 | mst->msg[0].buf = &mst->i2c_write_buffer[0]; | |
303 | mst->msg[0].len = 4; | |
b994d192 | 304 | |
5a0deeed | 305 | memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); |
b994d192 | 306 | |
5a0deeed OG |
307 | /* close the gate */ |
308 | dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); | |
309 | mst->msg[num + 1].addr = mst->i2c_addr; | |
310 | mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; | |
311 | mst->msg[num + 1].len = 4; | |
b994d192 | 312 | |
79fcce32 PB |
313 | ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? |
314 | num : -EIO); | |
315 | ||
316 | mutex_unlock(&mst->i2c_buffer_lock); | |
317 | return ret; | |
42afd061 PB |
318 | } |
319 | ||
b994d192 OG |
320 | static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { |
321 | .master_xfer = dibx000_i2c_gated_gpio67_xfer, | |
322 | .functionality = dibx000_i2c_func, | |
323 | }; | |
324 | ||
77e2c0f5 PB |
325 | static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, |
326 | struct i2c_msg msg[], int num) | |
42afd061 PB |
327 | { |
328 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); | |
79fcce32 | 329 | int ret; |
42afd061 | 330 | |
5a0deeed OG |
331 | if (num > 32) { |
332 | dprintk("%s: too much I2C message to be transmitted (%i).\ | |
333 | Maximum is 32", __func__, num); | |
334 | return -ENOMEM; | |
335 | } | |
336 | ||
42afd061 PB |
337 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); |
338 | ||
79fcce32 PB |
339 | if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { |
340 | dprintk("could not acquire lock"); | |
341 | return -EINVAL; | |
342 | } | |
343 | memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); | |
344 | ||
5a0deeed OG |
345 | /* open the gate */ |
346 | dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); | |
347 | mst->msg[0].addr = mst->i2c_addr; | |
348 | mst->msg[0].buf = &mst->i2c_write_buffer[0]; | |
349 | mst->msg[0].len = 4; | |
42afd061 | 350 | |
5a0deeed | 351 | memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); |
42afd061 | 352 | |
5a0deeed OG |
353 | /* close the gate */ |
354 | dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); | |
355 | mst->msg[num + 1].addr = mst->i2c_addr; | |
356 | mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; | |
357 | mst->msg[num + 1].len = 4; | |
42afd061 | 358 | |
79fcce32 PB |
359 | ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? |
360 | num : -EIO); | |
361 | mutex_unlock(&mst->i2c_buffer_lock); | |
362 | return ret; | |
42afd061 PB |
363 | } |
364 | ||
365 | static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { | |
77e2c0f5 | 366 | .master_xfer = dibx000_i2c_gated_tuner_xfer, |
42afd061 PB |
367 | .functionality = dibx000_i2c_func, |
368 | }; | |
369 | ||
77e2c0f5 | 370 | struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, |
b994d192 OG |
371 | enum dibx000_i2c_interface intf, |
372 | int gating) | |
42afd061 PB |
373 | { |
374 | struct i2c_adapter *i2c = NULL; | |
375 | ||
376 | switch (intf) { | |
77e2c0f5 PB |
377 | case DIBX000_I2C_INTERFACE_TUNER: |
378 | if (gating) | |
379 | i2c = &mst->gated_tuner_i2c_adap; | |
380 | break; | |
b994d192 OG |
381 | case DIBX000_I2C_INTERFACE_GPIO_1_2: |
382 | if (!gating) | |
383 | i2c = &mst->master_i2c_adap_gpio12; | |
384 | break; | |
385 | case DIBX000_I2C_INTERFACE_GPIO_3_4: | |
386 | if (!gating) | |
387 | i2c = &mst->master_i2c_adap_gpio34; | |
388 | break; | |
389 | case DIBX000_I2C_INTERFACE_GPIO_6_7: | |
390 | if (gating) | |
391 | i2c = &mst->master_i2c_adap_gpio67; | |
392 | break; | |
77e2c0f5 PB |
393 | default: |
394 | printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); | |
395 | break; | |
42afd061 PB |
396 | } |
397 | ||
398 | return i2c; | |
399 | } | |
77e2c0f5 | 400 | |
42afd061 PB |
401 | EXPORT_SYMBOL(dibx000_get_i2c_adapter); |
402 | ||
77e2c0f5 PB |
403 | void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) |
404 | { | |
405 | /* initialize the i2c-master by closing the gate */ | |
406 | u8 tx[4]; | |
407 | struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 }; | |
408 | ||
409 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); | |
410 | i2c_transfer(mst->i2c_adap, &m, 1); | |
411 | mst->selected_interface = 0xff; // the first time force a select of the I2C | |
412 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); | |
413 | } | |
414 | ||
415 | EXPORT_SYMBOL(dibx000_reset_i2c_master); | |
416 | ||
417 | static int i2c_adapter_init(struct i2c_adapter *i2c_adap, | |
b994d192 OG |
418 | struct i2c_algorithm *algo, const char *name, |
419 | struct dibx000_i2c_master *mst) | |
42afd061 | 420 | { |
2096b956 | 421 | strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); |
2c2742da | 422 | i2c_adap->algo = algo; |
42afd061 PB |
423 | i2c_adap->algo_data = NULL; |
424 | i2c_set_adapdata(i2c_adap, mst); | |
425 | if (i2c_add_adapter(i2c_adap) < 0) | |
426 | return -ENODEV; | |
427 | return 0; | |
428 | } | |
429 | ||
77e2c0f5 | 430 | int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, |
b994d192 | 431 | struct i2c_adapter *i2c_adap, u8 i2c_addr) |
42afd061 | 432 | { |
79fcce32 PB |
433 | int ret; |
434 | ||
435 | mutex_init(&mst->i2c_buffer_lock); | |
436 | if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { | |
437 | dprintk("could not acquire lock"); | |
438 | return -EINVAL; | |
439 | } | |
440 | memset(mst->msg, 0, sizeof(struct i2c_msg)); | |
441 | mst->msg[0].addr = i2c_addr >> 1; | |
442 | mst->msg[0].flags = 0; | |
443 | mst->msg[0].buf = mst->i2c_write_buffer; | |
444 | mst->msg[0].len = 4; | |
42afd061 PB |
445 | |
446 | mst->device_rev = device_rev; | |
77e2c0f5 PB |
447 | mst->i2c_adap = i2c_adap; |
448 | mst->i2c_addr = i2c_addr >> 1; | |
42afd061 | 449 | |
77e2c0f5 | 450 | if (device_rev == DIB7000P || device_rev == DIB8000) |
42afd061 PB |
451 | mst->base_reg = 1024; |
452 | else | |
453 | mst->base_reg = 768; | |
454 | ||
b994d192 OG |
455 | mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent; |
456 | if (i2c_adapter_init | |
457 | (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, | |
458 | "DiBX000 tuner I2C bus", mst) != 0) | |
459 | printk(KERN_ERR | |
460 | "DiBX000: could not initialize the tuner i2c_adapter\n"); | |
461 | ||
462 | mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent; | |
463 | if (i2c_adapter_init | |
464 | (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo, | |
465 | "DiBX000 master GPIO12 I2C bus", mst) != 0) | |
466 | printk(KERN_ERR | |
467 | "DiBX000: could not initialize the master i2c_adapter\n"); | |
468 | ||
469 | mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent; | |
470 | if (i2c_adapter_init | |
471 | (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo, | |
472 | "DiBX000 master GPIO34 I2C bus", mst) != 0) | |
473 | printk(KERN_ERR | |
474 | "DiBX000: could not initialize the master i2c_adapter\n"); | |
475 | ||
476 | mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent; | |
77e2c0f5 | 477 | if (i2c_adapter_init |
b994d192 OG |
478 | (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo, |
479 | "DiBX000 master GPIO67 I2C bus", mst) != 0) | |
77e2c0f5 | 480 | printk(KERN_ERR |
b994d192 | 481 | "DiBX000: could not initialize the master i2c_adapter\n"); |
42afd061 PB |
482 | |
483 | /* initialize the i2c-master by closing the gate */ | |
79fcce32 PB |
484 | dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0); |
485 | ||
486 | ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1); | |
487 | mutex_unlock(&mst->i2c_buffer_lock); | |
42afd061 | 488 | |
79fcce32 | 489 | return ret; |
42afd061 | 490 | } |
77e2c0f5 | 491 | |
42afd061 PB |
492 | EXPORT_SYMBOL(dibx000_init_i2c_master); |
493 | ||
494 | void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) | |
495 | { | |
496 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); | |
b994d192 OG |
497 | i2c_del_adapter(&mst->master_i2c_adap_gpio12); |
498 | i2c_del_adapter(&mst->master_i2c_adap_gpio34); | |
499 | i2c_del_adapter(&mst->master_i2c_adap_gpio67); | |
42afd061 PB |
500 | } |
501 | EXPORT_SYMBOL(dibx000_exit_i2c_master); | |
c6d74c2c | 502 | |
03245a5e | 503 | |
7ccf1eea | 504 | u32 systime(void) |
03245a5e | 505 | { |
b994d192 | 506 | struct timespec t; |
03245a5e | 507 | |
b994d192 OG |
508 | t = current_kernel_time(); |
509 | return (t.tv_sec * 10000) + (t.tv_nsec / 100000); | |
03245a5e OG |
510 | } |
511 | EXPORT_SYMBOL(systime); | |
512 | ||
99e44da7 | 513 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); |
c6d74c2c PB |
514 | MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); |
515 | MODULE_LICENSE("GPL"); |