diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-22 04:01:29 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-22 04:01:29 -0400 |
commit | 02e5fbf622aabf68bdc02282a17a3aeed054237a (patch) | |
tree | 60f2d4e09464dbf338c832bb39f861f29779b86b /sound/i2c | |
parent | b759b3ac9aee3afb01c21b603970ebb200c8048e (diff) | |
parent | bfe9fc8aebc997ce8bcf8ac0586c84a247812064 (diff) |
Merge branch 'topic/misc' into for-linus
Diffstat (limited to 'sound/i2c')
-rw-r--r-- | sound/i2c/other/Makefile | 2 | ||||
-rw-r--r-- | sound/i2c/other/tea575x-tuner.c | 153 |
2 files changed, 113 insertions, 42 deletions
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2dad40f3f622..c95d8f1aae87 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile | |||
@@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o | |||
14 | obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o | 14 | obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o |
15 | obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o | 15 | obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o |
16 | obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o | 16 | obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o |
17 | obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o | 17 | obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o |
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index ee538f1ae846..4831800239d3 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c | |||
@@ -37,8 +37,8 @@ static int radio_nr = -1; | |||
37 | module_param(radio_nr, int, 0); | 37 | module_param(radio_nr, int, 0); |
38 | 38 | ||
39 | #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) | 39 | #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) |
40 | #define FREQ_LO (87 * 16000) | 40 | #define FREQ_LO (50UL * 16000) |
41 | #define FREQ_HI (108 * 16000) | 41 | #define FREQ_HI (150UL * 16000) |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * definitions | 44 | * definitions |
@@ -77,27 +77,95 @@ 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 | |||
134 | static void snd_tea575x_get_freq(struct snd_tea575x *tea) | ||
135 | { | ||
136 | unsigned long freq; | ||
137 | |||
138 | freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; | ||
139 | /* freq *= 12.5 */ | ||
140 | freq *= 125; | ||
141 | freq /= 10; | ||
142 | /* crystal fixup */ | ||
143 | if (tea->tea5759) | ||
144 | freq += TEA575X_FMIF; | ||
145 | else | ||
146 | freq -= TEA575X_FMIF; | ||
147 | |||
148 | tea->freq = freq * 16; /* from kHz */ | ||
149 | } | ||
150 | |||
80 | static void snd_tea575x_set_freq(struct snd_tea575x *tea) | 151 | static void snd_tea575x_set_freq(struct snd_tea575x *tea) |
81 | { | 152 | { |
82 | unsigned long freq; | 153 | unsigned long freq; |
83 | 154 | ||
84 | freq = tea->freq / 16; /* to kHz */ | 155 | freq = clamp(tea->freq, FREQ_LO, FREQ_HI); |
85 | if (freq > 108000) | 156 | freq /= 16; /* to kHz */ |
86 | freq = 108000; | ||
87 | if (freq < 87000) | ||
88 | freq = 87000; | ||
89 | /* crystal fixup */ | 157 | /* crystal fixup */ |
90 | if (tea->tea5759) | 158 | if (tea->tea5759) |
91 | freq -= tea->freq_fixup; | 159 | freq -= TEA575X_FMIF; |
92 | else | 160 | else |
93 | freq += tea->freq_fixup; | 161 | freq += TEA575X_FMIF; |
94 | /* freq /= 12.5 */ | 162 | /* freq /= 12.5 */ |
95 | freq *= 10; | 163 | freq *= 10; |
96 | freq /= 125; | 164 | freq /= 125; |
97 | 165 | ||
98 | tea->val &= ~TEA575X_BIT_FREQ_MASK; | 166 | tea->val &= ~TEA575X_BIT_FREQ_MASK; |
99 | tea->val |= freq & TEA575X_BIT_FREQ_MASK; | 167 | tea->val |= freq & TEA575X_BIT_FREQ_MASK; |
100 | tea->ops->write(tea, tea->val); | 168 | snd_tea575x_write(tea, tea->val); |
101 | } | 169 | } |
102 | 170 | ||
103 | /* | 171 | /* |
@@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
109 | { | 177 | { |
110 | struct snd_tea575x *tea = video_drvdata(file); | 178 | struct snd_tea575x *tea = video_drvdata(file); |
111 | 179 | ||
112 | strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757"); | ||
113 | strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); | 180 | strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); |
114 | strlcpy(v->card, "Maestro Radio", sizeof(v->card)); | 181 | strlcpy(v->card, tea->card, sizeof(v->card)); |
115 | sprintf(v->bus_info, "PCI"); | 182 | strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); |
183 | strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); | ||
116 | v->version = RADIO_VERSION; | 184 | v->version = RADIO_VERSION; |
117 | v->capabilities = V4L2_CAP_TUNER; | 185 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; |
118 | return 0; | 186 | return 0; |
119 | } | 187 | } |
120 | 188 | ||
121 | static int vidioc_g_tuner(struct file *file, void *priv, | 189 | static int vidioc_g_tuner(struct file *file, void *priv, |
122 | struct v4l2_tuner *v) | 190 | struct v4l2_tuner *v) |
123 | { | 191 | { |
192 | struct snd_tea575x *tea = video_drvdata(file); | ||
193 | |||
124 | if (v->index > 0) | 194 | if (v->index > 0) |
125 | return -EINVAL; | 195 | return -EINVAL; |
126 | 196 | ||
197 | snd_tea575x_read(tea); | ||
198 | |||
127 | strcpy(v->name, "FM"); | 199 | strcpy(v->name, "FM"); |
128 | v->type = V4L2_TUNER_RADIO; | 200 | v->type = V4L2_TUNER_RADIO; |
201 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
129 | v->rangelow = FREQ_LO; | 202 | v->rangelow = FREQ_LO; |
130 | v->rangehigh = FREQ_HI; | 203 | v->rangehigh = FREQ_HI; |
131 | v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; | 204 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; |
132 | v->capability = V4L2_TUNER_CAP_LOW; | 205 | v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; |
133 | v->audmode = V4L2_TUNER_MODE_MONO; | 206 | v->signal = tea->tuned ? 0xffff : 0; |
134 | v->signal = 0xffff; | 207 | |
135 | return 0; | 208 | return 0; |
136 | } | 209 | } |
137 | 210 | ||
@@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
148 | { | 221 | { |
149 | struct snd_tea575x *tea = video_drvdata(file); | 222 | struct snd_tea575x *tea = video_drvdata(file); |
150 | 223 | ||
224 | if (f->tuner != 0) | ||
225 | return -EINVAL; | ||
151 | f->type = V4L2_TUNER_RADIO; | 226 | f->type = V4L2_TUNER_RADIO; |
227 | snd_tea575x_get_freq(tea); | ||
152 | f->frequency = tea->freq; | 228 | f->frequency = tea->freq; |
153 | return 0; | 229 | return 0; |
154 | } | 230 | } |
@@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
158 | { | 234 | { |
159 | struct snd_tea575x *tea = video_drvdata(file); | 235 | struct snd_tea575x *tea = video_drvdata(file); |
160 | 236 | ||
237 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
238 | return -EINVAL; | ||
239 | |||
161 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) | 240 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) |
162 | return -EINVAL; | 241 | return -EINVAL; |
163 | 242 | ||
@@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
209 | 288 | ||
210 | switch (ctrl->id) { | 289 | switch (ctrl->id) { |
211 | case V4L2_CID_AUDIO_MUTE: | 290 | case V4L2_CID_AUDIO_MUTE: |
212 | if (tea->ops->mute) { | 291 | ctrl->value = tea->mute; |
213 | ctrl->value = tea->mute; | 292 | return 0; |
214 | return 0; | ||
215 | } | ||
216 | } | 293 | } |
217 | return -EINVAL; | 294 | return -EINVAL; |
218 | } | 295 | } |
@@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
224 | 301 | ||
225 | switch (ctrl->id) { | 302 | switch (ctrl->id) { |
226 | case V4L2_CID_AUDIO_MUTE: | 303 | case V4L2_CID_AUDIO_MUTE: |
227 | if (tea->ops->mute) { | 304 | if (tea->mute != ctrl->value) { |
228 | tea->ops->mute(tea, ctrl->value); | ||
229 | tea->mute = ctrl->value; | 305 | tea->mute = ctrl->value; |
230 | return 0; | 306 | snd_tea575x_set_freq(tea); |
231 | } | 307 | } |
308 | return 0; | ||
232 | } | 309 | } |
233 | return -EINVAL; | 310 | return -EINVAL; |
234 | } | 311 | } |
@@ -293,18 +370,16 @@ static struct video_device tea575x_radio = { | |||
293 | /* | 370 | /* |
294 | * initialize all the tea575x chips | 371 | * initialize all the tea575x chips |
295 | */ | 372 | */ |
296 | void snd_tea575x_init(struct snd_tea575x *tea) | 373 | int snd_tea575x_init(struct snd_tea575x *tea) |
297 | { | 374 | { |
298 | int retval; | 375 | int retval; |
299 | unsigned int val; | ||
300 | struct video_device *tea575x_radio_inst; | 376 | struct video_device *tea575x_radio_inst; |
301 | 377 | ||
302 | val = tea->ops->read(tea); | 378 | tea->mute = 1; |
303 | if (val == 0x1ffffff || val == 0) { | 379 | |
304 | snd_printk(KERN_ERR | 380 | snd_tea575x_write(tea, 0x55AA); |
305 | "tea575x-tuner: Cannot find TEA575x chip\n"); | 381 | if (snd_tea575x_read(tea) != 0x55AA) |
306 | return; | 382 | return -ENODEV; |
307 | } | ||
308 | 383 | ||
309 | tea->in_use = 0; | 384 | tea->in_use = 0; |
310 | tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; | 385 | tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; |
@@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea) | |||
313 | tea575x_radio_inst = video_device_alloc(); | 388 | tea575x_radio_inst = video_device_alloc(); |
314 | if (tea575x_radio_inst == NULL) { | 389 | if (tea575x_radio_inst == NULL) { |
315 | printk(KERN_ERR "tea575x-tuner: not enough memory\n"); | 390 | printk(KERN_ERR "tea575x-tuner: not enough memory\n"); |
316 | return; | 391 | return -ENOMEM; |
317 | } | 392 | } |
318 | 393 | ||
319 | memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); | 394 | memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); |
@@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea) | |||
328 | if (retval) { | 403 | if (retval) { |
329 | printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); | 404 | printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); |
330 | kfree(tea575x_radio_inst); | 405 | kfree(tea575x_radio_inst); |
331 | return; | 406 | return retval; |
332 | } | 407 | } |
333 | 408 | ||
334 | snd_tea575x_set_freq(tea); | 409 | snd_tea575x_set_freq(tea); |
335 | |||
336 | /* mute on init */ | ||
337 | if (tea->ops->mute) { | ||
338 | tea->ops->mute(tea, 1); | ||
339 | tea->mute = 1; | ||
340 | } | ||
341 | tea->vd = tea575x_radio_inst; | 410 | tea->vd = tea575x_radio_inst; |
411 | |||
412 | return 0; | ||
342 | } | 413 | } |
343 | 414 | ||
344 | void snd_tea575x_exit(struct snd_tea575x *tea) | 415 | void snd_tea575x_exit(struct snd_tea575x *tea) |