[go: nahoru, domu]

142afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher#include <linux/i2c.h>
279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher#include <linux/mutex.h>
37a707b89202f905bd9f9fbde326933c59a81214cPaul Gortmaker#include <linux/module.h>
442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher#include "dibx000_common.h"
642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcherstatic int debug;
842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettchermodule_param(debug, int, 0644);
942afd061700edb43bb082bc65a2ddde431151d6bPatrick BoettcherMODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
1042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
1103245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0)
1242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
1342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcherstatic int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
1442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
1579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	int ret;
1679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
1779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
1879fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		dprintk("could not acquire lock");
1979fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		return -EINVAL;
2079fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	}
2179fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
225a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
235a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->i2c_write_buffer[1] = reg & 0xff;
245a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
255a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->i2c_write_buffer[3] = val & 0xff;
265a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie
275a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	memset(mst->msg, 0, sizeof(struct i2c_msg));
285a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].addr = mst->i2c_addr;
295a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].flags = 0;
305a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].buf = mst->i2c_write_buffer;
315a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].len = 4;
325a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie
3379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
3479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mutex_unlock(&mst->i2c_buffer_lock);
3579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
3679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	return ret;
3742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
3842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
39b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
40b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
4179fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	u16 ret;
4279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
4379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
4479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		dprintk("could not acquire lock");
4579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		return 0;
4679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	}
4779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
485a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->i2c_write_buffer[0] = reg >> 8;
495a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->i2c_write_buffer[1] = reg & 0xff;
505a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie
515a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
525a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].addr = mst->i2c_addr;
535a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].flags = 0;
545a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].buf = mst->i2c_write_buffer;
555a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].len = 2;
565a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[1].addr = mst->i2c_addr;
575a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[1].flags = I2C_M_RD;
585a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[1].buf = mst->i2c_read_buffer;
595a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[1].len = 2;
605a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie
615a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
62b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		dprintk("i2c read error on %d", reg);
63b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
6479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
6579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mutex_unlock(&mst->i2c_buffer_lock);
6679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
6779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	return ret;
68b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
69b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
70b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
71b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
72b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie	int i = 100;
73b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 status;
74b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
75b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie	while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0)
76b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		;
77b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
78b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	/* i2c timed out */
79b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	if (i == 0)
80b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		return -EREMOTEIO;
81b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
82b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	/* no acknowledge */
83b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	if ((status & 0x0080) == 0)
84b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		return -EREMOTEIO;
85b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
86b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return 0;
87b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
88b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
89b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop)
90b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
91b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 data;
92b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 da;
93b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 i;
94b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 txlen = msg->len, len;
95b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	const u8 *b = msg->buf;
96b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
97b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	while (txlen) {
98b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		dibx000_read_word(mst, mst->base_reg + 2);
99b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
100b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		len = txlen > 8 ? 8 : txlen;
101b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		for (i = 0; i < len; i += 2) {
102b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			data = *b++ << 8;
103b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			if (i+1 < len)
104b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				data |= *b++;
105b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			dibx000_write_word(mst, mst->base_reg, data);
106b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		}
107b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		da = (((u8) (msg->addr))  << 9) |
108b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(1           << 8) |
109b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(1           << 7) |
110b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 6) |
111b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 5) |
112b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			((len & 0x7) << 2) |
113b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 1) |
114b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 0);
115b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
116b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (txlen == msg->len)
117b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			da |= 1 << 5; /* start */
118b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
119b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (txlen-len == 0 && stop)
120b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			da |= 1 << 6; /* stop */
121b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
122b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		dibx000_write_word(mst, mst->base_reg+1, da);
123b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
124b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (dibx000_is_i2c_done(mst) != 0)
125b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			return -EREMOTEIO;
126b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		txlen -= len;
127b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	}
128b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
129b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return 0;
130b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
131b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
132b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg)
133b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
134b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 da;
135b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u8 *b = msg->buf;
136b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	u16 rxlen = msg->len, len;
137b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
138b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	while (rxlen) {
139b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		len = rxlen > 8 ? 8 : rxlen;
140b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		da = (((u8) (msg->addr)) << 9) |
141b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(1           << 8) |
142b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(1           << 7) |
143b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 6) |
144b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 5) |
145b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			((len & 0x7) << 2) |
146b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(1           << 1) |
147b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie			(0           << 0);
148b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
149b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (rxlen == msg->len)
150b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			da |= 1 << 5; /* start */
151b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
152b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (rxlen-len == 0)
153b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			da |= 1 << 6; /* stop */
154b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		dibx000_write_word(mst, mst->base_reg+1, da);
155b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
156b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (dibx000_is_i2c_done(mst) != 0)
157b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			return -EREMOTEIO;
158b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
159b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		rxlen -= len;
160b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
161b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		while (len) {
162b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			da = dibx000_read_word(mst, mst->base_reg);
163b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			*b++ = (da >> 8) & 0xff;
164b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			len--;
165b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			if (len >= 1) {
166b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				*b++ =  da   & 0xff;
167b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				len--;
168b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			}
169b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		}
170b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	}
171b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
172b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return 0;
173b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
174b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
175b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenieint dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed)
176b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
177b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
178b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
179b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	if (mst->device_rev < DIB7000MC && speed < 235)
180b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		speed = 235;
181b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed));
182b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
183b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
184b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier GrenieEXPORT_SYMBOL(dibx000_i2c_set_speed);
185b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
186b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic u32 dibx000_i2c_func(struct i2c_adapter *adapter)
187b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
188b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return I2C_FUNC_I2C;
189b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
19042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
19177e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcherstatic int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
19277e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher					enum dibx000_i2c_interface intf)
19342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
19442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
19503245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie		dprintk("selecting interface: %d", intf);
19642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		mst->selected_interface = intf;
19742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		return dibx000_write_word(mst, mst->base_reg + 4, intf);
19842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	}
19942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	return 0;
20042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
20142afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
202b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
203b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
204b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
205b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	int msg_index;
206b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	int ret = 0;
207b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
208b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2);
209b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie	for (msg_index = 0; msg_index < num; msg_index++) {
210b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		if (msg[msg_index].flags & I2C_M_RD) {
211b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
212b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			if (ret != 0)
213b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				return 0;
214b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		} else {
215b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
216b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			if (ret != 0)
217b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				return 0;
218b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		}
219b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	}
220b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
221b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return num;
222b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
223b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
224b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
225b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie{
226b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
227b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	int msg_index;
228b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	int ret = 0;
229b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
230b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4);
231b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie	for (msg_index = 0; msg_index < num; msg_index++) {
232b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		if (msg[msg_index].flags & I2C_M_RD) {
233b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
234b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			if (ret != 0)
235b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				return 0;
236b4d6046e841955be9cc49164b03b91c9524f9c2eOlivier Grenie		} else {
237b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
238b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			if (ret != 0)
239b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				return 0;
240b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		}
241b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	}
242b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
243b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return num;
244b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie}
245b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
246b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = {
247b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	.master_xfer = dibx000_i2c_master_xfer_gpio12,
248b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	.functionality = dibx000_i2c_func,
249b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie};
250b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
251b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = {
252b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	.master_xfer = dibx000_i2c_master_xfer_gpio34,
253b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	.functionality = dibx000_i2c_func,
254b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie};
255b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
25677e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcherstatic int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
25777e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher				 u8 addr, int onoff)
25842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
25942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	u16 val;
26042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
26142afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
26242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	if (onoff)
26377e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher		val = addr << 8;	// bit 7 = use master or not, if 0, the gate is open
26442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	else
26542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		val = 1 << 7;
26642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
26742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	if (mst->device_rev > DIB7000)
26842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		val <<= 1;
26942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
27042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
27177e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	tx[1] = ((mst->base_reg + 1) & 0xff);
27242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	tx[2] = val >> 8;
27342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	tx[3] = val & 0xff;
27442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
27542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	return 0;
27642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
27742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
278b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
279b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie					struct i2c_msg msg[], int num)
28042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
281b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
28279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	int ret;
283b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
2845a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	if (num > 32) {
2855a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie		dprintk("%s: too much I2C message to be transmitted (%i).\
2865a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie				Maximum is 32", __func__, num);
2875a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie		return -ENOMEM;
2885a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	}
2895a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie
290b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
291b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
29279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
29379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		dprintk("could not acquire lock");
29479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		return -EINVAL;
29579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	}
29679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
29779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
29879fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
2995a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	/* open the gate */
3005a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
3015a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].addr = mst->i2c_addr;
3025a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].buf = &mst->i2c_write_buffer[0];
3035a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].len = 4;
304b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
3055a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
306b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
3075a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	/* close the gate */
3085a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
3095a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[num + 1].addr = mst->i2c_addr;
3105a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
3115a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[num + 1].len = 4;
312b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
31379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
31479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher			num : -EIO);
31579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
31679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mutex_unlock(&mst->i2c_buffer_lock);
31779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	return ret;
31842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
31942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
320b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Greniestatic struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
321b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	.master_xfer = dibx000_i2c_gated_gpio67_xfer,
322b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	.functionality = dibx000_i2c_func,
323b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie};
324b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
32577e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcherstatic int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
32677e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher					struct i2c_msg msg[], int num)
32742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
32842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
32979fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	int ret;
33042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
3315a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	if (num > 32) {
3325a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie		dprintk("%s: too much I2C message to be transmitted (%i).\
3335a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie				Maximum is 32", __func__, num);
3345a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie		return -ENOMEM;
3355a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	}
3365a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie
33742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
33842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
33979fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
34079fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		dprintk("could not acquire lock");
34179fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		return -EINVAL;
34279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	}
34379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
34479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
3455a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	/* open the gate */
3465a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
3475a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].addr = mst->i2c_addr;
3485a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].buf = &mst->i2c_write_buffer[0];
3495a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[0].len = 4;
35042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
3515a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
35242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
3535a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	/* close the gate */
3545a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
3555a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[num + 1].addr = mst->i2c_addr;
3565a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
3575a0deeed5741117ee8625d6305d0034e219f102cOlivier Grenie	mst->msg[num + 1].len = 4;
35842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
35979fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
36079fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher			num : -EIO);
36179fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mutex_unlock(&mst->i2c_buffer_lock);
36279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	return ret;
36342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
36442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
36542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcherstatic struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
36677e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	.master_xfer = dibx000_i2c_gated_tuner_xfer,
36742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	.functionality = dibx000_i2c_func,
36842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher};
36942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
37077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcherstruct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
371b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie						enum dibx000_i2c_interface intf,
372b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie						int gating)
37342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
37442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	struct i2c_adapter *i2c = NULL;
37542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
37642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	switch (intf) {
37777e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	case DIBX000_I2C_INTERFACE_TUNER:
37877e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher		if (gating)
37977e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher			i2c = &mst->gated_tuner_i2c_adap;
38077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher		break;
381b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	case DIBX000_I2C_INTERFACE_GPIO_1_2:
382b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (!gating)
383b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			i2c = &mst->master_i2c_adap_gpio12;
384b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		break;
385b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	case DIBX000_I2C_INTERFACE_GPIO_3_4:
386b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (!gating)
387b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			i2c = &mst->master_i2c_adap_gpio34;
388b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		break;
389b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	case DIBX000_I2C_INTERFACE_GPIO_6_7:
390b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		if (gating)
391b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			i2c = &mst->master_i2c_adap_gpio67;
392b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		break;
39377e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	default:
39477e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher		printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
39577e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher		break;
39642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	}
39742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
39842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	return i2c;
39942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
40077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher
40142afd061700edb43bb082bc65a2ddde431151d6bPatrick BoettcherEXPORT_SYMBOL(dibx000_get_i2c_adapter);
40242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
40377e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettchervoid dibx000_reset_i2c_master(struct dibx000_i2c_master *mst)
40477e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher{
40577e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	/* initialize the i2c-master by closing the gate */
40677e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	u8 tx[4];
40777e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 };
40877e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher
40977e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
41077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	i2c_transfer(mst->i2c_adap, &m, 1);
41177e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	mst->selected_interface = 0xff;	// the first time force a select of the I2C
41277e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
41377e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher}
41477e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher
41577e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick BoettcherEXPORT_SYMBOL(dibx000_reset_i2c_master);
41677e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher
41777e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcherstatic int i2c_adapter_init(struct i2c_adapter *i2c_adap,
418b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				struct i2c_algorithm *algo, const char *name,
419b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				struct dibx000_i2c_master *mst)
42042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
4212096b956d24c4b5950b808fc23b218425d79ebb1David Brownell	strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
4222c2742da1e590f426e8d85ce4e33b69142245fb8Jean Delvare	i2c_adap->algo = algo;
42342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	i2c_adap->algo_data = NULL;
42442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	i2c_set_adapdata(i2c_adap, mst);
42542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	if (i2c_add_adapter(i2c_adap) < 0)
42642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		return -ENODEV;
42742afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	return 0;
42842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
42942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
43077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcherint dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
431b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				struct i2c_adapter *i2c_adap, u8 i2c_addr)
43242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
43379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	int ret;
43479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
43579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mutex_init(&mst->i2c_buffer_lock);
43679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
43779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		dprintk("could not acquire lock");
43879fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher		return -EINVAL;
43979fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	}
44079fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	memset(mst->msg, 0, sizeof(struct i2c_msg));
44179fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mst->msg[0].addr = i2c_addr >> 1;
44279fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mst->msg[0].flags = 0;
44379fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mst->msg[0].buf = mst->i2c_write_buffer;
44479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mst->msg[0].len = 4;
44542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
44642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	mst->device_rev = device_rev;
44777e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	mst->i2c_adap = i2c_adap;
44877e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	mst->i2c_addr = i2c_addr >> 1;
44942afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
45077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	if (device_rev == DIB7000P || device_rev == DIB8000)
45142afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		mst->base_reg = 1024;
45242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	else
45342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher		mst->base_reg = 768;
45442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
455b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent;
456b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	if (i2c_adapter_init
457b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
458b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			 "DiBX000 tuner I2C bus", mst) != 0)
459b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		printk(KERN_ERR
460b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				"DiBX000: could not initialize the tuner i2c_adapter\n");
461b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
462b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent;
463b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	if (i2c_adapter_init
464b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			(&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo,
465b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			 "DiBX000 master GPIO12 I2C bus", mst) != 0)
466b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		printk(KERN_ERR
467b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				"DiBX000: could not initialize the master i2c_adapter\n");
468b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
469b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent;
470b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	if (i2c_adapter_init
471b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			(&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo,
472b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			 "DiBX000 master GPIO34 I2C bus", mst) != 0)
473b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie		printk(KERN_ERR
474b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				"DiBX000: could not initialize the master i2c_adapter\n");
475b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie
476b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent;
47777e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher	if (i2c_adapter_init
478b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			(&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo,
479b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie			 "DiBX000 master GPIO67 I2C bus", mst) != 0)
48077e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher		printk(KERN_ERR
481b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie				"DiBX000: could not initialize the master i2c_adapter\n");
48242afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
48342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	/* initialize the i2c-master by closing the gate */
48479fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
48579fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher
48679fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
48779fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	mutex_unlock(&mst->i2c_buffer_lock);
48842afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
48979fcce3230b140f7675f8529ee53fe2f9644f902Patrick Boettcher	return ret;
49042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
49177e2c0f5d471e2b14140f0695a1b6a718f318dd7Patrick Boettcher
49242afd061700edb43bb082bc65a2ddde431151d6bPatrick BoettcherEXPORT_SYMBOL(dibx000_init_i2c_master);
49342afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher
49442afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettchervoid dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
49542afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher{
49642afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher	i2c_del_adapter(&mst->gated_tuner_i2c_adap);
497b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	i2c_del_adapter(&mst->master_i2c_adap_gpio12);
498b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	i2c_del_adapter(&mst->master_i2c_adap_gpio34);
499b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	i2c_del_adapter(&mst->master_i2c_adap_gpio67);
50042afd061700edb43bb082bc65a2ddde431151d6bPatrick Boettcher}
50142afd061700edb43bb082bc65a2ddde431151d6bPatrick BoettcherEXPORT_SYMBOL(dibx000_exit_i2c_master);
502c6d74c2ce86a80c9859010eb65e622214a6993edPatrick Boettcher
50303245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie
5047ccf1eea972177064b4df9d5ba68958604781db6Randy Dunlapu32 systime(void)
50503245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie{
506b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	struct timespec t;
50703245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie
508b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	t = current_kernel_time();
509b994d19268756b640ccc76f0b0d47ee13c0f8af9Olivier Grenie	return (t.tv_sec * 10000) + (t.tv_nsec / 100000);
51003245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie}
51103245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier GrenieEXPORT_SYMBOL(systime);
51203245a5ee69a5faa99b020fe1aca9bafe10c46a9Olivier Grenie
513c6d74c2ce86a80c9859010eb65e622214a6993edPatrick BoettcherMODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
514c6d74c2ce86a80c9859010eb65e622214a6993edPatrick BoettcherMODULE_DESCRIPTION("Common function the DiBcom demodulator family");
515c6d74c2ce86a80c9859010eb65e622214a6993edPatrick BoettcherMODULE_LICENSE("GPL");
516