diff options
Diffstat (limited to 'drivers/media/dvb/b2c2/flexcop-i2c.c')
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-i2c.c | 116 |
1 files changed, 61 insertions, 55 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 736251f393c2..be4266d4ae91 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c | |||
@@ -9,9 +9,9 @@ | |||
9 | 9 | ||
10 | #define FC_MAX_I2C_RETRIES 100000 | 10 | #define FC_MAX_I2C_RETRIES 100000 |
11 | 11 | ||
12 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100, int max_ack_errors) | 12 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100) |
13 | { | 13 | { |
14 | int i,ack_errors = 0; | 14 | int i; |
15 | flexcop_ibi_value r; | 15 | flexcop_ibi_value r; |
16 | 16 | ||
17 | r100->tw_sm_c_100.working_start = 1; | 17 | r100->tw_sm_c_100.working_start = 1; |
@@ -31,11 +31,7 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r | |||
31 | } | 31 | } |
32 | } else { | 32 | } else { |
33 | deb_i2c("suffering from an i2c ack_error\n"); | 33 | deb_i2c("suffering from an i2c ack_error\n"); |
34 | if (++ack_errors >= max_ack_errors) | 34 | return -EREMOTEIO; |
35 | break; | ||
36 | |||
37 | fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); | ||
38 | fc->write_ibi_reg(fc, tw_sm_c_100, *r100); | ||
39 | } | 35 | } |
40 | } | 36 | } |
41 | deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i); | 37 | deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i); |
@@ -48,19 +44,30 @@ static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, | |||
48 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ | 44 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ |
49 | ret; | 45 | ret; |
50 | 46 | ||
51 | if ((ret = flexcop_i2c_operation(fc,&r100,30)) != 0) | 47 | if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { |
52 | return ret; | 48 | /* The Cablestar needs a different kind of i2c-transfer (does not |
53 | 49 | * support "Repeat Start"): | |
54 | r104 = fc->read_ibi_reg(fc,tw_sm_c_104); | 50 | * wait for the ACK failure, |
55 | 51 | * and do a subsequent read with the Bit 30 enabled | |
56 | deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | 52 | */ |
53 | r100.tw_sm_c_100.no_base_addr_ack_error = 1; | ||
54 | if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { | ||
55 | deb_i2c("no_base_addr read failed. %d\n",ret); | ||
56 | return ret; | ||
57 | } | ||
58 | } | ||
57 | 59 | ||
58 | /* there is at least one byte, otherwise we wouldn't be here */ | ||
59 | buf[0] = r100.tw_sm_c_100.data1_reg; | 60 | buf[0] = r100.tw_sm_c_100.data1_reg; |
60 | 61 | ||
61 | if (len > 0) buf[1] = r104.tw_sm_c_104.data2_reg; | 62 | if (len > 0) { |
62 | if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; | 63 | r104 = fc->read_ibi_reg(fc,tw_sm_c_104); |
63 | if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; | 64 | deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); |
65 | |||
66 | /* there is at least one more byte, otherwise we wouldn't be here */ | ||
67 | buf[1] = r104.tw_sm_c_104.data2_reg; | ||
68 | if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; | ||
69 | if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; | ||
70 | } | ||
64 | 71 | ||
65 | return 0; | 72 | return 0; |
66 | } | 73 | } |
@@ -82,9 +89,45 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, | |||
82 | 89 | ||
83 | /* write the additional i2c data before doing the actual i2c operation */ | 90 | /* write the additional i2c data before doing the actual i2c operation */ |
84 | fc->write_ibi_reg(fc,tw_sm_c_104,r104); | 91 | fc->write_ibi_reg(fc,tw_sm_c_104,r104); |
92 | return flexcop_i2c_operation(fc,&r100); | ||
93 | } | ||
94 | |||
95 | int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | ||
96 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | ||
97 | { | ||
98 | int ret; | ||
99 | u16 bytes_to_transfer; | ||
100 | flexcop_ibi_value r100; | ||
101 | |||
102 | deb_i2c("op = %d\n",op); | ||
103 | r100.raw = 0; | ||
104 | r100.tw_sm_c_100.chipaddr = chipaddr; | ||
105 | r100.tw_sm_c_100.twoWS_rw = op; | ||
106 | r100.tw_sm_c_100.twoWS_port_reg = port; | ||
107 | |||
108 | while (len != 0) { | ||
109 | bytes_to_transfer = len > 4 ? 4 : len; | ||
85 | 110 | ||
86 | return flexcop_i2c_operation(fc,&r100,30); | 111 | r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; |
112 | r100.tw_sm_c_100.baseaddr = addr; | ||
113 | |||
114 | if (op == FC_READ) | ||
115 | ret = flexcop_i2c_read4(fc, r100, buf); | ||
116 | else | ||
117 | ret = flexcop_i2c_write4(fc,r100, buf); | ||
118 | |||
119 | if (ret < 0) | ||
120 | return ret; | ||
121 | |||
122 | buf += bytes_to_transfer; | ||
123 | addr += bytes_to_transfer; | ||
124 | len -= bytes_to_transfer; | ||
125 | }; | ||
126 | |||
127 | return 0; | ||
87 | } | 128 | } |
129 | /* exported for PCI i2c */ | ||
130 | EXPORT_SYMBOL(flexcop_i2c_request); | ||
88 | 131 | ||
89 | /* master xfer callback for demodulator */ | 132 | /* master xfer callback for demodulator */ |
90 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) | 133 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) |
@@ -123,43 +166,6 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs | |||
123 | return ret; | 166 | return ret; |
124 | } | 167 | } |
125 | 168 | ||
126 | int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | ||
127 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | ||
128 | { | ||
129 | int ret; | ||
130 | u16 bytes_to_transfer; | ||
131 | flexcop_ibi_value r100; | ||
132 | |||
133 | deb_i2c("op = %d\n",op); | ||
134 | r100.raw = 0; | ||
135 | r100.tw_sm_c_100.chipaddr = chipaddr; | ||
136 | r100.tw_sm_c_100.twoWS_rw = op; | ||
137 | r100.tw_sm_c_100.twoWS_port_reg = port; | ||
138 | |||
139 | while (len != 0) { | ||
140 | bytes_to_transfer = len > 4 ? 4 : len; | ||
141 | |||
142 | r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; | ||
143 | r100.tw_sm_c_100.baseaddr = addr; | ||
144 | |||
145 | if (op == FC_READ) | ||
146 | ret = flexcop_i2c_read4(fc, r100, buf); | ||
147 | else | ||
148 | ret = flexcop_i2c_write4(fc,r100, buf); | ||
149 | |||
150 | if (ret < 0) | ||
151 | return ret; | ||
152 | |||
153 | buf += bytes_to_transfer; | ||
154 | addr += bytes_to_transfer; | ||
155 | len -= bytes_to_transfer; | ||
156 | }; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | /* exported for PCI i2c */ | ||
161 | EXPORT_SYMBOL(flexcop_i2c_request); | ||
162 | |||
163 | static u32 flexcop_i2c_func(struct i2c_adapter *adapter) | 169 | static u32 flexcop_i2c_func(struct i2c_adapter *adapter) |
164 | { | 170 | { |
165 | return I2C_FUNC_I2C; | 171 | return I2C_FUNC_I2C; |