diff options
author | Mauro Carvalho Chehab <mchehab@brturbo.com.br> | 2005-07-12 16:58:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-12 19:01:06 -0400 |
commit | f7ce3cc67052de63a29bad90110640b687d12058 (patch) | |
tree | f3978eb08434d0e87b2467949bd22513c3535416 /drivers/media/video/tea5767.c | |
parent | ebe4c6fa535b0410e58e9c8352320896d07e2efb (diff) |
[PATCH] v4l: I2C Tuner
- Fixed a trouble on tuner-core that generates erros on computers with more
than one TV card.
- Rename tuner structures fields.
- Tail spaces removed.
- I2C cleanups and converged to a basic reference structure.
- Removed unused structures.
- Fix setting frequency on tda8290.
- Added code for TEA5767 autodetection.
- Standby mode support implemented. It is used to disable
a non used tuner. Currenlty implemented on tea5767.
- New macro: set_type disables other tuner when changing mode.
- Some cleanups.
- Use 50 kHz step when tunning radio for most tuners to improve precision.
Signed-off-by: Fabien Perrot <perrot1983@yahoo.fr>
Signed-off-by: Michael Krufky <mkrufky@m1k.net>
Signed-off-By: Nickolay V. Shmyrev <nshmyrev@yandex.ru>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/video/tea5767.c')
-rw-r--r-- | drivers/media/video/tea5767.c | 158 |
1 files changed, 81 insertions, 77 deletions
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index a29f08f81f63..b53c748caf2a 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview | 2 | * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview |
3 | * I2C address is allways 0xC0. | 3 | * I2C address is allways 0xC0. |
4 | * | 4 | * |
5 | * $Id: tea5767.c,v 1.11 2005/06/21 15:40:33 mchehab Exp $ | 5 | * $Id: tea5767.c,v 1.18 2005/07/07 03:02:55 mchehab Exp $ |
6 | * | 6 | * |
7 | * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) | 7 | * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) |
8 | * This code is placed under the terms of the GNU General Public License | 8 | * This code is placed under the terms of the GNU General Public License |
@@ -11,23 +11,11 @@ | |||
11 | * from their contributions on DScaler. | 11 | * from their contributions on DScaler. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/videodev.h> | ||
24 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
25 | #include <linux/i2c-algo-bit.h> | 15 | #include <linux/videodev.h> |
26 | 16 | #include <linux/delay.h> | |
17 | #include <media/tuner.h> | ||
27 | #include <media/tuner.h> | 18 | #include <media/tuner.h> |
28 | |||
29 | /* Declared at tuner-core.c */ | ||
30 | extern unsigned int tuner_debug; | ||
31 | 19 | ||
32 | #define PREFIX "TEA5767 " | 20 | #define PREFIX "TEA5767 " |
33 | 21 | ||
@@ -38,8 +26,8 @@ extern unsigned int tuner_debug; | |||
38 | ******************************/ | 26 | ******************************/ |
39 | 27 | ||
40 | /* First register */ | 28 | /* First register */ |
41 | #define TEA5767_MUTE 0x80 /* Mutes output */ | 29 | #define TEA5767_MUTE 0x80 /* Mutes output */ |
42 | #define TEA5767_SEARCH 0x40 /* Activates station search */ | 30 | #define TEA5767_SEARCH 0x40 /* Activates station search */ |
43 | /* Bits 0-5 for divider MSB */ | 31 | /* Bits 0-5 for divider MSB */ |
44 | 32 | ||
45 | /* Second register */ | 33 | /* Second register */ |
@@ -130,6 +118,14 @@ extern unsigned int tuner_debug; | |||
130 | /* Reserved for future extensions */ | 118 | /* Reserved for future extensions */ |
131 | #define TEA5767_RESERVED_MASK 0xff | 119 | #define TEA5767_RESERVED_MASK 0xff |
132 | 120 | ||
121 | enum tea5767_xtal_freq { | ||
122 | TEA5767_LOW_LO_32768 = 0, | ||
123 | TEA5767_HIGH_LO_32768 = 1, | ||
124 | TEA5767_LOW_LO_13MHz = 2, | ||
125 | TEA5767_HIGH_LO_13MHz = 3, | ||
126 | }; | ||
127 | |||
128 | |||
133 | /*****************************************************************************/ | 129 | /*****************************************************************************/ |
134 | 130 | ||
135 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) | 131 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) |
@@ -153,103 +149,112 @@ static void tea5767_status_dump(unsigned char *buffer) | |||
153 | else | 149 | else |
154 | printk(PREFIX "Tuner not at band limit\n"); | 150 | printk(PREFIX "Tuner not at band limit\n"); |
155 | 151 | ||
156 | div=((buffer[0]&0x3f)<<8) | buffer[1]; | 152 | div = ((buffer[0] & 0x3f) << 8) | buffer[1]; |
157 | 153 | ||
158 | switch (TEA5767_HIGH_LO_32768) { | 154 | switch (TEA5767_HIGH_LO_32768) { |
159 | case TEA5767_HIGH_LO_13MHz: | 155 | case TEA5767_HIGH_LO_13MHz: |
160 | frq = 1000*(div*50-700-225)/4; /* Freq in KHz */ | 156 | frq = 1000 * (div * 50 - 700 - 225) / 4; /* Freq in KHz */ |
161 | break; | 157 | break; |
162 | case TEA5767_LOW_LO_13MHz: | 158 | case TEA5767_LOW_LO_13MHz: |
163 | frq = 1000*(div*50+700+225)/4; /* Freq in KHz */ | 159 | frq = 1000 * (div * 50 + 700 + 225) / 4; /* Freq in KHz */ |
164 | break; | 160 | break; |
165 | case TEA5767_LOW_LO_32768: | 161 | case TEA5767_LOW_LO_32768: |
166 | frq = 1000*(div*32768/1000+700+225)/4; /* Freq in KHz */ | 162 | frq = 1000 * (div * 32768 / 1000 + 700 + 225) / 4; /* Freq in KHz */ |
167 | break; | 163 | break; |
168 | case TEA5767_HIGH_LO_32768: | 164 | case TEA5767_HIGH_LO_32768: |
169 | default: | 165 | default: |
170 | frq = 1000*(div*32768/1000-700-225)/4; /* Freq in KHz */ | 166 | frq = 1000 * (div * 32768 / 1000 - 700 - 225) / 4; /* Freq in KHz */ |
171 | break; | 167 | break; |
172 | } | 168 | } |
173 | buffer[0] = (div>>8) & 0x3f; | 169 | buffer[0] = (div >> 8) & 0x3f; |
174 | buffer[1] = div & 0xff; | 170 | buffer[1] = div & 0xff; |
175 | 171 | ||
176 | printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", | 172 | printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", |
177 | frq/1000,frq%1000,div); | 173 | frq / 1000, frq % 1000, div); |
178 | 174 | ||
179 | if (TEA5767_STEREO_MASK & buffer[2]) | 175 | if (TEA5767_STEREO_MASK & buffer[2]) |
180 | printk(PREFIX "Stereo\n"); | 176 | printk(PREFIX "Stereo\n"); |
181 | else | 177 | else |
182 | printk(PREFIX "Mono\n"); | 178 | printk(PREFIX "Mono\n"); |
183 | 179 | ||
184 | printk(PREFIX "IF Counter = %d\n",buffer[2] & TEA5767_IF_CNTR_MASK); | 180 | printk(PREFIX "IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); |
185 | 181 | ||
186 | printk(PREFIX "ADC Level = %d\n",(buffer[3] & TEA5767_ADC_LEVEL_MASK)>>4); | 182 | printk(PREFIX "ADC Level = %d\n", |
183 | (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); | ||
187 | 184 | ||
188 | printk(PREFIX "Chip ID = %d\n",(buffer[3] & TEA5767_CHIP_ID_MASK)); | 185 | printk(PREFIX "Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); |
189 | 186 | ||
190 | printk(PREFIX "Reserved = 0x%02x\n",(buffer[4] & TEA5767_RESERVED_MASK)); | 187 | printk(PREFIX "Reserved = 0x%02x\n", |
188 | (buffer[4] & TEA5767_RESERVED_MASK)); | ||
191 | } | 189 | } |
192 | 190 | ||
193 | /* Freq should be specifyed at 62.5 Hz */ | 191 | /* Freq should be specifyed at 62.5 Hz */ |
194 | static void set_radio_freq(struct i2c_client *c, unsigned int frq) | 192 | static void set_radio_freq(struct i2c_client *c, unsigned int frq) |
195 | { | 193 | { |
196 | struct tuner *t = i2c_get_clientdata(c); | 194 | struct tuner *t = i2c_get_clientdata(c); |
197 | unsigned char buffer[5]; | 195 | unsigned char buffer[5]; |
198 | unsigned div; | 196 | unsigned div; |
199 | int rc; | 197 | int rc; |
200 | 198 | ||
201 | if ( tuner_debug ) | 199 | tuner_dbg (PREFIX "radio freq counter %d\n", frq); |
202 | printk(PREFIX "radio freq counter %d\n",frq); | ||
203 | 200 | ||
204 | /* Rounds freq to next decimal value - for 62.5 KHz step */ | 201 | /* Rounds freq to next decimal value - for 62.5 KHz step */ |
205 | /* frq = 20*(frq/16)+radio_frq[frq%16]; */ | 202 | /* frq = 20*(frq/16)+radio_frq[frq%16]; */ |
206 | 203 | ||
207 | buffer[2] = TEA5767_PORT1_HIGH; | 204 | buffer[2] = TEA5767_PORT1_HIGH; |
208 | buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; | 205 | buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | |
209 | buffer[4]=0; | 206 | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; |
207 | buffer[4] = 0; | ||
208 | |||
209 | if (t->mode == T_STANDBY) { | ||
210 | tuner_dbg("TEA5767 set to standby mode\n"); | ||
211 | buffer[3] |= TEA5767_STDBY; | ||
212 | } | ||
210 | 213 | ||
211 | if (t->audmode == V4L2_TUNER_MODE_MONO) { | 214 | if (t->audmode == V4L2_TUNER_MODE_MONO) { |
212 | tuner_dbg("TEA5767 set to mono\n"); | 215 | tuner_dbg("TEA5767 set to mono\n"); |
213 | buffer[2] |= TEA5767_MONO; | 216 | buffer[2] |= TEA5767_MONO; |
214 | } else | 217 | } else { |
215 | tuner_dbg("TEA5767 set to stereo\n"); | 218 | tuner_dbg("TEA5767 set to stereo\n"); |
219 | } | ||
216 | 220 | ||
217 | switch (t->type) { | 221 | /* Should be replaced */ |
222 | switch (TEA5767_HIGH_LO_32768) { | ||
218 | case TEA5767_HIGH_LO_13MHz: | 223 | case TEA5767_HIGH_LO_13MHz: |
219 | tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); | 224 | tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); |
220 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | 225 | buffer[2] |= TEA5767_HIGH_LO_INJECT; |
221 | buffer[4] |= TEA5767_PLLREF_ENABLE; | 226 | buffer[4] |= TEA5767_PLLREF_ENABLE; |
222 | div = (frq*4/16+700+225+25)/50; | 227 | div = (frq * 4 / 16 + 700 + 225 + 25) / 50; |
223 | break; | 228 | break; |
224 | case TEA5767_LOW_LO_13MHz: | 229 | case TEA5767_LOW_LO_13MHz: |
225 | tuner_dbg("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); | 230 | tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); |
226 | 231 | ||
227 | buffer[4] |= TEA5767_PLLREF_ENABLE; | 232 | buffer[4] |= TEA5767_PLLREF_ENABLE; |
228 | div = (frq*4/16-700-225+25)/50; | 233 | div = (frq * 4 / 16 - 700 - 225 + 25) / 50; |
229 | break; | 234 | break; |
230 | case TEA5767_LOW_LO_32768: | 235 | case TEA5767_LOW_LO_32768: |
231 | tuner_dbg("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); | 236 | tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); |
232 | buffer[3] |= TEA5767_XTAL_32768; | 237 | buffer[3] |= TEA5767_XTAL_32768; |
233 | /* const 700=4000*175 Khz - to adjust freq to right value */ | 238 | /* const 700=4000*175 Khz - to adjust freq to right value */ |
234 | div = (1000*(frq*4/16-700-225)+16384)>>15; | 239 | div = (1000 * (frq * 4 / 16 - 700 - 225) + 16384) >> 15; |
235 | break; | 240 | break; |
236 | case TEA5767_HIGH_LO_32768: | 241 | case TEA5767_HIGH_LO_32768: |
237 | default: | 242 | default: |
238 | tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); | 243 | tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); |
239 | 244 | ||
240 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | 245 | buffer[2] |= TEA5767_HIGH_LO_INJECT; |
241 | buffer[3] |= TEA5767_XTAL_32768; | 246 | buffer[3] |= TEA5767_XTAL_32768; |
242 | div = (1000*(frq*4/16+700+225)+16384)>>15; | 247 | div = (1000 * (frq * 4 / 16 + 700 + 225) + 16384) >> 15; |
243 | break; | 248 | break; |
244 | } | 249 | } |
245 | buffer[0] = (div>>8) & 0x3f; | 250 | buffer[0] = (div >> 8) & 0x3f; |
246 | buffer[1] = div & 0xff; | 251 | buffer[1] = div & 0xff; |
247 | 252 | ||
248 | if ( tuner_debug ) | 253 | if (tuner_debug) |
249 | tea5767_status_dump(buffer); | 254 | tea5767_status_dump(buffer); |
250 | 255 | ||
251 | if (5 != (rc = i2c_master_send(c,buffer,5))) | 256 | if (5 != (rc = i2c_master_send(c, buffer, 5))) |
252 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n",rc); | 257 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); |
253 | } | 258 | } |
254 | 259 | ||
255 | static int tea5767_signal(struct i2c_client *c) | 260 | static int tea5767_signal(struct i2c_client *c) |
@@ -258,11 +263,11 @@ static int tea5767_signal(struct i2c_client *c) | |||
258 | int rc; | 263 | int rc; |
259 | struct tuner *t = i2c_get_clientdata(c); | 264 | struct tuner *t = i2c_get_clientdata(c); |
260 | 265 | ||
261 | memset(buffer,0,sizeof(buffer)); | 266 | memset(buffer, 0, sizeof(buffer)); |
262 | if (5 != (rc = i2c_master_recv(c,buffer,5))) | 267 | if (5 != (rc = i2c_master_recv(c, buffer, 5))) |
263 | tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); | 268 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); |
264 | 269 | ||
265 | return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) <<(13-4)); | 270 | return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4)); |
266 | } | 271 | } |
267 | 272 | ||
268 | static int tea5767_stereo(struct i2c_client *c) | 273 | static int tea5767_stereo(struct i2c_client *c) |
@@ -271,47 +276,46 @@ static int tea5767_stereo(struct i2c_client *c) | |||
271 | int rc; | 276 | int rc; |
272 | struct tuner *t = i2c_get_clientdata(c); | 277 | struct tuner *t = i2c_get_clientdata(c); |
273 | 278 | ||
274 | memset(buffer,0,sizeof(buffer)); | 279 | memset(buffer, 0, sizeof(buffer)); |
275 | if (5 != (rc = i2c_master_recv(c,buffer,5))) | 280 | if (5 != (rc = i2c_master_recv(c, buffer, 5))) |
276 | tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); | 281 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); |
277 | 282 | ||
278 | rc = buffer[2] & TEA5767_STEREO_MASK; | 283 | rc = buffer[2] & TEA5767_STEREO_MASK; |
279 | 284 | ||
280 | if ( tuner_debug ) | 285 | tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); |
281 | tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); | ||
282 | 286 | ||
283 | return ( (buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO: 0); | 287 | return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); |
284 | } | 288 | } |
285 | 289 | ||
286 | int tea_detection(struct i2c_client *c) | 290 | int tea5767_autodetection(struct i2c_client *c) |
287 | { | 291 | { |
288 | unsigned char buffer[5]= { 0xff, 0xff, 0xff, 0xff, 0xff }; | 292 | unsigned char buffer[5] = { 0xff, 0xff, 0xff, 0xff, 0xff }; |
289 | int rc; | 293 | int rc; |
290 | struct tuner *t = i2c_get_clientdata(c); | 294 | struct tuner *t = i2c_get_clientdata(c); |
291 | 295 | ||
292 | if (5 != (rc = i2c_master_recv(c,buffer,5))) { | 296 | if (5 != (rc = i2c_master_recv(c, buffer, 5))) { |
293 | tuner_warn ( "it is not a TEA5767. Received %i chars.\n",rc ); | 297 | tuner_warn("it is not a TEA5767. Received %i chars.\n", rc); |
294 | return EINVAL; | 298 | return EINVAL; |
295 | } | 299 | } |
296 | 300 | ||
297 | /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */ | 301 | /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */ |
298 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && | 302 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && |
299 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { | 303 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { |
300 | tuner_warn ( "All bytes are equal. It is not a TEA5767\n" ); | 304 | tuner_warn("All bytes are equal. It is not a TEA5767\n"); |
301 | return EINVAL; | 305 | return EINVAL; |
302 | } | 306 | } |
303 | 307 | ||
304 | /* Status bytes: | 308 | /* Status bytes: |
305 | * Byte 4: bit 3:1 : CI (Chip Identification) == 0 | 309 | * Byte 4: bit 3:1 : CI (Chip Identification) == 0 |
306 | * bit 0 : internally set to 0 | 310 | * bit 0 : internally set to 0 |
307 | * Byte 5: bit 7:0 : == 0 | 311 | * Byte 5: bit 7:0 : == 0 |
308 | */ | 312 | */ |
309 | 313 | ||
310 | if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { | 314 | if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { |
311 | tuner_warn ( "Chip ID is not zero. It is not a TEA5767\n" ); | 315 | tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); |
312 | return EINVAL; | 316 | return EINVAL; |
313 | } | 317 | } |
314 | tuner_warn ( "TEA5767 detected.\n" ); | 318 | tuner_warn("TEA5767 detected.\n"); |
315 | return 0; | 319 | return 0; |
316 | } | 320 | } |
317 | 321 | ||
@@ -319,16 +323,16 @@ int tea5767_tuner_init(struct i2c_client *c) | |||
319 | { | 323 | { |
320 | struct tuner *t = i2c_get_clientdata(c); | 324 | struct tuner *t = i2c_get_clientdata(c); |
321 | 325 | ||
322 | if (tea_detection(c)==EINVAL) return EINVAL; | 326 | if (tea5767_autodetection(c) == EINVAL) |
327 | return EINVAL; | ||
323 | 328 | ||
324 | tuner_info("type set to %d (%s)\n", | 329 | tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); |
325 | t->type, TEA5767_TUNER_NAME); | 330 | strlcpy(c->name, "tea5767", sizeof(c->name)); |
326 | strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name)); | ||
327 | 331 | ||
328 | t->tv_freq = set_tv_freq; | 332 | t->tv_freq = set_tv_freq; |
329 | t->radio_freq = set_radio_freq; | 333 | t->radio_freq = set_radio_freq; |
330 | t->has_signal = tea5767_signal; | 334 | t->has_signal = tea5767_signal; |
331 | t->is_stereo = tea5767_stereo; | 335 | t->is_stereo = tea5767_stereo; |
332 | 336 | ||
333 | return (0); | 337 | return (0); |
334 | } | 338 | } |