diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2007-08-27 20:23:40 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-09 21:07:39 -0400 |
commit | 7ab10bf72add23f0badf98ead92f58e34e14d35a (patch) | |
tree | 098a6c00ca2004f642ec84316449e78c1d8dd635 /drivers/media/video/tea5761.c | |
parent | 96c0b7cfa5de1d6be0a6f6d202a6a078f5577d8f (diff) |
V4L/DVB (6131): tea5761: convert from tuner sub-driver into dvb_frontend module
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Acked-by: Mike Isely <isely@pobox.com>
Acked-by: Steven Toth <stoth@hauppauge.com>
Acked-by: Patrick Boettcher <pb@linuxtv.org>
Acked-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tea5761.c')
-rw-r--r-- | drivers/media/video/tea5761.c | 132 |
1 files changed, 87 insertions, 45 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"); | ||