diff options
-rw-r--r-- | drivers/media/video/tea5761.c | 132 | ||||
-rw-r--r-- | drivers/media/video/tea5761.h | 28 | ||||
-rw-r--r-- | drivers/media/video/tuner-core.c | 5 | ||||
-rw-r--r-- | drivers/media/video/tuner-driver.h | 3 |
4 files changed, 118 insertions, 50 deletions
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 9965ba48cffa..8cdaf474ffdd 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c | |||
@@ -11,15 +11,19 @@ | |||
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
12 | #include <linux/videodev.h> | 12 | #include <linux/videodev.h> |
13 | #include <media/tuner.h> | 13 | #include <media/tuner.h> |
14 | #include "tuner-driver.h" | 14 | #include "tuner-i2c.h" |
15 | #include "tea5761.h" | ||
15 | 16 | ||
16 | #define PREFIX "TEA5761 " | 17 | static int debug = 0; |
18 | module_param(debug, int, 0644); | ||
19 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
17 | 20 | ||
18 | /* from tuner-core.c */ | 21 | #define PREFIX "tea5761 " |
19 | extern int tuner_debug; | ||
20 | 22 | ||
21 | struct tea5761_priv { | 23 | struct tea5761_priv { |
22 | struct tuner_i2c_props i2c_props; | 24 | struct tuner_i2c_props i2c_props; |
25 | |||
26 | u32 frequency; | ||
23 | }; | 27 | }; |
24 | 28 | ||
25 | /*****************************************************************************/ | 29 | /*****************************************************************************/ |
@@ -118,11 +122,6 @@ struct tea5761_priv { | |||
118 | 122 | ||
119 | /*****************************************************************************/ | 123 | /*****************************************************************************/ |
120 | 124 | ||
121 | static void set_tv_freq(struct tuner *t, unsigned int freq) | ||
122 | { | ||
123 | tuner_warn("This tuner doesn't support TV freq.\n"); | ||
124 | } | ||
125 | |||
126 | #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ | 125 | #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ |
127 | static void tea5761_status_dump(unsigned char *buffer) | 126 | static void tea5761_status_dump(unsigned char *buffer) |
128 | { | 127 | { |
@@ -137,16 +136,18 @@ static void tea5761_status_dump(unsigned char *buffer) | |||
137 | } | 136 | } |
138 | 137 | ||
139 | /* Freq should be specifyed at 62.5 Hz */ | 138 | /* Freq should be specifyed at 62.5 Hz */ |
140 | static void set_radio_freq(struct tuner *t, unsigned int frq) | 139 | static int set_radio_freq(struct dvb_frontend *fe, |
140 | struct analog_parameters *params) | ||
141 | { | 141 | { |
142 | struct tea5761_priv *priv = t->priv; | 142 | struct tea5761_priv *priv = fe->tuner_priv; |
143 | unsigned int frq = params->frequency; | ||
143 | unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; | 144 | unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; |
144 | unsigned div; | 145 | unsigned div; |
145 | int rc; | 146 | int rc; |
146 | 147 | ||
147 | tuner_dbg (PREFIX "radio freq counter %d\n", frq); | 148 | tuner_dbg("radio freq counter %d\n", frq); |
148 | 149 | ||
149 | if (t->mode == T_STANDBY) { | 150 | if (params->mode == T_STANDBY) { |
150 | tuner_dbg("TEA5761 set to standby mode\n"); | 151 | tuner_dbg("TEA5761 set to standby mode\n"); |
151 | buffer[5] |= TEA5761_TNCTRL_MU; | 152 | buffer[5] |= TEA5761_TNCTRL_MU; |
152 | } else { | 153 | } else { |
@@ -154,10 +155,9 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) | |||
154 | } | 155 | } |
155 | 156 | ||
156 | 157 | ||
157 | if (t->audmode == V4L2_TUNER_MODE_MONO) { | 158 | if (params->audmode == V4L2_TUNER_MODE_MONO) { |
158 | tuner_dbg("TEA5761 set to mono\n"); | 159 | tuner_dbg("TEA5761 set to mono\n"); |
159 | buffer[5] |= TEA5761_TNCTRL_MST; | 160 | buffer[5] |= TEA5761_TNCTRL_MST; |
160 | ; | ||
161 | } else { | 161 | } else { |
162 | tuner_dbg("TEA5761 set to stereo\n"); | 162 | tuner_dbg("TEA5761 set to stereo\n"); |
163 | } | 163 | } |
@@ -166,18 +166,22 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) | |||
166 | buffer[1] = (div >> 8) & 0x3f; | 166 | buffer[1] = (div >> 8) & 0x3f; |
167 | buffer[2] = div & 0xff; | 167 | buffer[2] = div & 0xff; |
168 | 168 | ||
169 | if (tuner_debug) | 169 | if (debug) |
170 | tea5761_status_dump(buffer); | 170 | tea5761_status_dump(buffer); |
171 | 171 | ||
172 | if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) | 172 | if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) |
173 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | 173 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); |
174 | |||
175 | priv->frequency = frq * 125 / 2; | ||
176 | |||
177 | return 0; | ||
174 | } | 178 | } |
175 | 179 | ||
176 | static int tea5761_signal(struct tuner *t) | 180 | static int tea5761_signal(struct dvb_frontend *fe) |
177 | { | 181 | { |
178 | unsigned char buffer[16]; | 182 | unsigned char buffer[16]; |
179 | int rc; | 183 | int rc; |
180 | struct tea5761_priv *priv = t->priv; | 184 | struct tea5761_priv *priv = fe->tuner_priv; |
181 | 185 | ||
182 | memset(buffer, 0, sizeof(buffer)); | 186 | memset(buffer, 0, sizeof(buffer)); |
183 | if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) | 187 | if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) |
@@ -186,11 +190,11 @@ static int tea5761_signal(struct tuner *t) | |||
186 | return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); | 190 | return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); |
187 | } | 191 | } |
188 | 192 | ||
189 | static int tea5761_stereo(struct tuner *t) | 193 | static int tea5761_stereo(struct dvb_frontend *fe) |
190 | { | 194 | { |
191 | unsigned char buffer[16]; | 195 | unsigned char buffer[16]; |
192 | int rc; | 196 | int rc; |
193 | struct tea5761_priv *priv = t->priv; | 197 | struct tea5761_priv *priv = fe->tuner_priv; |
194 | 198 | ||
195 | memset(buffer, 0, sizeof(buffer)); | 199 | memset(buffer, 0, sizeof(buffer)); |
196 | if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) | 200 | if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) |
@@ -203,58 +207,96 @@ static int tea5761_stereo(struct tuner *t) | |||
203 | return (rc ? V4L2_TUNER_SUB_STEREO : 0); | 207 | return (rc ? V4L2_TUNER_SUB_STEREO : 0); |
204 | } | 208 | } |
205 | 209 | ||
206 | int tea5761_autodetection(struct tuner *t) | 210 | static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) |
211 | { | ||
212 | struct tea5761_priv *priv = fe->tuner_priv; | ||
213 | int signal = tea5761_signal(fe); | ||
214 | |||
215 | *status = 0; | ||
216 | |||
217 | if (signal) | ||
218 | *status = TUNER_STATUS_LOCKED; | ||
219 | if (tea5761_stereo(fe)) | ||
220 | *status |= TUNER_STATUS_STEREO; | ||
221 | |||
222 | tuner_dbg("tea5761: Signal strength: %d\n", signal); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | ||
207 | { | 228 | { |
208 | unsigned char buffer[16]; | 229 | unsigned char buffer[16]; |
209 | int rc; | 230 | int rc; |
210 | struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; | 231 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; |
211 | 232 | ||
212 | if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { | 233 | if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { |
213 | tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); | 234 | printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); |
214 | return EINVAL; | 235 | return EINVAL; |
215 | } | 236 | } |
216 | 237 | ||
217 | if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) { | 238 | if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) { |
218 | tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); | 239 | printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); |
219 | return EINVAL; | 240 | return EINVAL; |
220 | } | 241 | } |
221 | tuner_warn("TEA5761 detected.\n"); | 242 | printk(KERN_WARNING "TEA5761 detected.\n"); |
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int tea5761_release(struct dvb_frontend *fe) | ||
247 | { | ||
248 | kfree(fe->tuner_priv); | ||
249 | fe->tuner_priv = NULL; | ||
250 | |||
222 | return 0; | 251 | return 0; |
223 | } | 252 | } |
224 | 253 | ||
225 | static void tea5761_release(struct tuner *t) | 254 | static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) |
226 | { | 255 | { |
227 | kfree(t->priv); | 256 | struct tea5761_priv *priv = fe->tuner_priv; |
228 | t->priv = NULL; | 257 | *frequency = priv->frequency; |
258 | return 0; | ||
229 | } | 259 | } |
230 | 260 | ||
231 | static struct tuner_operations tea5761_tuner_ops = { | 261 | static struct dvb_tuner_ops tea5761_tuner_ops = { |
232 | .set_tv_freq = set_tv_freq, | 262 | .info = { |
233 | .set_radio_freq = set_radio_freq, | 263 | .name = "tea5761", // Philips TEA5761HN FM Radio |
234 | .has_signal = tea5761_signal, | 264 | }, |
235 | .is_stereo = tea5761_stereo, | 265 | .set_analog_params = set_radio_freq, |
236 | .release = tea5761_release, | 266 | .release = tea5761_release, |
267 | .get_frequency = tea5761_get_frequency, | ||
268 | .get_status = tea5761_get_status, | ||
237 | }; | 269 | }; |
238 | 270 | ||
239 | int tea5761_tuner_init(struct tuner *t) | 271 | struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, |
272 | struct i2c_adapter* i2c_adap, | ||
273 | u8 i2c_addr) | ||
240 | { | 274 | { |
241 | struct tea5761_priv *priv = NULL; | 275 | struct tea5761_priv *priv = NULL; |
242 | 276 | ||
243 | if (tea5761_autodetection(t) == EINVAL) | 277 | if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL) |
244 | return EINVAL; | 278 | return NULL; |
245 | 279 | ||
246 | priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); | 280 | priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); |
247 | if (priv == NULL) | 281 | if (priv == NULL) |
248 | return -ENOMEM; | 282 | return NULL; |
249 | t->priv = priv; | 283 | fe->tuner_priv = priv; |
250 | 284 | ||
251 | priv->i2c_props.addr = t->i2c.addr; | 285 | priv->i2c_props.addr = i2c_addr; |
252 | priv->i2c_props.adap = t->i2c.adapter; | 286 | priv->i2c_props.adap = i2c_adap; |
253 | 287 | ||
254 | tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); | 288 | memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, |
255 | strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); | 289 | sizeof(struct dvb_tuner_ops)); |
256 | 290 | ||
257 | memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); | 291 | tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); |
258 | 292 | ||
259 | return (0); | 293 | return fe; |
260 | } | 294 | } |
295 | |||
296 | |||
297 | EXPORT_SYMBOL_GPL(tea5761_attach); | ||
298 | EXPORT_SYMBOL_GPL(tea5761_autodetection); | ||
299 | |||
300 | MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); | ||
301 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
302 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h new file mode 100644 index 000000000000..f287c0291bff --- /dev/null +++ b/drivers/media/video/tea5761.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TEA5761_H__ | ||
18 | #define __TEA5761_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); | ||
24 | extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
25 | struct i2c_adapter* i2c_adap, | ||
26 | u8 i2c_addr); | ||
27 | |||
28 | #endif /* __TEA5761_H__ */ | ||
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f24ec1a18b45..848ee6420c5c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "tuner-driver.h" | 21 | #include "tuner-driver.h" |
22 | #include "mt20xx.h" | 22 | #include "mt20xx.h" |
23 | #include "tda8290.h" | 23 | #include "tda8290.h" |
24 | #include "tea5761.h" | ||
24 | 25 | ||
25 | #define UNSET (-1U) | 26 | #define UNSET (-1U) |
26 | 27 | ||
@@ -270,7 +271,7 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
270 | break; | 271 | break; |
271 | #ifdef CONFIG_TUNER_TEA5761 | 272 | #ifdef CONFIG_TUNER_TEA5761 |
272 | case TUNER_TEA5761: | 273 | case TUNER_TEA5761: |
273 | if (tea5761_tuner_init(t) == EINVAL) { | 274 | if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { |
274 | t->type = TUNER_ABSENT; | 275 | t->type = TUNER_ABSENT; |
275 | t->mode_mask = T_UNINITIALIZED; | 276 | t->mode_mask = T_UNINITIALIZED; |
276 | return; | 277 | return; |
@@ -571,7 +572,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
571 | switch (addr) { | 572 | switch (addr) { |
572 | #ifdef CONFIG_TUNER_TEA5761 | 573 | #ifdef CONFIG_TUNER_TEA5761 |
573 | case 0x10: | 574 | case 0x10: |
574 | if (tea5761_autodetection(t) != EINVAL) { | 575 | if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { |
575 | t->type = TUNER_TEA5761; | 576 | t->type = TUNER_TEA5761; |
576 | t->mode_mask = T_RADIO; | 577 | t->mode_mask = T_RADIO; |
577 | t->mode = T_STANDBY; | 578 | t->mode = T_STANDBY; |
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 87d937f2f740..bcb6a61c2086 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h | |||
@@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); | |||
76 | 76 | ||
77 | extern int tda9887_tuner_init(struct tuner *t); | 77 | extern int tda9887_tuner_init(struct tuner *t); |
78 | 78 | ||
79 | extern int tea5761_tuner_init(struct tuner *t); | ||
80 | extern int tea5761_autodetection(struct tuner *t); | ||
81 | |||
82 | extern int tea5767_autodetection(struct tuner *t); | 79 | extern int tea5767_autodetection(struct tuner *t); |
83 | extern int tea5767_tuner_init(struct tuner *t); | 80 | extern int tea5767_tuner_init(struct tuner *t); |
84 | 81 | ||