Date:2011-10-02 18:35:59 (10 years 11 months ago)
Author:Maarten ter Huurne
Commit:daf6635b83d8430f2c5619ab69506434120ad546
Message:media: radio: RDA5807: Added driver.

Driver has enough functionality to make fmtools 2.x work, but is a work
in progress.

Many thanks to Jérôme VERES for his command line radio application that
demonstrates how the chip can be controlled via I2C.

Squashed version of development done in jz-3.0 branch.
Files: drivers/media/radio/Kconfig (1 diff)
drivers/media/radio/Makefile (1 diff)
drivers/media/radio/radio-rda5807.c (1 diff)
include/media/radio-rda5807.h (1 diff)

Change Details

drivers/media/radio/Kconfig
369369      To compile this driver as a module, choose M here: the
370370      module will be called radio-mr800.
371371
372config RADIO_RDA5807
373    tristate "RDA5807 I2C FM radio support"
374    depends on I2C && VIDEO_V4L2
375    ---help---
376      Say Y here if you want to use the RDA5807 FM receiver connected to
377      an I2C bus. It is used in for example the Dingoo A320 portable
378      media player.
379
380      To compile this driver as a module, choose M here: the
381      module will be called radio-rda5807.
382
372383config RADIO_TEA5764
373384    tristate "TEA5764 I2C FM radio support"
374385    depends on I2C && VIDEO_V4L2
drivers/media/radio/Makefile
2020obj-$(CONFIG_USB_DSBR) += dsbr100.o
2121obj-$(CONFIG_RADIO_SI470X) += si470x/
2222obj-$(CONFIG_USB_MR800) += radio-mr800.o
23obj-$(CONFIG_RADIO_RDA5807) += radio-rda5807.o
2324obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
2425obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
2526obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
drivers/media/radio/radio-rda5807.c
1/*
2 * radio-rda5807.c - Driver for using the RDA5807 FM tuner chip via I2C
3 *
4 * Copyright (c) 2011 Maarten ter Huurne <maarten@treewalker.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *
20 * Many thanks to Jérôme VERES for his command line radio application that
21 * demonstrates how the chip can be controlled via I2C.
22 *
23 * The RDA5807 has three ways of accessing registers:
24 * - I2C address 0x10: sequential access, RDA5800 style
25 * - I2C address 0x11: random access
26 * - I2C address 0x60: sequential access, TEA5767 compatible
27 * This driver uses random access and therefore the i2c_board_info should
28 * specify address 0x11 using the macro RDA5807_I2C_ADDR.
29 * Note that while there are many similarities, the register map of the RDA5807
30 * differs from that of the RDA5800 in several essential places.
31 */
32
33
34#include <asm/byteorder.h>
35#include <linux/bitops.h>
36#include <linux/module.h>
37#include <linux/i2c.h>
38#include <linux/kernel.h>
39#include <linux/pm.h>
40#include <linux/slab.h>
41#include <linux/types.h>
42#include <linux/videodev2.h>
43#include <media/radio-rda5807.h>
44#include <media/v4l2-ctrls.h>
45#include <media/v4l2-dev.h>
46#include <media/v4l2-ioctl.h>
47
48
49enum rda5807_reg {
50    RDA5807_REG_CHIPID = 0x00,
51    RDA5807_REG_CTRL = 0x02,
52    RDA5807_REG_CHAN = 0x03,
53    RDA5807_REG_IOCFG = 0x04,
54    RDA5807_REG_INTM_THRESH_VOL = 0x05,
55    RDA5807_REG_SEEK_RESULT = 0x0A,
56    RDA5807_REG_SIGNAL = 0x0B,
57};
58
59#define RDA5807_MASK_CTRL_DHIZ BIT(15)
60#define RDA5807_MASK_CTRL_DMUTE BIT(14)
61#define RDA5807_MASK_CTRL_MONO BIT(13)
62#define RDA5807_MASK_CTRL_BASS BIT(12)
63#define RDA5807_MASK_CTRL_SEEKUP BIT(9)
64#define RDA5807_MASK_CTRL_SEEK BIT(8)
65#define RDA5807_MASK_CTRL_SKMODE BIT(7)
66#define RDA5807_MASK_CTRL_CLKMODE (7 << 4)
67#define RDA5807_MASK_CTRL_SOFTRESET BIT(1)
68#define RDA5807_MASK_CTRL_ENABLE BIT(0)
69
70#define RDA5807_SHIFT_CHAN_WRCHAN 6
71#define RDA5807_MASK_CHAN_WRCHAN (0x3FF << RDA5807_SHIFT_CHAN_WRCHAN)
72#define RDA5807_MASK_CHAN_TUNE BIT(4)
73#define RDA5807_SHIFT_CHAN_BAND 2
74#define RDA5807_MASK_CHAN_BAND (0x3 << RDA5807_SHIFT_CHAN_BAND)
75#define RDA5807_SHIFT_CHAN_SPACE 0
76#define RDA5807_MASK_CHAN_SPACE (0x3 << RDA5807_SHIFT_CHAN_SPACE)
77
78#define RDA5807_MASK_SEEKRES_COMPLETE BIT(14)
79#define RDA5807_MASK_SEEKRES_FAIL BIT(13)
80#define RDA5807_MASK_SEEKRES_STEREO BIT(10)
81#define RDA5807_MASK_SEEKRES_READCHAN 0x3FF
82
83#define RDA5807_MASK_DEEMPHASIS BIT(11)
84
85#define RDA5807_SHIFT_VOLUME_DAC 0
86#define RDA5807_MASK_VOLUME_DAC (0xF << RDA5807_SHIFT_VOLUME_DAC)
87
88#define RDA5807_SHIFT_RSSI 9
89#define RDA5807_MASK_RSSI (0x7F << RDA5807_SHIFT_RSSI)
90
91#define RDA5807_FREQ_MIN_KHZ 76000
92#define RDA5807_FREQ_MAX_KHZ 108000
93
94static int rda5807_i2c_read(struct i2c_client *client, enum rda5807_reg reg)
95{
96    __u8 reg_buf = reg;
97    __u16 val_buf;
98    struct i2c_msg msgs[] = {
99        { /* write register number */
100            .addr = client->addr,
101            .flags = 0,
102            .len = sizeof(reg_buf),
103            .buf = &reg_buf,
104        },
105        { /* read register contents */
106            .addr = client->addr,
107            .flags = I2C_M_RD,
108            .len = sizeof(val_buf),
109            .buf = (__u8 *)&val_buf,
110        },
111    };
112    int err;
113
114    err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
115    if (err < 0) return err;
116    if (err < ARRAY_SIZE(msgs)) return -EIO;
117
118    dev_info(&client->dev, "reg[%02X] = %04X\n", reg, be16_to_cpu(val_buf));
119    return be16_to_cpu(val_buf);
120}
121
122static int rda5807_i2c_write(struct i2c_client *client, enum rda5807_reg reg,
123                 u16 val)
124{
125    __u8 buf[] = { reg, val >> 8, val & 0xFF };
126    struct i2c_msg msgs[] = {
127        { /* write register number and contents */
128            .addr = client->addr,
129            .flags = 0,
130            .len = sizeof(buf),
131            .buf = buf,
132        },
133    };
134    int err;
135
136    err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
137    if (err < 0) return err;
138    if (err < ARRAY_SIZE(msgs)) return -EIO;
139
140    dev_info(&client->dev, "reg[%02X] := %04X\n", reg, val);
141    return 0;
142}
143
144struct rda5807_driver {
145    struct v4l2_ctrl_handler ctrl_handler;
146    struct video_device video_dev;
147    struct i2c_client *i2c_client;
148};
149
150static const struct v4l2_file_operations rda5807_fops = {
151    .owner = THIS_MODULE,
152    .unlocked_ioctl = video_ioctl2,
153};
154
155static int rda5807_update_reg(struct rda5807_driver *radio,
156                  enum rda5807_reg reg, u16 mask, u16 val)
157{
158    int err = 0;
159    // TODO: Locking.
160    // Or do locking in the caller, in case we ever need to update
161    // two registers in one operation?
162    err = rda5807_i2c_read(radio->i2c_client, reg);
163    if (err >= 0) {
164        val |= ((u16)err & ~mask);
165        err = rda5807_i2c_write(radio->i2c_client, reg, val);
166    }
167    return err;
168}
169
170static int rda5807_set_enable(struct rda5807_driver *radio, int enabled)
171{
172    u16 val = enabled ? RDA5807_MASK_CTRL_ENABLE : 0;
173    int err;
174    dev_info(&radio->i2c_client->dev, "set enabled to %d\n", enabled);
175    err = rda5807_update_reg(radio, RDA5807_REG_CTRL,
176                 RDA5807_MASK_CTRL_ENABLE, val);
177    if (err < 0)
178        return err;
179    /* Tuning is lost when the chip is disabled, so re-tune when enabled. */
180    if (enabled)
181        return rda5807_update_reg(radio, RDA5807_REG_CHAN,
182                      RDA5807_MASK_CHAN_TUNE,
183                      RDA5807_MASK_CHAN_TUNE);
184    else
185        return 0;
186}
187
188static int rda5807_set_mute(struct rda5807_driver *radio, int muted)
189{
190    u16 val = muted ? 0 : RDA5807_MASK_CTRL_DMUTE /* disable mute */;
191    dev_info(&radio->i2c_client->dev, "set mute to %d\n", muted);
192    return rda5807_update_reg(radio, RDA5807_REG_CTRL,
193                  RDA5807_MASK_CTRL_DMUTE, val);
194}
195
196static int rda5807_set_volume(struct rda5807_driver *radio, int volume)
197{
198    dev_info(&radio->i2c_client->dev, "set volume to %d\n", volume);
199    return rda5807_update_reg(radio, RDA5807_REG_INTM_THRESH_VOL,
200                  RDA5807_MASK_VOLUME_DAC,
201                  volume << RDA5807_SHIFT_VOLUME_DAC);
202}
203
204static int rda5807_set_preemphasis(struct rda5807_driver *radio,
205                   enum v4l2_preemphasis preemp)
206{
207    dev_info(&radio->i2c_client->dev, "set preemphasis to %d\n", preemp);
208    return rda5807_update_reg(radio, RDA5807_REG_IOCFG,
209                  RDA5807_MASK_DEEMPHASIS,
210                  preemp == V4L2_PREEMPHASIS_50_uS
211                          ? RDA5807_MASK_DEEMPHASIS : 0);
212}
213
214static int rda5807_get_frequency(struct rda5807_driver *radio)
215{
216    u32 freq_khz;
217    u16 val;
218    int err;
219
220    err = rda5807_i2c_read(radio->i2c_client, RDA5807_REG_SEEK_RESULT);
221    if (err < 0)
222        return err;
223    val = err;
224
225    freq_khz = 50 * (val & RDA5807_MASK_SEEKRES_READCHAN)
226         + RDA5807_FREQ_MIN_KHZ;
227    dev_info(&radio->i2c_client->dev, "get freq of %u kHz\n", freq_khz);
228    return freq_khz;
229}
230
231static int rda5807_set_frequency(struct rda5807_driver *radio, u32 freq_khz)
232{
233    u16 mask = 0;
234    u16 val = 0;
235
236    dev_info(&radio->i2c_client->dev, "set freq to %u kHz\n", freq_khz);
237
238    if (freq_khz < RDA5807_FREQ_MIN_KHZ)
239        return -ERANGE;
240    if (freq_khz > RDA5807_FREQ_MAX_KHZ)
241        return -ERANGE;
242
243    /* select widest band */
244    mask |= RDA5807_MASK_CHAN_BAND;
245    val |= 2 << RDA5807_SHIFT_CHAN_BAND;
246    /* select 50 kHz channel spacing */
247    mask |= RDA5807_MASK_CHAN_SPACE;
248    val |= 2 << RDA5807_SHIFT_CHAN_SPACE;
249    /* select frequency */
250    mask |= RDA5807_MASK_CHAN_WRCHAN;
251    val |= ((freq_khz - RDA5807_FREQ_MIN_KHZ + 25) / 50)
252            << RDA5807_SHIFT_CHAN_WRCHAN;
253    /* start tune operation */
254    mask |= RDA5807_MASK_CHAN_TUNE;
255    val |= RDA5807_MASK_CHAN_TUNE;
256
257    return rda5807_update_reg(radio, RDA5807_REG_CHAN, mask, val);
258}
259
260static int rda5807_seek_frequency(struct rda5807_driver *radio,
261                  int upward, int wrap)
262{
263    u16 mask = 0;
264    u16 val = 0;
265
266    /* TODO: Seek threshold is configurable. How should the driver handle
267     * this configuration?
268     */
269    /* seek up or down? */
270    mask |= RDA5807_MASK_CTRL_SEEKUP;
271    if (upward)
272        val |= RDA5807_MASK_CTRL_SEEKUP;
273    /* wrap around at band limit? */
274    mask |= RDA5807_MASK_CTRL_SKMODE;
275    if (!wrap)
276        val |= RDA5807_MASK_CTRL_SKMODE;
277    /* seek command */
278    mask |= RDA5807_MASK_CTRL_SEEK;
279    val |= RDA5807_MASK_CTRL_SEEK;
280
281    return rda5807_update_reg(radio, RDA5807_REG_CTRL, mask, val);
282}
283
284static inline struct rda5807_driver *ctrl_to_radio(struct v4l2_ctrl *ctrl)
285{
286    return container_of(ctrl->handler, struct rda5807_driver, ctrl_handler);
287}
288
289static int rda5807_s_ctrl(struct v4l2_ctrl *ctrl)
290{
291    struct rda5807_driver *radio = ctrl_to_radio(ctrl);
292
293    switch (ctrl->id) {
294    case V4L2_CID_AUDIO_MUTE: {
295        /* Disable the radio while muted, to save power.
296         * TODO: We can't seek while the radio is disabled;
297         * is that a problem?
298         */
299        int err1 = rda5807_set_enable(radio, !ctrl->val);
300        int err2 = rda5807_set_mute(radio, ctrl->val);
301        return err1 ? err1 : err2;
302    }
303    case V4L2_CID_AUDIO_VOLUME:
304        return rda5807_set_volume(radio, ctrl->val);
305    case V4L2_CID_TUNE_PREEMPHASIS:
306        return rda5807_set_preemphasis(radio, ctrl->val);
307    default:
308        return -EINVAL;
309    }
310}
311
312static const struct v4l2_ctrl_ops rda5807_ctrl_ops = {
313    .s_ctrl = rda5807_s_ctrl,
314};
315
316static int rda5807_vidioc_querycap(struct file *file, void *fh,
317                   struct v4l2_capability *cap)
318{
319    *cap = (struct v4l2_capability) {
320        .driver = "rda5807",
321        .card = "RDA5807 FM receiver",
322        .bus_info = "I2C",
323        .capabilities = V4L2_CAP_RADIO | V4L2_CAP_TUNER
324                    | V4L2_CAP_HW_FREQ_SEEK,
325    };
326
327    return 0;
328}
329
330static int rda5807_vidioc_g_audio(struct file *file, void *fh,
331                  struct v4l2_audio *a)
332{
333    if (a->index != 0)
334        return -EINVAL;
335
336    *a = (struct v4l2_audio) {
337        .name = "Radio",
338        .capability = V4L2_AUDCAP_STEREO,
339        .mode = 0,
340    };
341
342    return 0;
343}
344
345static int rda5807_vidioc_g_tuner(struct file *file, void *fh,
346                  struct v4l2_tuner *a)
347{
348    struct rda5807_driver *radio = video_drvdata(file);
349    int err;
350    u16 seekres, signal;
351    __u32 rxsubchans;
352
353    if (a->index != 0)
354        return -EINVAL;
355
356    err = rda5807_i2c_read(radio->i2c_client, RDA5807_REG_SEEK_RESULT);
357    if (err < 0)
358        return err;
359    seekres = (u16)err;
360    if ((seekres & (RDA5807_MASK_SEEKRES_COMPLETE
361                        | RDA5807_MASK_SEEKRES_FAIL))
362                == RDA5807_MASK_SEEKRES_COMPLETE)
363        /* mono/stereo known */
364        rxsubchans = seekres & RDA5807_MASK_SEEKRES_STEREO
365                ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
366    else
367        /* mono/stereo unknown */
368        rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
369
370    err = rda5807_i2c_read(radio->i2c_client, RDA5807_REG_SIGNAL);
371    if (err < 0)
372        return err;
373    signal = ((u16)err & RDA5807_MASK_RSSI) >> RDA5807_SHIFT_RSSI;
374
375    *a = (struct v4l2_tuner) {
376        .name = "FM",
377        .type = V4L2_TUNER_RADIO,
378        .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO,
379        /* unit is 1/16 kHz */
380        .rangelow = RDA5807_FREQ_MIN_KHZ * 16,
381        .rangehigh = RDA5807_FREQ_MAX_KHZ * 16,
382        .rxsubchans = rxsubchans,
383        /* TODO: Implement forced mono (RDA5807_MASK_CTRL_MONO). */
384        .audmode = V4L2_TUNER_MODE_STEREO,
385        .signal = signal << (16 - 7),
386        .afc = 0, /* automatic frequency control */
387    };
388
389    return 0;
390}
391
392static int rda5807_vidioc_g_frequency(struct file *file, void *fh,
393                      struct v4l2_frequency *a)
394{
395    struct rda5807_driver *radio = video_drvdata(file);
396    int freq_khz;
397
398    if (a->tuner != 0)
399        return -EINVAL;
400    /* This ioctl ignores the type field. */
401
402    freq_khz = rda5807_get_frequency(radio);
403    if (freq_khz < 0)
404        return freq_khz;
405
406    a->frequency = (__u32)freq_khz * 16;
407    return 0;
408}
409
410static int rda5807_vidioc_s_frequency(struct file *file, void *fh,
411                      struct v4l2_frequency *a)
412{
413    struct rda5807_driver *radio = video_drvdata(file);
414
415    if (a->tuner != 0)
416        return -EINVAL;
417    if (a->type != V4L2_TUNER_RADIO)
418        return -EINVAL;
419
420    return rda5807_set_frequency(radio, (a->frequency * 625) / 10000);
421}
422
423static int rda5807_vidioc_s_hw_freq_seek(struct file *file, void *fh,
424                     struct v4l2_hw_freq_seek *a)
425{
426    struct rda5807_driver *radio = video_drvdata(file);
427
428    if (a->tuner != 0)
429        return -EINVAL;
430    if (a->type != V4L2_TUNER_RADIO)
431        return -EINVAL;
432
433    return rda5807_seek_frequency(radio, a->seek_upward, a->wrap_around);
434}
435
436static const struct v4l2_ioctl_ops rda5807_ioctl_ops = {
437    .vidioc_querycap = rda5807_vidioc_querycap,
438    .vidioc_g_audio = rda5807_vidioc_g_audio,
439    .vidioc_g_tuner = rda5807_vidioc_g_tuner,
440    .vidioc_g_frequency = rda5807_vidioc_g_frequency,
441    .vidioc_s_frequency = rda5807_vidioc_s_frequency,
442    .vidioc_s_hw_freq_seek = rda5807_vidioc_s_hw_freq_seek,
443};
444
445static int __devinit rda5807_i2c_probe(struct i2c_client *client,
446                       const struct i2c_device_id *id)
447{
448    struct rda5807_platform_data *pdata = client->dev.platform_data;
449    struct rda5807_driver *radio;
450    int err;
451    u16 val;
452
453    if (!pdata) {
454        dev_err(&client->dev, "Platform data missing\n");
455        return -EINVAL;
456    }
457
458    err = rda5807_i2c_read(client, RDA5807_REG_CHIPID);
459    if (err < 0) {
460        dev_err(&client->dev, "Failed to read chip ID (%d)\n", err);
461        return err;
462    }
463    val = err;
464    if ((val & 0xFF00) != 0x5800) {
465        dev_err(&client->dev, "Chip ID mismatch: "
466                      "expected 58xx, got %04X\n", val);
467        return -ENODEV;
468    }
469    dev_info(&client->dev, "Found FM radio receiver\n");
470
471    // TODO: Resetting the chip would be good.
472
473    radio = kzalloc(sizeof(*radio), GFP_KERNEL);
474    if (!radio) {
475        dev_err(&client->dev, "Failed to allocate driver data\n");
476        return -ENOMEM;
477    }
478
479    radio->i2c_client = client;
480
481    /* Initialize controls. */
482    v4l2_ctrl_handler_init(&radio->ctrl_handler, 3);
483    v4l2_ctrl_new_std(&radio->ctrl_handler, &rda5807_ctrl_ops,
484              V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
485    v4l2_ctrl_new_std(&radio->ctrl_handler, &rda5807_ctrl_ops,
486              V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 8);
487    /* TODO: V4L2_CID_TUNE_PREEMPHASIS is based on V4L2_CID_FM_TX_CLASS_BASE
488     * which suggests it is a transmit control rather than a receive
489     * control. The register bit we change is called "de-emphasis",
490     * but there is no de-emphasis control in V4L2.
491     */
492    v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &rda5807_ctrl_ops,
493                   V4L2_CID_TUNE_PREEMPHASIS,
494                   V4L2_PREEMPHASIS_75_uS,
495                   BIT(V4L2_PREEMPHASIS_DISABLED),
496                   V4L2_PREEMPHASIS_50_uS);
497    err = radio->ctrl_handler.error;
498    if (err) {
499        dev_err(&client->dev, "Failed to init controls handler (%d)\n",
500            err);
501        goto err_ctrl_free;
502    }
503
504    radio->video_dev = (struct video_device) {
505        .name = "RDA5807 FM receiver",
506        .flags = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG,
507        .ctrl_handler = &radio->ctrl_handler,
508        .fops = &rda5807_fops,
509        .ioctl_ops = &rda5807_ioctl_ops,
510        .release = video_device_release_empty,
511        //.lock = &radio->lock,
512    };
513    i2c_set_clientdata(client, radio);
514    video_set_drvdata(&radio->video_dev, radio);
515
516    err = video_register_device(&radio->video_dev, VFL_TYPE_RADIO, -1);
517    if (err < 0) {
518        dev_err(&client->dev, "Failed to register video device (%d)\n",
519                      err);
520        goto err_ctrl_free;
521    }
522
523    /* Configure chip inputs. */
524    err = rda5807_update_reg(radio, RDA5807_REG_INTM_THRESH_VOL,
525                 0xF << 4, (pdata->input_flags & 0xF) << 4);
526    if (err < 0) {
527        dev_warn(&client->dev, "Failed to configure inputs (%d)\n",
528                       err);
529    }
530    /* Configure chip outputs. */
531    val = 0;
532    if (pdata->output_flags & RDA5807_OUTPUT_AUDIO_I2S) {
533        val |= BIT(6);
534    } else if (pdata->output_flags & RDA5807_OUTPUT_STEREO_INDICATOR) {
535        val |= BIT(4);
536    }
537    err = rda5807_update_reg(radio, RDA5807_REG_IOCFG, 0x003F, val);
538    if (err < 0) {
539        dev_warn(&client->dev, "Failed to configure outputs (%d)\n",
540                       err);
541    }
542    val = 0;
543    if (pdata->output_flags & RDA5807_OUTPUT_AUDIO_ANALOG) {
544        val |= BIT(15);
545    }
546    err = rda5807_update_reg(radio, RDA5807_REG_CTRL, BIT(15), val);
547    if (err < 0) {
548        dev_warn(&client->dev, "Failed to configure outputs (%d)\n",
549                       err);
550    }
551
552    err = v4l2_ctrl_handler_setup(&radio->ctrl_handler);
553    if (err < 0) {
554        dev_err(&client->dev, "Failed to set default control values"
555                      " (%d)\n", err);
556        goto err_video_unreg;
557    }
558
559    return 0;
560
561err_video_unreg:
562    video_unregister_device(&radio->video_dev);
563
564err_ctrl_free:
565    v4l2_ctrl_handler_free(&radio->ctrl_handler);
566
567/*err_radio_rel:*/
568    video_device_release_empty(&radio->video_dev);
569    kfree(radio);
570
571    return err;
572}
573
574static int __devexit rda5807_i2c_remove(struct i2c_client *client)
575{
576    struct rda5807_driver *radio = i2c_get_clientdata(client);
577
578    video_unregister_device(&radio->video_dev);
579    v4l2_ctrl_handler_free(&radio->ctrl_handler);
580    video_device_release_empty(&radio->video_dev);
581    kfree(radio);
582
583    return 0;
584}
585
586#ifdef CONFIG_PM
587
588static int rda5807_suspend(struct device *dev)
589{
590    struct i2c_client *client = to_i2c_client(dev);
591    struct rda5807_driver *radio = i2c_get_clientdata(client);
592
593    return rda5807_set_enable(radio, 0);
594}
595
596static int rda5807_resume(struct device *dev)
597{
598    struct i2c_client *client = to_i2c_client(dev);
599    struct rda5807_driver *radio = i2c_get_clientdata(client);
600    struct v4l2_ctrl *mute_ctrl = v4l2_ctrl_find(&radio->ctrl_handler,
601                             V4L2_CID_AUDIO_MUTE);
602    s32 mute_val = v4l2_ctrl_g_ctrl(mute_ctrl);
603    int enabled = !mute_val;
604
605    if (enabled)
606        return rda5807_set_enable(radio, enabled);
607    else
608        return 0;
609}
610
611static SIMPLE_DEV_PM_OPS(rda5807_pm_ops, rda5807_suspend, rda5807_resume);
612#define RDA5807_PM_OPS (&rda5807_pm_ops)
613
614#else
615
616#define RDA5807_PM_OPS NULL
617
618#endif
619
620static const struct i2c_device_id rda5807_id[] = {
621    { "radio-rda5807", 0 },
622    { }
623};
624MODULE_DEVICE_TABLE(i2c, rda5807_id);
625
626static struct i2c_driver rda5807_i2c_driver = {
627    .probe = rda5807_i2c_probe,
628    .remove = __devexit_p(rda5807_i2c_remove),
629    .id_table = rda5807_id,
630    .driver = {
631        .name = "radio-rda5807",
632        .owner = THIS_MODULE,
633        .pm = RDA5807_PM_OPS,
634    },
635};
636
637static int __init rda5807_init(void)
638{
639    return i2c_add_driver(&rda5807_i2c_driver);
640}
641
642static void __exit rda5807_exit(void)
643{
644    i2c_del_driver(&rda5807_i2c_driver);
645}
646
647module_init(rda5807_init);
648module_exit(rda5807_exit);
649
650MODULE_AUTHOR("Maarten ter Huurne <maarten@treewalker.org>");
651MODULE_DESCRIPTION("RDA5807 FM tuner driver");
652MODULE_LICENSE("GPL");
include/media/radio-rda5807.h
1/*
2 * radio-rda5807.h - Board related data for the RDA5807 FM tuner chip driver
3 *
4 * Copyright (c) 2011 Maarten ter Huurne <maarten@treewalker.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#ifndef RADIO_RDA5807_H
21#define RADIO_RDA5807_H
22
23/* The driver uses random access I/O to the registers via I2C address 0x11. */
24#define RDA5807_I2C_ADDR 0x11
25
26/* Working current: 1.8, 2.1, 2.5 or 3.0 mA. */
27#define RDA5807_INPUT_LNA_WC_18 (0 << 0)
28#define RDA5807_INPUT_LNA_WC_21 (1 << 0)
29#define RDA5807_INPUT_LNA_WC_25 (2 << 0)
30#define RDA5807_INPUT_LNA_WC_30 (3 << 0)
31/* Use antenna signal connected to LNAN and/or LNAP pin? */
32#define RDA5807_LNA_PORT_N (1 << 2)
33#define RDA5807_LNA_PORT_P (1 << 3)
34
35/* Ouput analog audio on LOUT+ROUT pins */
36#define RDA5807_OUTPUT_AUDIO_ANALOG (1 << 0)
37/* Output digital audio using I2S on GPIO1-3 pins */
38#define RDA5807_OUTPUT_AUDIO_I2S (1 << 1)
39/* Output stereo indicator signal on GPIO3 pin */
40#define RDA5807_OUTPUT_STEREO_INDICATOR (1 << 2)
41
42struct rda5807_platform_data {
43    u8 input_flags;
44    u8 output_flags;
45};
46
47#endif /* RADIO_RDA5807_H */

Archive Download the corresponding diff file



interactive