aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/media/Kconfig8
-rw-r--r--drivers/media/video/Kconfig12
-rw-r--r--drivers/media/video/Makefile5
-rw-r--r--drivers/media/video/tuner-core.c12
-rw-r--r--drivers/media/video/tuner-driver.h2
-rw-r--r--drivers/media/video/tuner-xc2028.c398
-rw-r--r--drivers/media/video/tuner-xc2028.h24
7 files changed, 248 insertions, 213 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 1604f0490404..dfb52592451f 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -69,6 +69,7 @@ source "drivers/media/common/Kconfig"
69config VIDEO_TUNER 69config VIDEO_TUNER
70 tristate 70 tristate
71 depends on I2C 71 depends on I2C
72 select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
72 select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE 73 select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
73 select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE 74 select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
74 select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE 75 select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
@@ -89,6 +90,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE
89 90
90if VIDEO_TUNER_CUSTOMIZE 91if VIDEO_TUNER_CUSTOMIZE
91 92
93config TUNER_XC2028
94 tristate "XCeive xc2028/xc3028 tuners"
95 depends on I2C
96 default m if VIDEO_TUNER_CUSTOMIZE
97 help
98 Say Y here to include support for the xc2028/xc3028 tuners.
99
92config TUNER_MT20XX 100config TUNER_MT20XX
93 tristate "Microtune 2032 / 2050 tuners" 101 tristate "Microtune 2032 / 2050 tuners"
94 depends on I2C 102 depends on I2C
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 454846355e93..ea5be3711a7d 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -505,18 +505,6 @@ config TUNER_3036
505 Say Y here to include support for Philips SAB3036 compatible tuners. 505 Say Y here to include support for Philips SAB3036 compatible tuners.
506 If in doubt, say N. 506 If in doubt, say N.
507 507
508config TUNER_XC2028
509 tristate "Xceive xc2028 support for tm5600/tm6000 driver"
510 depends on I2C
511 select VIDEO_TUNER
512 help
513 Say Y here to include support for Xceive xc2028 tuner. This is
514 required on a few tm5600/tm6000 designs. You should notice
515 that this module currently works only with the special
516 firmware versions used on those Trident chips.
517
518 If in doubt, say N.
519
520config VIDEO_VINO 508config VIDEO_VINO
521 tristate "SGI Vino Video For Linux (EXPERIMENTAL)" 509 tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
522 depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 510 depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 1fd775e0a0b0..08ac197cc1dd 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -6,10 +6,6 @@ zr36067-objs := zoran_procfs.o zoran_device.o \
6 zoran_driver.o zoran_card.o 6 zoran_driver.o zoran_card.o
7tuner-objs := tuner-core.o tuner-types.o tda9887.o 7tuner-objs := tuner-core.o tuner-types.o tda9887.o
8 8
9ifneq ($(CONFIG_TUNER_XC2028),)
10 tuner-objs += tuner-xc2028.o
11endif
12
13msp3400-objs := msp3400-driver.o msp3400-kthreads.o 9msp3400-objs := msp3400-driver.o msp3400-kthreads.o
14 10
15obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ 11obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
@@ -85,6 +81,7 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
85 81
86obj-$(CONFIG_VIDEO_TUNER) += tuner.o 82obj-$(CONFIG_VIDEO_TUNER) += tuner.o
87 83
84obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
88obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o 85obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
89obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o 86obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
90obj-$(CONFIG_TUNER_TDA8290) += tda8290.o 87obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index ce817a17ccf1..13112732ed2c 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -24,6 +24,7 @@
24#include "tda8290.h" 24#include "tda8290.h"
25#include "tea5761.h" 25#include "tea5761.h"
26#include "tea5767.h" 26#include "tea5767.h"
27#include "tuner-xc2028.h"
27#include "tuner-simple.h" 28#include "tuner-simple.h"
28 29
29#define UNSET (-1U) 30#define UNSET (-1U)
@@ -323,8 +324,17 @@ static void set_type(struct i2c_client *c, unsigned int type,
323 attach_simple_tuner(t); 324 attach_simple_tuner(t);
324 break; 325 break;
325 case TUNER_XC2028: 326 case TUNER_XC2028:
326 xc2028_tuner_init(c); 327 {
328 int rc=xc2028_attach(&t->fe, t->i2c.adapter, t->i2c.addr,
329 &c->dev, c->adapter->algo_data,
330 t->tuner_callback);
331 if (rc<0) {
332 t->type = TUNER_ABSENT;
333 t->mode_mask = T_UNINITIALIZED;
334 return;
335 }
327 break; 336 break;
337 }
328 case TUNER_TDA9887: 338 case TUNER_TDA9887:
329 tda9887_tuner_init(t); 339 tda9887_tuner_init(t);
330 break; 340 break;
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
index 5e733bc8362d..28a10da76d12 100644
--- a/drivers/media/video/tuner-driver.h
+++ b/drivers/media/video/tuner-driver.h
@@ -70,8 +70,6 @@ struct tuner {
70 struct tuner_operations ops; 70 struct tuner_operations ops;
71}; 71};
72 72
73extern int xc2028_tuner_init(struct i2c_client *c);
74
75/* ------------------------------------------------------------------------ */ 73/* ------------------------------------------------------------------------ */
76 74
77extern int tda9887_tuner_init(struct tuner *t); 75extern int tda9887_tuner_init(struct tuner *t);
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");
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
index 34ff4cba131a..d5a18a37d1c5 100644
--- a/drivers/media/video/tuner-xc2028.h
+++ b/drivers/media/video/tuner-xc2028.h
@@ -4,6 +4,11 @@
4 * This code is placed under the terms of the GNU General Public License v2 4 * This code is placed under the terms of the GNU General Public License v2
5 */ 5 */
6 6
7#ifndef __TUNER_XC2028_H__
8#define __TUNER_XC2028_H__
9
10#include "dvb_frontend.h"
11
7/* xc2028 commands for callback */ 12/* xc2028 commands for callback */
8#define XC2028_TUNER_RESET 0 13#define XC2028_TUNER_RESET 0
9#define XC2028_RESET_CLK 1 14#define XC2028_RESET_CLK 1
@@ -11,4 +16,21 @@
11struct dvb_frontend; 16struct dvb_frontend;
12struct i2c_client; 17struct i2c_client;
13 18
14int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe); 19#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
20int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
21 u8 i2c_addr, struct device *dev, void *video_dev,
22 int (*tuner_callback) (void *dev, int command,int arg));
23
24#else
25static inline int xc2028_attach(struct dvb_frontend *fe,
26 struct i2c_adapter* i2c_adap,
27 u8 i2c_addr, struct device *dev, void *video_dev,
28 int (*tuner_callback) (void *dev, int command,int arg))
29{
30 printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
31 __FUNCTION__);
32 return -EINVAL;
33}
34#endif
35
36#endif /* __TUNER_XC2028_H__ */