diff options
author | Patrick Boettcher <pb@linuxtv.org> | 2008-03-29 19:49:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:07:56 -0400 |
commit | 6394cf53abc0b3a2db9e8b947ef5c77b16861ec8 (patch) | |
tree | 6d442ab2e89d17ef963ee840ba50440e225f30cb /drivers/media/dvb/b2c2/flexcop-i2c.c | |
parent | 0b5afdd2ea5f52d260d1e42d43fb0fa09ec0da2f (diff) |
V4L/DVB (7469): Preparation for supporting new devices, cleanup and saneness
To prepare the support for new device to the flexcop-family some preparation and cleanups was done + some saneness:
- created an i2c-adapter for each i2c-port available. Easier usage for devices with several device on different i2c-busses
- initialize i2c before doing the eeprom read
- changed the way to attach the different frontends, easier to read now
- enabled support for i2c-devices having no register address (1-byte access)
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/b2c2/flexcop-i2c.c')
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-i2c.c | 180 |
1 files changed, 122 insertions, 58 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 6bf858a436c9..55973eaf3711 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #define FC_MAX_I2C_RETRIES 100000 | 10 | #define FC_MAX_I2C_RETRIES 100000 |
11 | 11 | ||
12 | /* #define DUMP_I2C_MESSAGES */ | ||
13 | |||
12 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100) | 14 | static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100) |
13 | { | 15 | { |
14 | int i; | 16 | int i; |
@@ -38,30 +40,25 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r | |||
38 | return -EREMOTEIO; | 40 | return -EREMOTEIO; |
39 | } | 41 | } |
40 | 42 | ||
41 | static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf) | 43 | static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, |
44 | flexcop_ibi_value r100, u8 *buf) | ||
42 | { | 45 | { |
43 | flexcop_ibi_value r104; | 46 | flexcop_ibi_value r104; |
44 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ | 47 | int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ |
45 | ret; | 48 | ret; |
46 | 49 | ||
47 | if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { | 50 | r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; |
48 | /* The Cablestar needs a different kind of i2c-transfer (does not | 51 | ret = flexcop_i2c_operation(i2c->fc, &r100); |
49 | * support "Repeat Start"): | 52 | if (ret != 0) { |
50 | * wait for the ACK failure, | 53 | deb_i2c("read failed. %d\n", ret); |
51 | * and do a subsequent read with the Bit 30 enabled | 54 | return ret; |
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 | } | 55 | } |
59 | 56 | ||
60 | buf[0] = r100.tw_sm_c_100.data1_reg; | 57 | buf[0] = r100.tw_sm_c_100.data1_reg; |
61 | 58 | ||
62 | if (len > 0) { | 59 | if (len > 0) { |
63 | r104 = fc->read_ibi_reg(fc,tw_sm_c_104); | 60 | r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104); |
64 | deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | 61 | deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw); |
65 | 62 | ||
66 | /* there is at least one more byte, otherwise we wouldn't be here */ | 63 | /* there is at least one more byte, otherwise we wouldn't be here */ |
67 | buf[1] = r104.tw_sm_c_104.data2_reg; | 64 | buf[1] = r104.tw_sm_c_104.data2_reg; |
@@ -85,17 +82,22 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, | |||
85 | r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; | 82 | r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; |
86 | r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; | 83 | r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; |
87 | 84 | ||
88 | deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw); | 85 | deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw); |
89 | 86 | ||
90 | /* write the additional i2c data before doing the actual i2c operation */ | 87 | /* write the additional i2c data before doing the actual i2c operation */ |
91 | fc->write_ibi_reg(fc,tw_sm_c_104,r104); | 88 | fc->write_ibi_reg(fc, tw_sm_c_104, r104); |
92 | return flexcop_i2c_operation(fc,&r100); | 89 | return flexcop_i2c_operation(fc, &r100); |
93 | } | 90 | } |
94 | 91 | ||
95 | int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | 92 | int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, |
96 | flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) | 93 | flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) |
97 | { | 94 | { |
98 | int ret; | 95 | int ret; |
96 | |||
97 | #ifdef DUMP_I2C_MESSAGES | ||
98 | int i; | ||
99 | #endif | ||
100 | |||
99 | u16 bytes_to_transfer; | 101 | u16 bytes_to_transfer; |
100 | flexcop_ibi_value r100; | 102 | flexcop_ibi_value r100; |
101 | 103 | ||
@@ -103,7 +105,25 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | |||
103 | r100.raw = 0; | 105 | r100.raw = 0; |
104 | r100.tw_sm_c_100.chipaddr = chipaddr; | 106 | r100.tw_sm_c_100.chipaddr = chipaddr; |
105 | r100.tw_sm_c_100.twoWS_rw = op; | 107 | r100.tw_sm_c_100.twoWS_rw = op; |
106 | r100.tw_sm_c_100.twoWS_port_reg = port; | 108 | r100.tw_sm_c_100.twoWS_port_reg = i2c->port; |
109 | |||
110 | #ifdef DUMP_I2C_MESSAGES | ||
111 | printk(KERN_DEBUG "%d ", i2c->port); | ||
112 | if (op == FC_READ) | ||
113 | printk("rd("); | ||
114 | else | ||
115 | printk("wr("); | ||
116 | |||
117 | printk("%02x): %02x ", chipaddr, addr); | ||
118 | #endif | ||
119 | |||
120 | /* in that case addr is the only value -> | ||
121 | * we write it twice as baseaddr and val0 | ||
122 | * BBTI is doing it like that for ISL6421 at least */ | ||
123 | if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { | ||
124 | buf = &addr; | ||
125 | len = 1; | ||
126 | } | ||
107 | 127 | ||
108 | while (len != 0) { | 128 | while (len != 0) { |
109 | bytes_to_transfer = len > 4 ? 4 : len; | 129 | bytes_to_transfer = len > 4 ? 4 : len; |
@@ -112,9 +132,14 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | |||
112 | r100.tw_sm_c_100.baseaddr = addr; | 132 | r100.tw_sm_c_100.baseaddr = addr; |
113 | 133 | ||
114 | if (op == FC_READ) | 134 | if (op == FC_READ) |
115 | ret = flexcop_i2c_read4(fc, r100, buf); | 135 | ret = flexcop_i2c_read4(i2c, r100, buf); |
116 | else | 136 | else |
117 | ret = flexcop_i2c_write4(fc,r100, buf); | 137 | ret = flexcop_i2c_write4(i2c->fc, r100, buf); |
138 | |||
139 | #ifdef DUMP_I2C_MESSAGES | ||
140 | for (i = 0; i < bytes_to_transfer; i++) | ||
141 | printk("%02x ", buf[i]); | ||
142 | #endif | ||
118 | 143 | ||
119 | if (ret < 0) | 144 | if (ret < 0) |
120 | return ret; | 145 | return ret; |
@@ -122,7 +147,11 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, | |||
122 | buf += bytes_to_transfer; | 147 | buf += bytes_to_transfer; |
123 | addr += bytes_to_transfer; | 148 | addr += bytes_to_transfer; |
124 | len -= bytes_to_transfer; | 149 | len -= bytes_to_transfer; |
125 | }; | 150 | } |
151 | |||
152 | #ifdef DUMP_I2C_MESSAGES | ||
153 | printk("\n"); | ||
154 | #endif | ||
126 | 155 | ||
127 | return 0; | 156 | return 0; |
128 | } | 157 | } |
@@ -132,7 +161,7 @@ EXPORT_SYMBOL(flexcop_i2c_request); | |||
132 | /* master xfer callback for demodulator */ | 161 | /* master xfer callback for demodulator */ |
133 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) | 162 | static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) |
134 | { | 163 | { |
135 | struct flexcop_device *fc = i2c_get_adapdata(i2c_adap); | 164 | struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); |
136 | int i, ret = 0; | 165 | int i, ret = 0; |
137 | 166 | ||
138 | /* Some drivers use 1 byte or 0 byte reads as probes, which this | 167 | /* Some drivers use 1 byte or 0 byte reads as probes, which this |
@@ -142,34 +171,29 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs | |||
142 | if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) | 171 | if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) |
143 | return 1; | 172 | return 1; |
144 | 173 | ||
145 | if (mutex_lock_interruptible(&fc->i2c_mutex)) | 174 | if (mutex_lock_interruptible(&i2c->fc->i2c_mutex)) |
146 | return -ERESTARTSYS; | 175 | return -ERESTARTSYS; |
147 | 176 | ||
148 | /* reading */ | 177 | for (i = 0; i < num; i++) { |
149 | if (num == 2 && | 178 | /* reading */ |
150 | msgs[0].flags == 0 && | 179 | if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) { |
151 | msgs[1].flags == I2C_M_RD && | 180 | ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr, |
152 | msgs[0].buf != NULL && | 181 | msgs[i].buf[0], msgs[i+1].buf, msgs[i+1].len); |
153 | msgs[1].buf != NULL) { | 182 | i++; /* skip the following message */ |
154 | 183 | } else /* writing */ | |
155 | ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); | 184 | ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr, |
156 | 185 | msgs[i].buf[0], &msgs[i].buf[1], | |
157 | } else for (i = 0; i < num; i++) { /* writing command */ | 186 | msgs[i].len - 1); |
158 | if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) { | 187 | if (ret < 0) { |
159 | ret = -EINVAL; | 188 | err("i2c master_xfer failed"); |
160 | break; | 189 | break; |
161 | } | 190 | } |
162 | |||
163 | ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); | ||
164 | } | 191 | } |
165 | 192 | ||
166 | if (ret < 0) | 193 | mutex_unlock(&i2c->fc->i2c_mutex); |
167 | err("i2c master_xfer failed"); | ||
168 | else | ||
169 | ret = num; | ||
170 | |||
171 | mutex_unlock(&fc->i2c_mutex); | ||
172 | 194 | ||
195 | if (ret == 0) | ||
196 | ret = num; | ||
173 | return ret; | 197 | return ret; |
174 | } | 198 | } |
175 | 199 | ||
@@ -189,28 +213,68 @@ int flexcop_i2c_init(struct flexcop_device *fc) | |||
189 | 213 | ||
190 | mutex_init(&fc->i2c_mutex); | 214 | mutex_init(&fc->i2c_mutex); |
191 | 215 | ||
192 | memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); | 216 | fc->fc_i2c_adap[0].fc = fc; |
193 | strncpy(fc->i2c_adap.name, "B2C2 FlexCop device", | 217 | fc->fc_i2c_adap[1].fc = fc; |
194 | sizeof(fc->i2c_adap.name)); | 218 | fc->fc_i2c_adap[2].fc = fc; |
195 | 219 | ||
196 | i2c_set_adapdata(&fc->i2c_adap,fc); | 220 | fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD; |
221 | fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; | ||
222 | fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; | ||
223 | |||
224 | strncpy(fc->fc_i2c_adap[0].i2c_adap.name, | ||
225 | "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE); | ||
226 | strncpy(fc->fc_i2c_adap[1].i2c_adap.name, | ||
227 | "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE); | ||
228 | strncpy(fc->fc_i2c_adap[2].i2c_adap.name, | ||
229 | "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE); | ||
230 | |||
231 | i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); | ||
232 | i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); | ||
233 | i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]); | ||
234 | |||
235 | fc->fc_i2c_adap[0].i2c_adap.class = | ||
236 | fc->fc_i2c_adap[1].i2c_adap.class = | ||
237 | fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL; | ||
238 | fc->fc_i2c_adap[0].i2c_adap.algo = | ||
239 | fc->fc_i2c_adap[1].i2c_adap.algo = | ||
240 | fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo; | ||
241 | fc->fc_i2c_adap[0].i2c_adap.algo_data = | ||
242 | fc->fc_i2c_adap[1].i2c_adap.algo_data = | ||
243 | fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL; | ||
244 | fc->fc_i2c_adap[0].i2c_adap.dev.parent = | ||
245 | fc->fc_i2c_adap[1].i2c_adap.dev.parent = | ||
246 | fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev; | ||
247 | |||
248 | ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
197 | 251 | ||
198 | fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; | 252 | ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap); |
199 | fc->i2c_adap.algo = &flexcop_algo; | 253 | if (ret < 0) |
200 | fc->i2c_adap.algo_data = NULL; | 254 | goto adap_1_failed; |
201 | fc->i2c_adap.dev.parent = fc->dev; | ||
202 | 255 | ||
203 | if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) | 256 | ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap); |
204 | return ret; | 257 | if (ret < 0) |
258 | goto adap_2_failed; | ||
205 | 259 | ||
206 | fc->init_state |= FC_STATE_I2C_INIT; | 260 | fc->init_state |= FC_STATE_I2C_INIT; |
207 | return 0; | 261 | return 0; |
262 | |||
263 | adap_2_failed: | ||
264 | i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); | ||
265 | adap_1_failed: | ||
266 | i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); | ||
267 | |||
268 | return ret; | ||
208 | } | 269 | } |
209 | 270 | ||
210 | void flexcop_i2c_exit(struct flexcop_device *fc) | 271 | void flexcop_i2c_exit(struct flexcop_device *fc) |
211 | { | 272 | { |
212 | if (fc->init_state & FC_STATE_I2C_INIT) | 273 | if (fc->init_state & FC_STATE_I2C_INIT) { |
213 | i2c_del_adapter(&fc->i2c_adap); | 274 | i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap); |
275 | i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); | ||
276 | i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); | ||
277 | } | ||
214 | 278 | ||
215 | fc->init_state &= ~FC_STATE_I2C_INIT; | 279 | fc->init_state &= ~FC_STATE_I2C_INIT; |
216 | } | 280 | } |