• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/media/dvb/b2c2/
1/*
2 * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
3 * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
4 * see flexcop.c for copyright information
5 */
6#include "flexcop.h"
7
8#define FC_MAX_I2C_RETRIES 100000
9
10static int flexcop_i2c_operation(struct flexcop_device *fc,
11		flexcop_ibi_value *r100)
12{
13	int i;
14	flexcop_ibi_value r;
15
16	r100->tw_sm_c_100.working_start = 1;
17	deb_i2c("r100 before: %08x\n",r100->raw);
18
19	fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
20	fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
21
22	for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
23		r = fc->read_ibi_reg(fc, tw_sm_c_100);
24
25		if (!r.tw_sm_c_100.no_base_addr_ack_error) {
26			if (r.tw_sm_c_100.st_done) {
27				*r100 = r;
28				deb_i2c("i2c success\n");
29				return 0;
30			}
31		} else {
32			deb_i2c("suffering from an i2c ack_error\n");
33			return -EREMOTEIO;
34		}
35	}
36	deb_i2c("tried %d times i2c operation, "
37			"never finished or too many ack errors.\n", i);
38	return -EREMOTEIO;
39}
40
41static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
42		flexcop_ibi_value r100, u8 *buf)
43{
44	flexcop_ibi_value r104;
45	int len = r100.tw_sm_c_100.total_bytes,
46		/* remember total_bytes is buflen-1 */
47		ret;
48
49	if (i2c->fc->dev_type == FC_SKY_REV27)
50		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
51
52	ret = flexcop_i2c_operation(i2c->fc, &r100);
53	if (ret != 0) {
54		deb_i2c("Retrying operation\n");
55		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
56		ret = flexcop_i2c_operation(i2c->fc, &r100);
57	}
58	if (ret != 0) {
59		deb_i2c("read failed. %d\n", ret);
60		return ret;
61	}
62
63	buf[0] = r100.tw_sm_c_100.data1_reg;
64
65	if (len > 0) {
66		r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
67		deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
68
69		/* there is at least one more byte, otherwise we wouldn't be here */
70		buf[1] = r104.tw_sm_c_104.data2_reg;
71		if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
72		if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
73	}
74	return 0;
75}
76
77static int flexcop_i2c_write4(struct flexcop_device *fc,
78		flexcop_ibi_value r100, u8 *buf)
79{
80	flexcop_ibi_value r104;
81	int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
82	r104.raw = 0;
83
84	/* there is at least one byte, otherwise we wouldn't be here */
85	r100.tw_sm_c_100.data1_reg = buf[0];
86	r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
87	r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
88	r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
89
90	deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
91
92	/* write the additional i2c data before doing the actual i2c operation */
93	fc->write_ibi_reg(fc, tw_sm_c_104, r104);
94	return flexcop_i2c_operation(fc, &r100);
95}
96
97int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
98		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
99{
100	int ret;
101
102#ifdef DUMP_I2C_MESSAGES
103	int i;
104#endif
105
106	u16 bytes_to_transfer;
107	flexcop_ibi_value r100;
108
109	deb_i2c("op = %d\n",op);
110	r100.raw = 0;
111	r100.tw_sm_c_100.chipaddr = chipaddr;
112	r100.tw_sm_c_100.twoWS_rw = op;
113	r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
114
115#ifdef DUMP_I2C_MESSAGES
116	printk(KERN_DEBUG "%d ", i2c->port);
117	if (op == FC_READ)
118		printk("rd(");
119	else
120		printk("wr(");
121	printk("%02x): %02x ", chipaddr, addr);
122#endif
123
124	/* in that case addr is the only value ->
125	 * we write it twice as baseaddr and val0
126	 * BBTI is doing it like that for ISL6421 at least */
127	if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
128		buf = &addr;
129		len = 1;
130	}
131
132	while (len != 0) {
133		bytes_to_transfer = len > 4 ? 4 : len;
134
135		r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
136		r100.tw_sm_c_100.baseaddr = addr;
137
138		if (op == FC_READ)
139			ret = flexcop_i2c_read4(i2c, r100, buf);
140		else
141			ret = flexcop_i2c_write4(i2c->fc, r100, buf);
142
143#ifdef DUMP_I2C_MESSAGES
144		for (i = 0; i < bytes_to_transfer; i++)
145			printk("%02x ", buf[i]);
146#endif
147
148		if (ret < 0)
149			return ret;
150
151		buf  += bytes_to_transfer;
152		addr += bytes_to_transfer;
153		len  -= bytes_to_transfer;
154	}
155
156#ifdef DUMP_I2C_MESSAGES
157	printk("\n");
158#endif
159
160	return 0;
161}
162/* exported for PCI i2c */
163EXPORT_SYMBOL(flexcop_i2c_request);
164
165/* master xfer callback for demodulator */
166static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
167		struct i2c_msg msgs[], int num)
168{
169	struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
170	int i, ret = 0;
171
172	/* Some drivers use 1 byte or 0 byte reads as probes, which this
173	 * driver doesn't support.  These probes will always fail, so this
174	 * hack makes them always succeed.  If one knew how, it would of
175	 * course be better to actually do the read.  */
176	if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
177		return 1;
178
179	if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
180		return -ERESTARTSYS;
181
182	for (i = 0; i < num; i++) {
183		/* reading */
184		if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
185			ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
186					msgs[i].buf[0], msgs[i+1].buf,
187					msgs[i+1].len);
188			i++; /* skip the following message */
189		} else /* writing */
190			ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
191					msgs[i].buf[0], &msgs[i].buf[1],
192					msgs[i].len - 1);
193		if (ret < 0) {
194			deb_i2c("i2c master_xfer failed");
195			break;
196		}
197	}
198
199	mutex_unlock(&i2c->fc->i2c_mutex);
200
201	if (ret == 0)
202		ret = num;
203	return ret;
204}
205
206static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
207{
208	return I2C_FUNC_I2C;
209}
210
211static struct i2c_algorithm flexcop_algo = {
212	.master_xfer	= flexcop_master_xfer,
213	.functionality	= flexcop_i2c_func,
214};
215
216int flexcop_i2c_init(struct flexcop_device *fc)
217{
218	int ret;
219	mutex_init(&fc->i2c_mutex);
220
221	fc->fc_i2c_adap[0].fc = fc;
222	fc->fc_i2c_adap[1].fc = fc;
223	fc->fc_i2c_adap[2].fc = fc;
224	fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
225	fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
226	fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
227
228	strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
229			sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
230	strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
231			sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
232	strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
233			sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
234
235	i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
236	i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
237	i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
238
239	fc->fc_i2c_adap[0].i2c_adap.class =
240		fc->fc_i2c_adap[1].i2c_adap.class =
241		fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL;
242	fc->fc_i2c_adap[0].i2c_adap.algo =
243		fc->fc_i2c_adap[1].i2c_adap.algo =
244		fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
245	fc->fc_i2c_adap[0].i2c_adap.algo_data =
246		fc->fc_i2c_adap[1].i2c_adap.algo_data =
247		fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
248	fc->fc_i2c_adap[0].i2c_adap.dev.parent =
249		fc->fc_i2c_adap[1].i2c_adap.dev.parent =
250		fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
251
252	ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
253	if (ret < 0)
254		return ret;
255
256	ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
257	if (ret < 0)
258		goto adap_1_failed;
259
260	ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
261	if (ret < 0)
262		goto adap_2_failed;
263
264	fc->init_state |= FC_STATE_I2C_INIT;
265	return 0;
266
267adap_2_failed:
268	i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
269adap_1_failed:
270	i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
271	return ret;
272}
273
274void flexcop_i2c_exit(struct flexcop_device *fc)
275{
276	if (fc->init_state & FC_STATE_I2C_INIT) {
277		i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
278		i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
279		i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
280	}
281	fc->init_state &= ~FC_STATE_I2C_INIT;
282}
283