linux/drivers/media/video/vp27smpx.c
<<
>>
Prefs
   1/*
   2 * vp27smpx - driver version 0.0.1
   3 *
   4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
   5 *
   6 * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com>
   7 * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22 */
  23
  24#include <linux/module.h>
  25#include <linux/types.h>
  26#include <linux/ioctl.h>
  27#include <asm/uaccess.h>
  28#include <linux/i2c.h>
  29#include <linux/i2c-id.h>
  30#include <linux/videodev.h>
  31#include <media/v4l2-common.h>
  32#include <media/v4l2-chip-ident.h>
  33
  34MODULE_DESCRIPTION("vp27smpx driver");
  35MODULE_AUTHOR("Hans Verkuil");
  36MODULE_LICENSE("GPL");
  37
  38static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
  39
  40
  41I2C_CLIENT_INSMOD;
  42
  43/* ----------------------------------------------------------------------- */
  44
  45struct vp27smpx_state {
  46        int radio;
  47        u32 audmode;
  48};
  49
  50static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
  51{
  52        struct vp27smpx_state *state = i2c_get_clientdata(client);
  53        u8 data[3] = { 0x00, 0x00, 0x04 };
  54
  55        switch (audmode) {
  56                case V4L2_TUNER_MODE_MONO:
  57                case V4L2_TUNER_MODE_LANG1:
  58                        break;
  59                case V4L2_TUNER_MODE_STEREO:
  60                case V4L2_TUNER_MODE_LANG1_LANG2:
  61                        data[1] = 0x01;
  62                        break;
  63                case V4L2_TUNER_MODE_LANG2:
  64                        data[1] = 0x02;
  65                        break;
  66        }
  67
  68        if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
  69                v4l_err(client, "%s: I/O error setting audmode\n", client->name);
  70        }
  71        else {
  72                state->audmode = audmode;
  73        }
  74}
  75
  76static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
  77                          void *arg)
  78{
  79        struct vp27smpx_state *state = i2c_get_clientdata(client);
  80        struct v4l2_tuner *vt = arg;
  81
  82        switch (cmd) {
  83        case AUDC_SET_RADIO:
  84                state->radio = 1;
  85                break;
  86
  87        case VIDIOC_S_STD:
  88                state->radio = 0;
  89                break;
  90
  91        case VIDIOC_S_TUNER:
  92                if (!state->radio)
  93                        vp27smpx_set_audmode(client, vt->audmode);
  94                break;
  95
  96        case VIDIOC_G_TUNER:
  97                if (state->radio)
  98                        break;
  99                vt->audmode = state->audmode;
 100                vt->capability = V4L2_TUNER_CAP_STEREO |
 101                        V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
 102                vt->rxsubchans = V4L2_TUNER_SUB_MONO;
 103                break;
 104
 105        case VIDIOC_G_CHIP_IDENT:
 106                return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
 107
 108        case VIDIOC_LOG_STATUS:
 109                v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
 110                                state->radio ? " (Radio)" : "");
 111                break;
 112
 113        default:
 114                return -EINVAL;
 115        }
 116        return 0;
 117}
 118
 119/* ----------------------------------------------------------------------- */
 120
 121/* i2c implementation */
 122
 123/*
 124 * Generic i2c probe
 125 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 126 */
 127
 128static struct i2c_driver i2c_driver;
 129
 130static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
 131{
 132        struct i2c_client *client;
 133        struct vp27smpx_state *state;
 134
 135        /* Check if the adapter supports the needed features */
 136        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 137                return 0;
 138
 139        client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
 140        if (client == 0)
 141                return -ENOMEM;
 142
 143        client->addr = address;
 144        client->adapter = adapter;
 145        client->driver = &i2c_driver;
 146        snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
 147
 148        v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
 149
 150        state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
 151        if (state == NULL) {
 152                kfree(client);
 153                return -ENOMEM;
 154        }
 155        state->audmode = V4L2_TUNER_MODE_STEREO;
 156        i2c_set_clientdata(client, state);
 157
 158        /* initialize vp27smpx */
 159        vp27smpx_set_audmode(client, state->audmode);
 160        i2c_attach_client(client);
 161
 162        return 0;
 163}
 164
 165static int vp27smpx_probe(struct i2c_adapter *adapter)
 166{
 167        if (adapter->class & I2C_CLASS_TV_ANALOG)
 168                return i2c_probe(adapter, &addr_data, vp27smpx_attach);
 169        return 0;
 170}
 171
 172static int vp27smpx_detach(struct i2c_client *client)
 173{
 174        struct vp27smpx_state *state = i2c_get_clientdata(client);
 175        int err;
 176
 177        err = i2c_detach_client(client);
 178        if (err) {
 179                return err;
 180        }
 181        kfree(state);
 182        kfree(client);
 183
 184        return 0;
 185}
 186
 187/* ----------------------------------------------------------------------- */
 188
 189/* i2c implementation */
 190static struct i2c_driver i2c_driver = {
 191        .driver = {
 192                .name = "vp27smpx",
 193        },
 194        .id             = I2C_DRIVERID_VP27SMPX,
 195        .attach_adapter = vp27smpx_probe,
 196        .detach_client  = vp27smpx_detach,
 197        .command        = vp27smpx_command,
 198};
 199
 200
 201static int __init vp27smpx_init_module(void)
 202{
 203        return i2c_add_driver(&i2c_driver);
 204}
 205
 206static void __exit vp27smpx_cleanup_module(void)
 207{
 208        i2c_del_driver(&i2c_driver);
 209}
 210
 211module_init(vp27smpx_init_module);
 212module_exit(vp27smpx_cleanup_module);
 213