diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-23 14:24:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:01:05 -0500 |
commit | 215b95baf969c6f895969f0a4ae0479954fba7cd (patch) | |
tree | 67e02c71a7d306cb82221e674325a27221ce5e06 /drivers | |
parent | 3b20532c791399182bd04f0fcc70b60a95637fa5 (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')
-rw-r--r-- | drivers/media/Kconfig | 8 | ||||
-rw-r--r-- | drivers/media/video/Kconfig | 12 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 5 | ||||
-rw-r--r-- | drivers/media/video/tuner-core.c | 12 | ||||
-rw-r--r-- | drivers/media/video/tuner-driver.h | 2 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 398 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.h | 24 |
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" | |||
69 | config VIDEO_TUNER | 69 | config 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 | ||
90 | if VIDEO_TUNER_CUSTOMIZE | 91 | if VIDEO_TUNER_CUSTOMIZE |
91 | 92 | ||
93 | config 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 | |||
92 | config TUNER_MT20XX | 100 | config 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 | ||
508 | config 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 | |||
520 | config VIDEO_VINO | 508 | config 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 |
7 | tuner-objs := tuner-core.o tuner-types.o tda9887.o | 7 | tuner-objs := tuner-core.o tuner-types.o tda9887.o |
8 | 8 | ||
9 | ifneq ($(CONFIG_TUNER_XC2028),) | ||
10 | tuner-objs += tuner-xc2028.o | ||
11 | endif | ||
12 | |||
13 | msp3400-objs := msp3400-driver.o msp3400-kthreads.o | 9 | msp3400-objs := msp3400-driver.o msp3400-kthreads.o |
14 | 10 | ||
15 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ | 11 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ |
@@ -85,6 +81,7 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o | |||
85 | 81 | ||
86 | obj-$(CONFIG_VIDEO_TUNER) += tuner.o | 82 | obj-$(CONFIG_VIDEO_TUNER) += tuner.o |
87 | 83 | ||
84 | obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o | ||
88 | obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o | 85 | obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o |
89 | obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o | 86 | obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o |
90 | obj-$(CONFIG_TUNER_TDA8290) += tda8290.o | 87 | obj-$(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 | ||
73 | extern int xc2028_tuner_init(struct i2c_client *c); | ||
74 | |||
75 | /* ------------------------------------------------------------------------ */ | 73 | /* ------------------------------------------------------------------------ */ |
76 | 74 | ||
77 | extern int tda9887_tuner_init(struct tuner *t); | 75 | extern 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) | 24 | static 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"; | |||
40 | static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; | 39 | static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; |
41 | 40 | ||
42 | struct xc2028_data { | 41 | struct 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) \ |
56 | if (size != (rc = i2c_master_send(c, buf, size))) \ | 64 | if (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) \ |
61 | if (size != (rc = i2c_master_recv(c, buf, size))) \ | 69 | if (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 | ||
77 | static int xc2028_get_reg(struct i2c_client *c, u16 reg) | 85 | static 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 | ||
96 | static int load_firmware (struct i2c_client *c, const char *name) | 105 | static 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 | ||
182 | static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, | 193 | static 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 | ||
290 | static int xc2028_signal(struct i2c_client *c) | 299 | static 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 | ||
312 | ret: | 322 | ret: |
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 | ||
320 | static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, | 332 | static 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 | ||
380 | ret: | 392 | rc=0; |
381 | mutex_unlock(&xc2028->lock); | ||
382 | } | ||
383 | 393 | ||
394 | ret: | ||
395 | mutex_unlock(&priv->lock); | ||
384 | 396 | ||
385 | static 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 | ||
393 | static void xc2028_release(struct i2c_client *c) | 400 | static 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 | |||
401 | static 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 | ||
409 | static int init=0; | 412 | static int xc2028_set_params(struct dvb_frontend *fe, |
410 | 413 | struct dvb_frontend_parameters *p) | |
411 | int 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 | ||
456 | static int xc3028_set_params(struct dvb_frontend *fe, | 431 | static 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 | ||
469 | static int xc3028_dvb_release(struct dvb_frontend *fe) | 445 | static 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 | |||
478 | static 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 | ||
485 | static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = { | 456 | static 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 | ||
510 | int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe) | 475 | int 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 | ||
521 | EXPORT_SYMBOL(xc2028_attach); | 530 | EXPORT_SYMBOL(xc2028_attach); |
522 | 531 | ||
532 | MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); | ||
533 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
534 | MODULE_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 @@ | |||
11 | struct dvb_frontend; | 16 | struct dvb_frontend; |
12 | struct i2c_client; | 17 | struct i2c_client; |
13 | 18 | ||
14 | int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe); | 19 | #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) |
20 | int 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 | ||
25 | static 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__ */ | ||