aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-xc2028.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-10-23 14:24:06 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:01:05 -0500
commit215b95baf969c6f895969f0a4ae0479954fba7cd (patch)
tree67e02c71a7d306cb82221e674325a27221ce5e06 /drivers/media/video/tuner-xc2028.c
parent3b20532c791399182bd04f0fcc70b60a95637fa5 (diff)
V4L/DVB (6430): Convert tuner-xc2028 driver to the newer hybrid approach
This changeset converts tuner-xc2028 to the newer hybrid approach. It also prevents creating twice the xc3028 private struct by both DVB and V4L parts. Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r--drivers/media/video/tuner-xc2028.c398
1 files changed, 205 insertions, 193 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 0e68002a4a04..e4c371896de4 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -13,16 +13,15 @@
13#include <linux/delay.h> 13#include <linux/delay.h>
14#include <media/tuner.h> 14#include <media/tuner.h>
15#include <linux/mutex.h> 15#include <linux/mutex.h>
16#include "tuner-driver.h" 16#include "tuner-i2c.h"
17#include "tuner-xc2028.h" 17#include "tuner-xc2028.h"
18 18
19#include <linux/dvb/frontend.h> 19#include <linux/dvb/frontend.h>
20#include "dvb_frontend.h" 20#include "dvb_frontend.h"
21 21
22/* digital TV standards */ 22#define PREFIX "xc2028 "
23#define V4L2_STD_DTV_6MHZ ((v4l2_std_id)0x04000000) 23
24#define V4L2_STD_DTV_7MHZ ((v4l2_std_id)0x08000000) 24static LIST_HEAD(xc2028_list);
25#define V4L2_STD_DTV_8MHZ ((v4l2_std_id)0x10000000)
26 25
27/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ 26/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */
28 27
@@ -40,6 +39,15 @@ static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw";
40static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; 39static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw";
41 40
42struct xc2028_data { 41struct xc2028_data {
42 struct list_head xc2028_list;
43 struct tuner_i2c_props i2c_props;
44 int (*tuner_callback) (void *dev,
45 int command, int arg);
46 struct device *dev;
47 void *video_dev;
48 int count;
49 u32 frequency;
50
43 v4l2_std_id firm_type; /* video stds supported 51 v4l2_std_id firm_type; /* video stds supported
44 by current firmware */ 52 by current firmware */
45 fe_bandwidth_t bandwidth; /* Firmware bandwidth: 53 fe_bandwidth_t bandwidth; /* Firmware bandwidth:
@@ -48,61 +56,64 @@ struct xc2028_data {
48 were loaded? */ 56 were loaded? */
49 enum tuner_mode mode; 57 enum tuner_mode mode;
50 struct i2c_client *i2c_client; 58 struct i2c_client *i2c_client;
51 59
52 struct mutex lock; 60 struct mutex lock;
53}; 61};
54 62
55#define i2c_send(rc,c,buf,size) \ 63#define i2c_send(rc, priv, buf, size) \
56if (size != (rc = i2c_master_send(c, buf, size))) \ 64if (size != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size))) \
57 tuner_warn("i2c output error: rc = %d (should be %d)\n", \ 65 tuner_info("i2c output error: rc = %d (should be %d)\n", \
58 rc, (int)size); 66 rc, (int)size);
59 67
60#define i2c_rcv(rc,c,buf,size) \ 68#define i2c_rcv(rc, priv, buf, size) \
61if (size != (rc = i2c_master_recv(c, buf, size))) \ 69if (size != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size))) \
62 tuner_warn("i2c input error: rc = %d (should be %d)\n", \ 70 tuner_info("i2c input error: rc = %d (should be %d)\n", \
63 rc, (int)size); 71 rc, (int)size);
64 72
65#define send_seq(c, data...) \ 73#define send_seq(priv, data...) \
66{ int rc; \ 74{ int rc; \
67 const static u8 _val[] = data; \ 75 static u8 _val[] = data; \
68 if (sizeof(_val) != \ 76 if (sizeof(_val) != \
69 (rc = i2c_master_send \ 77 (rc = tuner_i2c_xfer_send (&priv->i2c_props, \
70 (c, _val, sizeof(_val)))) { \ 78 _val, sizeof(_val)))) { \
71 printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \ 79 tuner_info("Error on line %d: %d\n",__LINE__,rc); \
72 return; \ 80 return -EINVAL; \
73 } \ 81 } \
74 msleep (10); \ 82 msleep (10); \
75} 83}
76 84
77static int xc2028_get_reg(struct i2c_client *c, u16 reg) 85static int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
78{ 86{
79 int rc; 87 int rc;
80 unsigned char buf[1]; 88 unsigned char buf[1];
81 struct tuner *t = i2c_get_clientdata(c); 89
90 tuner_info("%s called\n", __FUNCTION__);
82 91
83 buf[0]= reg; 92 buf[0]= reg;
84 93
85 i2c_send(rc, c, buf, sizeof(buf)); 94 i2c_send(rc, priv, buf, sizeof(buf));
86 if (rc<0) 95 if (rc<0)
87 return rc; 96 return rc;
88 97
89 i2c_rcv(rc, c, buf, 2); 98 i2c_rcv(rc, priv, buf, 2);
90 if (rc<0) 99 if (rc<0)
91 return rc; 100 return rc;
92 101
93 return (buf[1])|(buf[0]<<8); 102 return (buf[1])|(buf[0]<<8);
94} 103}
95 104
96static int load_firmware (struct i2c_client *c, const char *name) 105static int load_firmware (struct dvb_frontend *fe, const char *name)
97{ 106{
107 struct xc2028_data *priv = fe->tuner_priv;
98 const struct firmware *fw=NULL; 108 const struct firmware *fw=NULL;
99 struct tuner *t = i2c_get_clientdata(c);
100 unsigned char *p, *endp; 109 unsigned char *p, *endp;
101 int len=0, rc=0; 110 int len=0, rc=0;
102 static const char firmware_ver[] = "tm6000/xcv v1"; 111 static const char firmware_ver[] = "tm6000/xcv v1";
103 112
104 tuner_info("xc2028: Loading firmware %s\n", name); 113 tuner_info("%s called\n", __FUNCTION__);
105 rc = request_firmware(&fw, name, &c->dev); 114
115 tuner_info("Loading firmware %s\n", name);
116 rc = request_firmware(&fw, name, priv->dev);
106 if (rc < 0) { 117 if (rc < 0) {
107 if (rc==-ENOENT) 118 if (rc==-ENOENT)
108 tuner_info("Error: firmware %s not found.\n", name); 119 tuner_info("Error: firmware %s not found.\n", name);
@@ -138,7 +149,7 @@ static int load_firmware (struct i2c_client *c, const char *name)
138 while(p<endp) { 149 while(p<endp) {
139 if ((*p) & 0x80) { 150 if ((*p) & 0x80) {
140 /* Special callback command received */ 151 /* Special callback command received */
141 rc = t->tuner_callback(c->adapter->algo_data, 152 rc = priv->tuner_callback(priv->video_dev,
142 XC2028_TUNER_RESET, (*p)&0x7f); 153 XC2028_TUNER_RESET, (*p)&0x7f);
143 if (rc<0) { 154 if (rc<0) {
144 tuner_info("Error at RESET code %d\n", 155 tuner_info("Error at RESET code %d\n",
@@ -162,7 +173,7 @@ static int load_firmware (struct i2c_client *c, const char *name)
162 goto err; 173 goto err;
163 } 174 }
164 175
165 i2c_send(rc, c, p, len); 176 i2c_send(rc, priv, p, len);
166 if (rc<0) 177 if (rc<0)
167 goto err; 178 goto err;
168 p+=len; 179 p+=len;
@@ -179,171 +190,173 @@ err:
179 return rc; 190 return rc;
180} 191}
181 192
182static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, 193static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
194 v4l2_std_id std,
183 fe_bandwidth_t bandwidth) 195 fe_bandwidth_t bandwidth)
184{ 196{
197 struct xc2028_data *priv = fe->tuner_priv;
185 int rc, version; 198 int rc, version;
186 struct tuner *t = i2c_get_clientdata(c);
187 struct xc2028_data *xc2028 = t->priv;
188 const char *name; 199 const char *name;
189 int change_digital_bandwidth; 200 int change_digital_bandwidth;
190 201
191 if (!t->tuner_callback) { 202 tuner_info("%s called\n", __FUNCTION__);
192 printk(KERN_ERR "xc2028: need tuner_callback to load firmware\n");
193 return -EINVAL;
194 }
195 203
196 printk(KERN_INFO "xc2028: I am in mode %u and I should switch to mode %i\n", 204 tuner_info( "I am in mode %u and I should switch to mode %i\n",
197 xc2028->mode, new_mode); 205 priv->mode, new_mode);
198 206
199 /* first of all, determine whether we have switched the mode */ 207 /* first of all, determine whether we have switched the mode */
200 if(new_mode != xc2028->mode) { 208 if(new_mode != priv->mode) {
201 xc2028->mode = new_mode; 209 priv->mode = new_mode;
202 xc2028->need_load_generic = 1; 210 priv->need_load_generic = 1;
203 } 211 }
204 212
205 change_digital_bandwidth = (xc2028->mode == T_DIGITAL_TV 213 change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
206 && bandwidth != xc2028->bandwidth) ? 1 : 0; 214 && bandwidth != priv->bandwidth) ? 1 : 0;
207 tuner_info("xc2028: old bandwidth %u, new bandwidth %u\n", xc2028->bandwidth, 215 tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
208 bandwidth); 216 bandwidth);
209 217
210 if (xc2028->need_load_generic) { 218 if (priv->need_load_generic) {
211 if (xc2028->bandwidth==8) 219 if (priv->bandwidth==8)
212 name = firmware_8MHZ_INIT0; 220 name = firmware_8MHZ_INIT0;
213 else 221 else
214 name = firmware_INIT0; 222 name = firmware_INIT0;
215 223
216 /* Reset is needed before loading firmware */ 224 /* Reset is needed before loading firmware */
217 rc = t->tuner_callback(c->adapter->algo_data, 225 rc = priv->tuner_callback(priv->video_dev,
218 XC2028_TUNER_RESET, 0); 226 XC2028_TUNER_RESET, 0);
219 if (rc<0) 227 if (rc<0)
220 return rc; 228 return rc;
221 229
222 rc = load_firmware(c,name); 230 rc = load_firmware(fe,name);
223 if (rc<0) 231 if (rc<0)
224 return rc; 232 return rc;
225 233
226 xc2028->need_load_generic=0; 234 priv->need_load_generic=0;
227 xc2028->firm_type=0; 235 priv->firm_type=0;
228 if(xc2028->mode == T_DIGITAL_TV) { 236 if(priv->mode == T_DIGITAL_TV) {
229 change_digital_bandwidth=1; 237 change_digital_bandwidth=1;
230 } 238 }
231 } 239 }
232 240
233 tuner_info("xc2028: I should change bandwidth %u\n", 241 tuner_info("I should change bandwidth %u\n",
234 change_digital_bandwidth); 242 change_digital_bandwidth);
235 243
244 /* FIXME: t->std makes no sense here */
236 if (change_digital_bandwidth) { 245 if (change_digital_bandwidth) {
237 switch(bandwidth) { 246 switch(bandwidth) {
238 case BANDWIDTH_8_MHZ: 247 case BANDWIDTH_8_MHZ:
239 t->std = V4L2_STD_DTV_8MHZ; 248 std = V4L2_STD_DTV_8MHZ;
240 break; 249 break;
241 250
242 case BANDWIDTH_7_MHZ: 251 case BANDWIDTH_7_MHZ:
243 t->std = V4L2_STD_DTV_7MHZ; 252 std = V4L2_STD_DTV_7MHZ;
244 break; 253 break;
245 254
246 case BANDWIDTH_6_MHZ: 255 case BANDWIDTH_6_MHZ:
247 t->std = V4L2_STD_DTV_6MHZ; 256 std = V4L2_STD_DTV_6MHZ;
248 break; 257 break;
249 258
250 default: 259 default:
251 tuner_info("error: bandwidth not supported.\n"); 260 tuner_info("error: bandwidth not supported.\n");
252 }; 261 };
253 xc2028->bandwidth = bandwidth; 262 priv->bandwidth = bandwidth;
254 } 263 }
255 264
256 if (xc2028->firm_type & t->std) { 265 if (priv->firm_type & std) {
257 tuner_info("xc3028: no need to load a std-specific firmware.\n"); 266 tuner_info("xc3028: no need to load a std-specific firmware.\n");
258 return 0; 267 return 0;
259 } 268 }
260 269
261 rc = load_firmware(c,firmware_INIT1); 270 rc = load_firmware(fe,firmware_INIT1);
262 271
263 if (t->std & V4L2_STD_MN) 272 if (std & V4L2_STD_MN)
264 name=firmware_MN; 273 name=firmware_MN;
265 else if (t->std & V4L2_STD_DTV_6MHZ) 274 else if (std & V4L2_STD_DTV_6MHZ)
266 name=firmware_6M; 275 name=firmware_6M;
267 else if (t->std & V4L2_STD_DTV_7MHZ) 276 else if (std & V4L2_STD_DTV_7MHZ)
268 name=firmware_7M; 277 name=firmware_7M;
269 else if (t->std & V4L2_STD_DTV_8MHZ) 278 else if (std & V4L2_STD_DTV_8MHZ)
270 name=firmware_8M; 279 name=firmware_8M;
271 else if (t->std & V4L2_STD_PAL_B) 280 else if (std & V4L2_STD_PAL_B)
272 name=firmware_B; 281 name=firmware_B;
273 else 282 else
274 name=firmware_DK; 283 name=firmware_DK;
275 284
276 tuner_info("xc2028: loading firmware named %s.\n", name); 285 tuner_info("loading firmware named %s.\n", name);
277 rc = load_firmware(c, name); 286 rc = load_firmware(fe, name);
278 if (rc<0) 287 if (rc<0)
279 return rc; 288 return rc;
280 289
281 version = xc2028_get_reg(c, 0x4); 290 version = xc2028_get_reg(priv, 0x4);
282 tuner_info("Firmware version is %d.%d\n", 291 tuner_info("Firmware version is %d.%d\n",
283 (version>>4)&0x0f,(version)&0x0f); 292 (version>>4)&0x0f,(version)&0x0f);
284 293
285 xc2028->firm_type=t->std; 294 priv->firm_type=std;
286 295
287 return 0; 296 return 0;
288} 297}
289 298
290static int xc2028_signal(struct i2c_client *c) 299static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
291{ 300{
292 struct tuner *t = i2c_get_clientdata(c); 301 struct xc2028_data *priv = fe->tuner_priv;
293 struct xc2028_data *xc2028 = t->priv;
294 int frq_lock, signal=0; 302 int frq_lock, signal=0;
295 303
296 mutex_lock(&xc2028->lock); 304 tuner_info("%s called\n", __FUNCTION__);
297 305
298 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); 306 mutex_lock(&priv->lock);
299 307
300 frq_lock = xc2028_get_reg(c, 0x2); 308 *strength = 0;
309
310 frq_lock = xc2028_get_reg(priv, 0x2);
301 if (frq_lock<=0) 311 if (frq_lock<=0)
302 goto ret; 312 goto ret;
303 313
304 /* Frequency is locked. Return signal quality */ 314 /* Frequency is locked. Return signal quality */
305 315
306 signal = xc2028_get_reg(c, 0x40); 316 signal = xc2028_get_reg(priv, 0x40);
307 317
308 if(signal<=0) { 318 if(signal<=0) {
309 signal=frq_lock; 319 signal=frq_lock;
310 } 320 }
311 321
312ret: 322ret:
313 mutex_unlock(&xc2028->lock); 323 mutex_unlock(&priv->lock);
324
325 *strength = signal;
314 326
315 return signal; 327 return 0;
316} 328}
317 329
318#define DIV 15625 330#define DIV 15625
319 331
320static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, 332static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
321 enum tuner_mode new_mode, fe_bandwidth_t bandwidth) 333 enum tuner_mode new_mode,
334 v4l2_std_id std,
335 fe_bandwidth_t bandwidth)
322{ 336{
323 int rc; 337 struct xc2028_data *priv = fe->tuner_priv;
338 int rc=-EINVAL;
324 unsigned char buf[5]; 339 unsigned char buf[5];
325 struct tuner *t = i2c_get_clientdata(c);
326 u32 div, offset = 0; 340 u32 div, offset = 0;
327 341
342 tuner_info("%s called\n", __FUNCTION__);
343
328 /* HACK: It seems that specific firmware need to be reloaded 344 /* HACK: It seems that specific firmware need to be reloaded
329 when freq is changed */ 345 when freq is changed */
330 struct xc2028_data *xc2028 = t->priv;
331 346
332 mutex_lock(&xc2028->lock); 347 mutex_lock(&priv->lock);
333 348
334 xc2028->firm_type=0; 349 priv->firm_type=0;
335 350
336 /* Reset GPIO 1 */ 351 /* Reset GPIO 1 */
337 if (t->tuner_callback) { 352 rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0);
338 rc = t->tuner_callback( c->adapter->algo_data, 353 if (rc<0)
339 XC2028_TUNER_RESET, 0); 354 goto ret;
340 if (rc<0) 355
341 goto ret;
342 }
343 msleep(10); 356 msleep(10);
344 printk("xc3028: should set frequency %d kHz)\n", freq / 1000); 357 tuner_info("should set frequency %d kHz)\n", freq / 1000);
345 358
346 if (check_firmware(c, new_mode, bandwidth)<0) 359 if (check_firmware(fe, new_mode, std, bandwidth)<0)
347 goto ret; 360 goto ret;
348 361
349 if(new_mode == T_DIGITAL_TV) 362 if(new_mode == T_DIGITAL_TV)
@@ -352,13 +365,10 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */,
352 div = (freq - offset + DIV/2)/DIV; 365 div = (freq - offset + DIV/2)/DIV;
353 366
354 /* CMD= Set frequency */ 367 /* CMD= Set frequency */
355 send_seq(c, {0x00, 0x02, 0x00, 0x00}); 368 send_seq(priv, {0x00, 0x02, 0x00, 0x00});
356 if (t->tuner_callback) { 369 rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
357 rc = t->tuner_callback( c->adapter->algo_data, 370 if (rc<0)
358 XC2028_RESET_CLK, 1); 371 goto ret;
359 if (rc<0)
360 goto ret;
361 }
362 372
363 msleep(10); 373 msleep(10);
364 374
@@ -368,121 +378,82 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */,
368 buf[3]= 0xff & (div); 378 buf[3]= 0xff & (div);
369 buf[4]= 0; 379 buf[4]= 0;
370 380
371 i2c_send(rc, c, buf, sizeof(buf)); 381 i2c_send(rc, priv, buf, sizeof(buf));
372 if (rc<0) 382 if (rc<0)
373 goto ret; 383 goto ret;
374 msleep(100); 384 msleep(100);
375 385
386 priv->frequency=freq;
387
376 printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", 388 printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n",
377 buf[1],buf[2],buf[3],buf[4], 389 buf[1],buf[2],buf[3],buf[4],
378 freq / 16, freq % 16 * 100 / 16); 390 freq / 1000000, (freq%1000000)/10000);
379 391
380ret: 392 rc=0;
381 mutex_unlock(&xc2028->lock);
382}
383 393
394ret:
395 mutex_unlock(&priv->lock);
384 396
385static void set_tv_freq(struct i2c_client *c, unsigned int freq) 397 return rc;
386{
387 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
388
389 generic_set_tv_freq(c, freq * 62500l, T_ANALOG_TV,
390 BANDWIDTH_8_MHZ /* unimportant */);
391} 398}
392 399
393static void xc2028_release(struct i2c_client *c) 400static int xc2028_set_tv_freq(struct dvb_frontend *fe,
401 struct analog_parameters *p)
394{ 402{
395 struct tuner *t = i2c_get_clientdata(c); 403 struct xc2028_data *priv = fe->tuner_priv;
396 404
397 kfree(t->priv); 405 tuner_info("%s called\n", __FUNCTION__);
398 t->priv = NULL;
399}
400
401static struct tuner_operations tea5767_tuner_ops = {
402 .set_tv_freq = set_tv_freq,
403 .has_signal = xc2028_signal,
404 .release = xc2028_release,
405// .is_stereo = xc2028_stereo,
406};
407 406
407 return generic_set_tv_freq(fe, 62500l*p->frequency, T_ANALOG_TV,
408 p->std,
409 BANDWIDTH_8_MHZ /* NOT USED */);
410}
408 411
409static int init=0; 412static int xc2028_set_params(struct dvb_frontend *fe,
410 413 struct dvb_frontend_parameters *p)
411int xc2028_tuner_init(struct i2c_client *c)
412{ 414{
413 struct tuner *t = i2c_get_clientdata(c); 415 struct xc2028_data *priv = fe->tuner_priv;
414 int version = xc2028_get_reg(c, 0x4);
415 int prd_id = xc2028_get_reg(c, 0x8);
416 struct xc2028_data *xc2028;
417 416
418 tuner_info("Xcv2028/3028 init called!\n"); 417 tuner_info("%s called\n", __FUNCTION__);
419 418
420 if (init) { 419 /* FIXME: Only OFDM implemented */
421 printk (KERN_ERR "Module already initialized!\n"); 420 if (fe->ops.info.type != FE_OFDM) {
422 return 0; 421 tuner_info ("DTV type not implemented.\n");
422 return -EINVAL;
423 } 423 }
424 init++;
425
426 xc2028 = kzalloc(sizeof(*xc2028), GFP_KERNEL);
427 if (!xc2028)
428 return -ENOMEM;
429 t->priv = xc2028;
430 424
431 xc2028->bandwidth=BANDWIDTH_6_MHZ; 425 return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV,
432 xc2028->need_load_generic=1; 426 0, /* NOT USED */
433 xc2028->mode = T_UNINITIALIZED; 427 p->u.ofdm.bandwidth);
434 428
435 mutex_init(&xc2028->lock);
436
437 /* FIXME: Check where t->priv will be freed */
438
439 if (version<0)
440 version=0;
441
442 if (prd_id<0)
443 prd_id=0;
444
445 strlcpy(c->name, "xc2028", sizeof(c->name));
446 tuner_info("type set to %d (%s, hw ver=%d.%d, fw ver=%d.%d, id=0x%04x)\n",
447 t->type, c->name,
448 (version>>12)&0x0f,(version>>8)&0x0f,
449 (version>>4)&0x0f,(version)&0x0f, prd_id);
450
451 memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
452
453 return 0;
454} 429}
455 430
456static int xc3028_set_params(struct dvb_frontend *fe, 431static int xc2028_dvb_release(struct dvb_frontend *fe)
457 struct dvb_frontend_parameters *p)
458{ 432{
459 struct i2c_client *c = fe->tuner_priv; 433 struct xc2028_data *priv = fe->tuner_priv;
434
435 tuner_info("%s called\n", __FUNCTION__);
460 436
461 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); 437 priv->count--;
462 438
463 generic_set_tv_freq(c, p->frequency, T_DIGITAL_TV, 439 if (!priv->count)
464 p->u.ofdm.bandwidth); 440 kfree (priv);
465 441
466 return 0; 442 return 0;
467} 443}
468 444
469static int xc3028_dvb_release(struct dvb_frontend *fe) 445static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
470{ 446{
471 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); 447 struct xc2028_data *priv = fe->tuner_priv;
472 448
473 fe->tuner_priv = NULL; 449 tuner_info("%s called\n", __FUNCTION__);
474 450
475 return 0; 451 *frequency = priv->frequency;
476}
477
478static int xc3028_dvb_init(struct dvb_frontend *fe)
479{
480 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
481 452
482 return 0; 453 return 0;
483} 454}
484 455
485static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = { 456static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
486 .info = { 457 .info = {
487 .name = "Xceive XC3028", 458 .name = "Xceive XC3028",
488 .frequency_min = 42000000, 459 .frequency_min = 42000000,
@@ -490,33 +461,74 @@ static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = {
490 .frequency_step = 50000, 461 .frequency_step = 50000,
491 }, 462 },
492 463
493 .release = xc3028_dvb_release, 464 .set_analog_params = xc2028_set_tv_freq,
494 .init = xc3028_dvb_init, 465 .release = xc2028_dvb_release,
466 .get_frequency = xc2028_get_frequency,
467 .get_rf_strength = xc2028_signal,
468 .set_params = xc2028_set_params,
495 469
496// int (*sleep)(struct dvb_frontend *fe); 470// int (*sleep)(struct dvb_frontend *fe);
497
498 /** This is for simple PLLs - set all parameters in one go. */
499 .set_params = xc3028_set_params,
500
501 /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
502// int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
503
504// int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
505// int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); 471// int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
506
507// int (*get_status)(struct dvb_frontend *fe, u32 *status); 472// int (*get_status)(struct dvb_frontend *fe, u32 *status);
508}; 473};
509 474
510int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe) 475int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
476 u8 i2c_addr, struct device *dev, void *video_dev,
477 int (*tuner_callback) (void *dev, int command,int arg))
511{ 478{
512 fe->tuner_priv = c; 479 struct xc2028_data *priv;
513 480
514 memcpy(&fe->ops.tuner_ops, &xc3028_dvb_tuner_ops, sizeof(fe->ops.tuner_ops)); 481 printk( KERN_INFO PREFIX "Xcv2028/3028 init called!\n");
515 482
516 return 0; 483 if (NULL == dev)
517} 484 return -ENODEV;
485
486 if (NULL == video_dev)
487 return -ENODEV;
488
489 if (!tuner_callback) {
490 printk( KERN_ERR PREFIX "No tuner callback!\n");
491 return -EINVAL;
492 }
493
494 list_for_each_entry(priv, &xc2028_list, xc2028_list) {
495 if (priv->dev == dev) {
496 dev = NULL;
497 priv->count++;
498 }
499 }
500
501 if (dev) {
502 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
503 if (priv == NULL)
504 return -ENOMEM;
518 505
506 fe->tuner_priv = priv;
519 507
508 priv->bandwidth=BANDWIDTH_6_MHZ;
509 priv->need_load_generic=1;
510 priv->mode = T_UNINITIALIZED;
511 priv->i2c_props.addr = i2c_addr;
512 priv->i2c_props.adap = i2c_adap;
513 priv->dev = dev;
514 priv->video_dev = video_dev;
515 priv->tuner_callback = tuner_callback;
516
517 mutex_init(&priv->lock);
518
519 list_add_tail(&priv->xc2028_list,&xc2028_list);
520 }
521
522 memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
523 sizeof(xc2028_dvb_tuner_ops));
524
525 tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
526
527 return 0;
528}
520 529
521EXPORT_SYMBOL(xc2028_attach); 530EXPORT_SYMBOL(xc2028_attach);
522 531
532MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
533MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
534MODULE_LICENSE("GPL");