diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-01-16 03:16:29 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-02-14 14:11:23 -0500 |
commit | 1d211f26b5542da66cf48ff8ef783aceeb7e8099 (patch) | |
tree | 14a87984be2ccd6b3ba8dde93ee38f318876de21 /drivers/media/radio | |
parent | 32c518364a03d336113a9133410af6d8c8dc0107 (diff) |
[media] radio-trust: Convert to radio-isa
Tested with v4l2-compliance, but not with actual hardware. Contact the
linux-media mailinglist if you have this card!
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio')
-rw-r--r-- | drivers/media/radio/Kconfig | 5 | ||||
-rw-r--r-- | drivers/media/radio/radio-trust.c | 387 |
2 files changed, 104 insertions, 288 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 0b6d807f44c2..a81d15ccf067 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig | |||
@@ -377,10 +377,15 @@ config RADIO_TERRATEC | |||
377 | config RADIO_TRUST | 377 | config RADIO_TRUST |
378 | tristate "Trust FM radio card" | 378 | tristate "Trust FM radio card" |
379 | depends on ISA && VIDEO_V4L2 | 379 | depends on ISA && VIDEO_V4L2 |
380 | select RADIO_ISA | ||
380 | help | 381 | help |
381 | This is a driver for the Trust FM radio cards. Say Y if you have | 382 | This is a driver for the Trust FM radio cards. Say Y if you have |
382 | such a card and want to use it under Linux. | 383 | such a card and want to use it under Linux. |
383 | 384 | ||
385 | Note: this driver hasn't been tested since a long time due to lack | ||
386 | of hardware. If you have this hardware, then please contact the | ||
387 | linux-media mailinglist. | ||
388 | |||
384 | To compile this driver as a module, choose M here: the | 389 | To compile this driver as a module, choose M here: the |
385 | module will be called radio-trust. | 390 | module will be called radio-trust. |
386 | 391 | ||
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index b3f45a019d82..0703a801c639 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c | |||
@@ -23,11 +23,12 @@ | |||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <media/v4l2-device.h> | 24 | #include <media/v4l2-device.h> |
25 | #include <media/v4l2-ioctl.h> | 25 | #include <media/v4l2-ioctl.h> |
26 | #include "radio-isa.h" | ||
26 | 27 | ||
27 | MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); | 28 | MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); |
28 | MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); | 29 | MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); |
29 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
30 | MODULE_VERSION("0.0.3"); | 31 | MODULE_VERSION("0.1.99"); |
31 | 32 | ||
32 | /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ | 33 | /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ |
33 | 34 | ||
@@ -35,39 +36,38 @@ MODULE_VERSION("0.0.3"); | |||
35 | #define CONFIG_RADIO_TRUST_PORT -1 | 36 | #define CONFIG_RADIO_TRUST_PORT -1 |
36 | #endif | 37 | #endif |
37 | 38 | ||
38 | static int io = CONFIG_RADIO_TRUST_PORT; | 39 | #define TRUST_MAX 2 |
39 | static int radio_nr = -1; | ||
40 | 40 | ||
41 | module_param(io, int, 0); | 41 | static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT, |
42 | MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); | 42 | [1 ... (TRUST_MAX - 1)] = -1 }; |
43 | module_param(radio_nr, int, 0); | 43 | static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 }; |
44 | |||
45 | module_param_array(io, int, NULL, 0444); | ||
46 | MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)"); | ||
47 | module_param_array(radio_nr, int, NULL, 0444); | ||
48 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); | ||
44 | 49 | ||
45 | struct trust { | 50 | struct trust { |
46 | struct v4l2_device v4l2_dev; | 51 | struct radio_isa_card isa; |
47 | struct video_device vdev; | ||
48 | int io; | ||
49 | int ioval; | 52 | int ioval; |
50 | __u16 curvol; | ||
51 | __u16 curbass; | ||
52 | __u16 curtreble; | ||
53 | int muted; | ||
54 | unsigned long curfreq; | ||
55 | int curstereo; | ||
56 | int curmute; | ||
57 | struct mutex lock; | ||
58 | }; | 53 | }; |
59 | 54 | ||
60 | static struct trust trust_card; | 55 | static struct radio_isa_card *trust_alloc(void) |
56 | { | ||
57 | struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL); | ||
58 | |||
59 | return tr ? &tr->isa : NULL; | ||
60 | } | ||
61 | 61 | ||
62 | /* i2c addresses */ | 62 | /* i2c addresses */ |
63 | #define TDA7318_ADDR 0x88 | 63 | #define TDA7318_ADDR 0x88 |
64 | #define TSA6060T_ADDR 0xc4 | 64 | #define TSA6060T_ADDR 0xc4 |
65 | 65 | ||
66 | #define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) | 66 | #define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0) |
67 | #define TR_SET_SCL outb(tr->ioval |= 2, tr->io) | 67 | #define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io) |
68 | #define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) | 68 | #define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io) |
69 | #define TR_SET_SDA outb(tr->ioval |= 1, tr->io) | 69 | #define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io) |
70 | #define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) | 70 | #define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io) |
71 | 71 | ||
72 | static void write_i2c(struct trust *tr, int n, ...) | 72 | static void write_i2c(struct trust *tr, int n, ...) |
73 | { | 73 | { |
@@ -84,10 +84,10 @@ static void write_i2c(struct trust *tr, int n, ...) | |||
84 | TR_CLR_SCL; | 84 | TR_CLR_SCL; |
85 | TR_DELAY; | 85 | TR_DELAY; |
86 | 86 | ||
87 | for(; n; n--) { | 87 | for (; n; n--) { |
88 | val = va_arg(args, unsigned); | 88 | val = va_arg(args, unsigned); |
89 | for(mask = 0x80; mask; mask >>= 1) { | 89 | for (mask = 0x80; mask; mask >>= 1) { |
90 | if(val & mask) | 90 | if (val & mask) |
91 | TR_SET_SDA; | 91 | TR_SET_SDA; |
92 | else | 92 | else |
93 | TR_CLR_SDA; | 93 | TR_CLR_SDA; |
@@ -115,317 +115,128 @@ static void write_i2c(struct trust *tr, int n, ...) | |||
115 | va_end(args); | 115 | va_end(args); |
116 | } | 116 | } |
117 | 117 | ||
118 | static void tr_setvol(struct trust *tr, __u16 vol) | 118 | static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) |
119 | { | 119 | { |
120 | mutex_lock(&tr->lock); | 120 | struct trust *tr = container_of(isa, struct trust, isa); |
121 | tr->curvol = vol / 2048; | ||
122 | write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); | ||
123 | mutex_unlock(&tr->lock); | ||
124 | } | ||
125 | 121 | ||
126 | static int basstreble2chip[15] = { | 122 | tr->ioval = (tr->ioval & 0xf7) | (mute << 3); |
127 | 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 | 123 | outb(tr->ioval, isa->io); |
128 | }; | 124 | write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f); |
129 | 125 | return 0; | |
130 | static void tr_setbass(struct trust *tr, __u16 bass) | ||
131 | { | ||
132 | mutex_lock(&tr->lock); | ||
133 | tr->curbass = bass / 4370; | ||
134 | write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); | ||
135 | mutex_unlock(&tr->lock); | ||
136 | } | ||
137 | |||
138 | static void tr_settreble(struct trust *tr, __u16 treble) | ||
139 | { | ||
140 | mutex_lock(&tr->lock); | ||
141 | tr->curtreble = treble / 4370; | ||
142 | write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); | ||
143 | mutex_unlock(&tr->lock); | ||
144 | } | 126 | } |
145 | 127 | ||
146 | static void tr_setstereo(struct trust *tr, int stereo) | 128 | static int trust_s_stereo(struct radio_isa_card *isa, bool stereo) |
147 | { | 129 | { |
148 | mutex_lock(&tr->lock); | 130 | struct trust *tr = container_of(isa, struct trust, isa); |
149 | tr->curstereo = !!stereo; | ||
150 | tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); | ||
151 | outb(tr->ioval, tr->io); | ||
152 | mutex_unlock(&tr->lock); | ||
153 | } | ||
154 | 131 | ||
155 | static void tr_setmute(struct trust *tr, int mute) | 132 | tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2); |
156 | { | 133 | outb(tr->ioval, isa->io); |
157 | mutex_lock(&tr->lock); | 134 | return 0; |
158 | tr->curmute = !!mute; | ||
159 | tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); | ||
160 | outb(tr->ioval, tr->io); | ||
161 | mutex_unlock(&tr->lock); | ||
162 | } | 135 | } |
163 | 136 | ||
164 | static int tr_getsigstr(struct trust *tr) | 137 | static u32 trust_g_signal(struct radio_isa_card *isa) |
165 | { | 138 | { |
166 | int i, v; | 139 | int i, v; |
167 | 140 | ||
168 | mutex_lock(&tr->lock); | ||
169 | for (i = 0, v = 0; i < 100; i++) | 141 | for (i = 0, v = 0; i < 100; i++) |
170 | v |= inb(tr->io); | 142 | v |= inb(isa->io); |
171 | mutex_unlock(&tr->lock); | ||
172 | return (v & 1) ? 0 : 0xffff; | 143 | return (v & 1) ? 0 : 0xffff; |
173 | } | 144 | } |
174 | 145 | ||
175 | static int tr_getstereo(struct trust *tr) | 146 | static int trust_s_frequency(struct radio_isa_card *isa, u32 freq) |
176 | { | ||
177 | /* don't know how to determine it, just return the setting */ | ||
178 | return tr->curstereo; | ||
179 | } | ||
180 | |||
181 | static void tr_setfreq(struct trust *tr, unsigned long f) | ||
182 | { | 147 | { |
183 | mutex_lock(&tr->lock); | 148 | struct trust *tr = container_of(isa, struct trust, isa); |
184 | tr->curfreq = f; | ||
185 | f /= 160; /* Convert to 10 kHz units */ | ||
186 | f += 1070; /* Add 10.7 MHz IF */ | ||
187 | write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); | ||
188 | mutex_unlock(&tr->lock); | ||
189 | } | ||
190 | 149 | ||
191 | static int vidioc_querycap(struct file *file, void *priv, | 150 | freq /= 160; /* Convert to 10 kHz units */ |
192 | struct v4l2_capability *v) | 151 | freq += 1070; /* Add 10.7 MHz IF */ |
193 | { | 152 | write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1, |
194 | strlcpy(v->driver, "radio-trust", sizeof(v->driver)); | 153 | freq >> 7, 0x60 | ((freq >> 15) & 1), 0); |
195 | strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); | ||
196 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | ||
197 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
198 | return 0; | 154 | return 0; |
199 | } | 155 | } |
200 | 156 | ||
201 | static int vidioc_g_tuner(struct file *file, void *priv, | 157 | static int basstreble2chip[15] = { |
202 | struct v4l2_tuner *v) | 158 | 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 |
203 | { | 159 | }; |
204 | struct trust *tr = video_drvdata(file); | ||
205 | |||
206 | if (v->index > 0) | ||
207 | return -EINVAL; | ||
208 | |||
209 | strlcpy(v->name, "FM", sizeof(v->name)); | ||
210 | v->type = V4L2_TUNER_RADIO; | ||
211 | v->rangelow = 87.5 * 16000; | ||
212 | v->rangehigh = 108 * 16000; | ||
213 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
214 | v->capability = V4L2_TUNER_CAP_LOW; | ||
215 | if (tr_getstereo(tr)) | ||
216 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
217 | else | ||
218 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
219 | v->signal = tr_getsigstr(tr); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
224 | struct v4l2_tuner *v) | ||
225 | { | ||
226 | struct trust *tr = video_drvdata(file); | ||
227 | |||
228 | if (v->index) | ||
229 | return -EINVAL; | ||
230 | tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
235 | struct v4l2_frequency *f) | ||
236 | { | ||
237 | struct trust *tr = video_drvdata(file); | ||
238 | |||
239 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
240 | return -EINVAL; | ||
241 | tr_setfreq(tr, f->frequency); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
246 | struct v4l2_frequency *f) | ||
247 | { | ||
248 | struct trust *tr = video_drvdata(file); | ||
249 | |||
250 | if (f->tuner != 0) | ||
251 | return -EINVAL; | ||
252 | f->type = V4L2_TUNER_RADIO; | ||
253 | f->frequency = tr->curfreq; | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
258 | struct v4l2_queryctrl *qc) | ||
259 | { | ||
260 | switch (qc->id) { | ||
261 | case V4L2_CID_AUDIO_MUTE: | ||
262 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
263 | case V4L2_CID_AUDIO_VOLUME: | ||
264 | return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); | ||
265 | case V4L2_CID_AUDIO_BASS: | ||
266 | case V4L2_CID_AUDIO_TREBLE: | ||
267 | return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); | ||
268 | } | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
273 | struct v4l2_control *ctrl) | ||
274 | { | ||
275 | struct trust *tr = video_drvdata(file); | ||
276 | |||
277 | switch (ctrl->id) { | ||
278 | case V4L2_CID_AUDIO_MUTE: | ||
279 | ctrl->value = tr->curmute; | ||
280 | return 0; | ||
281 | case V4L2_CID_AUDIO_VOLUME: | ||
282 | ctrl->value = tr->curvol * 2048; | ||
283 | return 0; | ||
284 | case V4L2_CID_AUDIO_BASS: | ||
285 | ctrl->value = tr->curbass * 4370; | ||
286 | return 0; | ||
287 | case V4L2_CID_AUDIO_TREBLE: | ||
288 | ctrl->value = tr->curtreble * 4370; | ||
289 | return 0; | ||
290 | } | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | 160 | ||
294 | static int vidioc_s_ctrl(struct file *file, void *priv, | 161 | static int trust_s_ctrl(struct v4l2_ctrl *ctrl) |
295 | struct v4l2_control *ctrl) | ||
296 | { | 162 | { |
297 | struct trust *tr = video_drvdata(file); | 163 | struct radio_isa_card *isa = |
164 | container_of(ctrl->handler, struct radio_isa_card, hdl); | ||
165 | struct trust *tr = container_of(isa, struct trust, isa); | ||
298 | 166 | ||
299 | switch (ctrl->id) { | 167 | switch (ctrl->id) { |
300 | case V4L2_CID_AUDIO_MUTE: | ||
301 | tr_setmute(tr, ctrl->value); | ||
302 | return 0; | ||
303 | case V4L2_CID_AUDIO_VOLUME: | ||
304 | tr_setvol(tr, ctrl->value); | ||
305 | return 0; | ||
306 | case V4L2_CID_AUDIO_BASS: | 168 | case V4L2_CID_AUDIO_BASS: |
307 | tr_setbass(tr, ctrl->value); | 169 | write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]); |
308 | return 0; | 170 | return 0; |
309 | case V4L2_CID_AUDIO_TREBLE: | 171 | case V4L2_CID_AUDIO_TREBLE: |
310 | tr_settreble(tr, ctrl->value); | 172 | write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]); |
311 | return 0; | 173 | return 0; |
312 | } | 174 | } |
313 | return -EINVAL; | 175 | return -EINVAL; |
314 | } | 176 | } |
315 | 177 | ||
316 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | 178 | static const struct v4l2_ctrl_ops trust_ctrl_ops = { |
317 | { | 179 | .s_ctrl = trust_s_ctrl, |
318 | *i = 0; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
323 | { | ||
324 | return i ? -EINVAL : 0; | ||
325 | } | ||
326 | |||
327 | static int vidioc_g_audio(struct file *file, void *priv, | ||
328 | struct v4l2_audio *a) | ||
329 | { | ||
330 | a->index = 0; | ||
331 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
332 | a->capability = V4L2_AUDCAP_STEREO; | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int vidioc_s_audio(struct file *file, void *priv, | ||
337 | struct v4l2_audio *a) | ||
338 | { | ||
339 | return a->index ? -EINVAL : 0; | ||
340 | } | ||
341 | |||
342 | static const struct v4l2_file_operations trust_fops = { | ||
343 | .owner = THIS_MODULE, | ||
344 | .unlocked_ioctl = video_ioctl2, | ||
345 | }; | ||
346 | |||
347 | static const struct v4l2_ioctl_ops trust_ioctl_ops = { | ||
348 | .vidioc_querycap = vidioc_querycap, | ||
349 | .vidioc_g_tuner = vidioc_g_tuner, | ||
350 | .vidioc_s_tuner = vidioc_s_tuner, | ||
351 | .vidioc_g_frequency = vidioc_g_frequency, | ||
352 | .vidioc_s_frequency = vidioc_s_frequency, | ||
353 | .vidioc_queryctrl = vidioc_queryctrl, | ||
354 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
355 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
356 | .vidioc_g_audio = vidioc_g_audio, | ||
357 | .vidioc_s_audio = vidioc_s_audio, | ||
358 | .vidioc_g_input = vidioc_g_input, | ||
359 | .vidioc_s_input = vidioc_s_input, | ||
360 | }; | 180 | }; |
361 | 181 | ||
362 | static int __init trust_init(void) | 182 | static int trust_initialize(struct radio_isa_card *isa) |
363 | { | 183 | { |
364 | struct trust *tr = &trust_card; | 184 | struct trust *tr = container_of(isa, struct trust, isa); |
365 | struct v4l2_device *v4l2_dev = &tr->v4l2_dev; | ||
366 | int res; | ||
367 | 185 | ||
368 | strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); | ||
369 | tr->io = io; | ||
370 | tr->ioval = 0xf; | 186 | tr->ioval = 0xf; |
371 | mutex_init(&tr->lock); | ||
372 | |||
373 | if (tr->io == -1) { | ||
374 | v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | if (!request_region(tr->io, 2, "Trust FM Radio")) { | ||
378 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); | ||
379 | return -EBUSY; | ||
380 | } | ||
381 | |||
382 | res = v4l2_device_register(NULL, v4l2_dev); | ||
383 | if (res < 0) { | ||
384 | release_region(tr->io, 2); | ||
385 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
386 | return res; | ||
387 | } | ||
388 | |||
389 | strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); | ||
390 | tr->vdev.v4l2_dev = v4l2_dev; | ||
391 | tr->vdev.fops = &trust_fops; | ||
392 | tr->vdev.ioctl_ops = &trust_ioctl_ops; | ||
393 | tr->vdev.release = video_device_release_empty; | ||
394 | video_set_drvdata(&tr->vdev, tr); | ||
395 | |||
396 | write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ | 187 | write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ |
397 | write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ | 188 | write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ |
398 | write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ | 189 | write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ |
399 | write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ | 190 | write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ |
400 | write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ | 191 | write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ |
401 | 192 | ||
402 | tr_setvol(tr, 0xffff); | 193 | v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, |
403 | tr_setbass(tr, 0x8000); | 194 | V4L2_CID_AUDIO_BASS, 0, 15, 1, 8); |
404 | tr_settreble(tr, 0x8000); | 195 | v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, |
405 | tr_setstereo(tr, 1); | 196 | V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8); |
406 | 197 | return isa->hdl.error; | |
407 | /* mute card - prevents noisy bootups */ | 198 | } |
408 | tr_setmute(tr, 1); | ||
409 | 199 | ||
410 | if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | 200 | static const struct radio_isa_ops trust_ops = { |
411 | v4l2_device_unregister(v4l2_dev); | 201 | .init = trust_initialize, |
412 | release_region(tr->io, 2); | 202 | .alloc = trust_alloc, |
413 | return -EINVAL; | 203 | .s_mute_volume = trust_s_mute_volume, |
414 | } | 204 | .s_frequency = trust_s_frequency, |
205 | .s_stereo = trust_s_stereo, | ||
206 | .g_signal = trust_g_signal, | ||
207 | }; | ||
415 | 208 | ||
416 | v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); | 209 | static const int trust_ioports[] = { 0x350, 0x358 }; |
210 | |||
211 | static struct radio_isa_driver trust_driver = { | ||
212 | .driver = { | ||
213 | .match = radio_isa_match, | ||
214 | .probe = radio_isa_probe, | ||
215 | .remove = radio_isa_remove, | ||
216 | .driver = { | ||
217 | .name = "radio-trust", | ||
218 | }, | ||
219 | }, | ||
220 | .io_params = io, | ||
221 | .radio_nr_params = radio_nr, | ||
222 | .io_ports = trust_ioports, | ||
223 | .num_of_io_ports = ARRAY_SIZE(trust_ioports), | ||
224 | .region_size = 2, | ||
225 | .card = "Trust FM Radio", | ||
226 | .ops = &trust_ops, | ||
227 | .has_stereo = true, | ||
228 | .max_volume = 31, | ||
229 | }; | ||
417 | 230 | ||
418 | return 0; | 231 | static int __init trust_init(void) |
232 | { | ||
233 | return isa_register_driver(&trust_driver.driver, TRUST_MAX); | ||
419 | } | 234 | } |
420 | 235 | ||
421 | static void __exit cleanup_trust_module(void) | 236 | static void __exit trust_exit(void) |
422 | { | 237 | { |
423 | struct trust *tr = &trust_card; | 238 | isa_unregister_driver(&trust_driver.driver); |
424 | |||
425 | video_unregister_device(&tr->vdev); | ||
426 | v4l2_device_unregister(&tr->v4l2_dev); | ||
427 | release_region(tr->io, 2); | ||
428 | } | 239 | } |
429 | 240 | ||
430 | module_init(trust_init); | 241 | module_init(trust_init); |
431 | module_exit(cleanup_trust_module); | 242 | module_exit(trust_exit); |