diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2011-05-09 17:39:26 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-10 03:29:42 -0400 |
commit | 14219d06592025541559027d0fd8f96ef75f313c (patch) | |
tree | 0a137c2c9ef92b44c4a901c0c9c7df665db95eaf /sound | |
parent | 59bb7f0eebe69aa32a5c7917a23a7da1c5667d73 (diff) |
ALSA: tea575x: unify read/write functions
Implement generic read/write functions to access TEA575x tuners. They're now
implemented 4 times (once in es1968 and 3 times in fm801).
This also allows mute to work on all cards.
Also improve tuner detection/initialization.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/i2c/other/tea575x-tuner.c | 98 |
1 files changed, 72 insertions, 26 deletions
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 9f35f378a17d..31f9795daca6 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c | |||
@@ -77,11 +77,65 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
77 | * lowlevel part | 77 | * lowlevel part |
78 | */ | 78 | */ |
79 | 79 | ||
80 | static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val) | ||
81 | { | ||
82 | u16 l; | ||
83 | u8 data; | ||
84 | |||
85 | tea->ops->set_direction(tea, 1); | ||
86 | udelay(16); | ||
87 | |||
88 | for (l = 25; l > 0; l--) { | ||
89 | data = (val >> 24) & TEA575X_DATA; | ||
90 | val <<= 1; /* shift data */ | ||
91 | tea->ops->set_pins(tea, data | TEA575X_WREN); | ||
92 | udelay(2); | ||
93 | tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK); | ||
94 | udelay(2); | ||
95 | tea->ops->set_pins(tea, data | TEA575X_WREN); | ||
96 | udelay(2); | ||
97 | } | ||
98 | |||
99 | if (!tea->mute) | ||
100 | tea->ops->set_pins(tea, 0); | ||
101 | } | ||
102 | |||
103 | static unsigned int snd_tea575x_read(struct snd_tea575x *tea) | ||
104 | { | ||
105 | u16 l, rdata; | ||
106 | u32 data = 0; | ||
107 | |||
108 | tea->ops->set_direction(tea, 0); | ||
109 | tea->ops->set_pins(tea, 0); | ||
110 | udelay(16); | ||
111 | |||
112 | for (l = 24; l--;) { | ||
113 | tea->ops->set_pins(tea, TEA575X_CLK); | ||
114 | udelay(2); | ||
115 | if (!l) | ||
116 | tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1; | ||
117 | tea->ops->set_pins(tea, 0); | ||
118 | udelay(2); | ||
119 | data <<= 1; /* shift data */ | ||
120 | rdata = tea->ops->get_pins(tea); | ||
121 | if (!l) | ||
122 | tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1; | ||
123 | if (rdata & TEA575X_DATA) | ||
124 | data++; | ||
125 | udelay(2); | ||
126 | } | ||
127 | |||
128 | if (tea->mute) | ||
129 | tea->ops->set_pins(tea, TEA575X_WREN); | ||
130 | |||
131 | return data; | ||
132 | } | ||
133 | |||
80 | static void snd_tea575x_get_freq(struct snd_tea575x *tea) | 134 | static void snd_tea575x_get_freq(struct snd_tea575x *tea) |
81 | { | 135 | { |
82 | unsigned long freq; | 136 | unsigned long freq; |
83 | 137 | ||
84 | freq = tea->ops->read(tea) & TEA575X_BIT_FREQ_MASK; | 138 | freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; |
85 | /* freq *= 12.5 */ | 139 | /* freq *= 12.5 */ |
86 | freq *= 125; | 140 | freq *= 125; |
87 | freq /= 10; | 141 | freq /= 10; |
@@ -111,7 +165,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea) | |||
111 | 165 | ||
112 | tea->val &= ~TEA575X_BIT_FREQ_MASK; | 166 | tea->val &= ~TEA575X_BIT_FREQ_MASK; |
113 | tea->val |= freq & TEA575X_BIT_FREQ_MASK; | 167 | tea->val |= freq & TEA575X_BIT_FREQ_MASK; |
114 | tea->ops->write(tea, tea->val); | 168 | snd_tea575x_write(tea, tea->val); |
115 | } | 169 | } |
116 | 170 | ||
117 | /* | 171 | /* |
@@ -139,7 +193,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
139 | if (v->index > 0) | 193 | if (v->index > 0) |
140 | return -EINVAL; | 194 | return -EINVAL; |
141 | 195 | ||
142 | tea->ops->read(tea); | 196 | snd_tea575x_read(tea); |
143 | 197 | ||
144 | strcpy(v->name, "FM"); | 198 | strcpy(v->name, "FM"); |
145 | v->type = V4L2_TUNER_RADIO; | 199 | v->type = V4L2_TUNER_RADIO; |
@@ -233,10 +287,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
233 | 287 | ||
234 | switch (ctrl->id) { | 288 | switch (ctrl->id) { |
235 | case V4L2_CID_AUDIO_MUTE: | 289 | case V4L2_CID_AUDIO_MUTE: |
236 | if (tea->ops->mute) { | 290 | ctrl->value = tea->mute; |
237 | ctrl->value = tea->mute; | 291 | return 0; |
238 | return 0; | ||
239 | } | ||
240 | } | 292 | } |
241 | return -EINVAL; | 293 | return -EINVAL; |
242 | } | 294 | } |
@@ -248,11 +300,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
248 | 300 | ||
249 | switch (ctrl->id) { | 301 | switch (ctrl->id) { |
250 | case V4L2_CID_AUDIO_MUTE: | 302 | case V4L2_CID_AUDIO_MUTE: |
251 | if (tea->ops->mute) { | 303 | if (tea->mute != ctrl->value) { |
252 | tea->ops->mute(tea, ctrl->value); | ||
253 | tea->mute = ctrl->value; | 304 | tea->mute = ctrl->value; |
254 | return 0; | 305 | snd_tea575x_set_freq(tea); |
255 | } | 306 | } |
307 | return 0; | ||
256 | } | 308 | } |
257 | return -EINVAL; | 309 | return -EINVAL; |
258 | } | 310 | } |
@@ -317,18 +369,16 @@ static struct video_device tea575x_radio = { | |||
317 | /* | 369 | /* |
318 | * initialize all the tea575x chips | 370 | * initialize all the tea575x chips |
319 | */ | 371 | */ |
320 | void snd_tea575x_init(struct snd_tea575x *tea) | 372 | int snd_tea575x_init(struct snd_tea575x *tea) |
321 | { | 373 | { |
322 | int retval; | 374 | int retval; |
323 | unsigned int val; | ||
324 | struct video_device *tea575x_radio_inst; | 375 | struct video_device *tea575x_radio_inst; |
325 | 376 | ||
326 | val = tea->ops->read(tea); | 377 | tea->mute = 1; |
327 | if (val == 0x1ffffff || val == 0) { | 378 | |
328 | snd_printk(KERN_ERR | 379 | snd_tea575x_write(tea, 0x55AA); |
329 | "tea575x-tuner: Cannot find TEA575x chip\n"); | 380 | if (snd_tea575x_read(tea) != 0x55AA) |
330 | return; | 381 | return -ENODEV; |
331 | } | ||
332 | 382 | ||
333 | tea->in_use = 0; | 383 | tea->in_use = 0; |
334 | tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; | 384 | tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; |
@@ -337,7 +387,7 @@ void snd_tea575x_init(struct snd_tea575x *tea) | |||
337 | tea575x_radio_inst = video_device_alloc(); | 387 | tea575x_radio_inst = video_device_alloc(); |
338 | if (tea575x_radio_inst == NULL) { | 388 | if (tea575x_radio_inst == NULL) { |
339 | printk(KERN_ERR "tea575x-tuner: not enough memory\n"); | 389 | printk(KERN_ERR "tea575x-tuner: not enough memory\n"); |
340 | return; | 390 | return -ENOMEM; |
341 | } | 391 | } |
342 | 392 | ||
343 | memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); | 393 | memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); |
@@ -352,17 +402,13 @@ void snd_tea575x_init(struct snd_tea575x *tea) | |||
352 | if (retval) { | 402 | if (retval) { |
353 | printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); | 403 | printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); |
354 | kfree(tea575x_radio_inst); | 404 | kfree(tea575x_radio_inst); |
355 | return; | 405 | return retval; |
356 | } | 406 | } |
357 | 407 | ||
358 | snd_tea575x_set_freq(tea); | 408 | snd_tea575x_set_freq(tea); |
359 | |||
360 | /* mute on init */ | ||
361 | if (tea->ops->mute) { | ||
362 | tea->ops->mute(tea, 1); | ||
363 | tea->mute = 1; | ||
364 | } | ||
365 | tea->vd = tea575x_radio_inst; | 409 | tea->vd = tea575x_radio_inst; |
410 | |||
411 | return 0; | ||
366 | } | 412 | } |
367 | 413 | ||
368 | void snd_tea575x_exit(struct snd_tea575x *tea) | 414 | void snd_tea575x_exit(struct snd_tea575x *tea) |