linux/drivers/media/video/cs53l32a.c
<<
>>
Prefs
   1/*
   2 * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver.
   3 * Copyright (C) 2005  Martin Vaughan
   4 *
   5 * Audio source switching for Adaptec AVC-2410 added by Trev Jackson
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22
  23#include <linux/module.h>
  24#include <linux/types.h>
  25#include <linux/ioctl.h>
  26#include <asm/uaccess.h>
  27#include <linux/i2c.h>
  28#include <linux/i2c-id.h>
  29#include <linux/videodev2.h>
  30#include <media/v4l2-device.h>
  31#include <media/v4l2-chip-ident.h>
  32#include <media/v4l2-i2c-drv.h>
  33
  34MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
  35MODULE_AUTHOR("Martin Vaughan");
  36MODULE_LICENSE("GPL");
  37
  38static int debug;
  39
  40module_param(debug, bool, 0644);
  41
  42MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
  43
  44
  45/* ----------------------------------------------------------------------- */
  46
  47static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
  48{
  49        struct i2c_client *client = v4l2_get_subdevdata(sd);
  50
  51        return i2c_smbus_write_byte_data(client, reg, value);
  52}
  53
  54static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
  55{
  56        struct i2c_client *client = v4l2_get_subdevdata(sd);
  57
  58        return i2c_smbus_read_byte_data(client, reg);
  59}
  60
  61static int cs53l32a_s_routing(struct v4l2_subdev *sd,
  62                              u32 input, u32 output, u32 config)
  63{
  64        /* There are 2 physical inputs, but the second input can be
  65           placed in two modes, the first mode bypasses the PGA (gain),
  66           the second goes through the PGA. Hence there are three
  67           possible inputs to choose from. */
  68        if (input > 2) {
  69                v4l2_err(sd, "Invalid input %d.\n", input);
  70                return -EINVAL;
  71        }
  72        cs53l32a_write(sd, 0x01, 0x01 + (input << 4));
  73        return 0;
  74}
  75
  76static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  77{
  78        if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
  79                ctrl->value = (cs53l32a_read(sd, 0x03) & 0xc0) != 0;
  80                return 0;
  81        }
  82        if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
  83                return -EINVAL;
  84        ctrl->value = (s8)cs53l32a_read(sd, 0x04);
  85        return 0;
  86}
  87
  88static int cs53l32a_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  89{
  90        if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
  91                cs53l32a_write(sd, 0x03, ctrl->value ? 0xf0 : 0x30);
  92                return 0;
  93        }
  94        if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
  95                return -EINVAL;
  96        if (ctrl->value > 12 || ctrl->value < -96)
  97                return -EINVAL;
  98        cs53l32a_write(sd, 0x04, (u8) ctrl->value);
  99        cs53l32a_write(sd, 0x05, (u8) ctrl->value);
 100        return 0;
 101}
 102
 103static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 104{
 105        struct i2c_client *client = v4l2_get_subdevdata(sd);
 106
 107        return v4l2_chip_ident_i2c_client(client,
 108                        chip, V4L2_IDENT_CS53l32A, 0);
 109}
 110
 111static int cs53l32a_log_status(struct v4l2_subdev *sd)
 112{
 113        u8 v = cs53l32a_read(sd, 0x01);
 114        u8 m = cs53l32a_read(sd, 0x03);
 115        s8 vol = cs53l32a_read(sd, 0x04);
 116
 117        v4l2_info(sd, "Input:  %d%s\n", (v >> 4) & 3,
 118                        (m & 0xC0) ? " (muted)" : "");
 119        v4l2_info(sd, "Volume: %d dB\n", vol);
 120        return 0;
 121}
 122
 123/* ----------------------------------------------------------------------- */
 124
 125static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
 126        .log_status = cs53l32a_log_status,
 127        .g_chip_ident = cs53l32a_g_chip_ident,
 128        .g_ctrl = cs53l32a_g_ctrl,
 129        .s_ctrl = cs53l32a_s_ctrl,
 130};
 131
 132static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
 133        .s_routing = cs53l32a_s_routing,
 134};
 135
 136static const struct v4l2_subdev_ops cs53l32a_ops = {
 137        .core = &cs53l32a_core_ops,
 138        .audio = &cs53l32a_audio_ops,
 139};
 140
 141/* ----------------------------------------------------------------------- */
 142
 143/* i2c implementation */
 144
 145/*
 146 * Generic i2c probe
 147 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 148 */
 149
 150static int cs53l32a_probe(struct i2c_client *client,
 151                          const struct i2c_device_id *id)
 152{
 153        struct v4l2_subdev *sd;
 154        int i;
 155
 156        /* Check if the adapter supports the needed features */
 157        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 158                return -EIO;
 159
 160        if (!id)
 161                strlcpy(client->name, "cs53l32a", sizeof(client->name));
 162
 163        v4l_info(client, "chip found @ 0x%x (%s)\n",
 164                        client->addr << 1, client->adapter->name);
 165
 166        sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
 167        if (sd == NULL)
 168                return -ENOMEM;
 169        v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
 170
 171        for (i = 1; i <= 7; i++) {
 172                u8 v = cs53l32a_read(sd, i);
 173
 174                v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
 175        }
 176
 177        /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
 178
 179        cs53l32a_write(sd, 0x01, (u8) 0x21);
 180        cs53l32a_write(sd, 0x02, (u8) 0x29);
 181        cs53l32a_write(sd, 0x03, (u8) 0x30);
 182        cs53l32a_write(sd, 0x04, (u8) 0x00);
 183        cs53l32a_write(sd, 0x05, (u8) 0x00);
 184        cs53l32a_write(sd, 0x06, (u8) 0x00);
 185        cs53l32a_write(sd, 0x07, (u8) 0x00);
 186
 187        /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
 188
 189        for (i = 1; i <= 7; i++) {
 190                u8 v = cs53l32a_read(sd, i);
 191
 192                v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
 193        }
 194        return 0;
 195}
 196
 197static int cs53l32a_remove(struct i2c_client *client)
 198{
 199        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 200
 201        v4l2_device_unregister_subdev(sd);
 202        kfree(sd);
 203        return 0;
 204}
 205
 206static const struct i2c_device_id cs53l32a_id[] = {
 207        { "cs53l32a", 0 },
 208        { }
 209};
 210MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
 211
 212static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 213        .name = "cs53l32a",
 214        .remove = cs53l32a_remove,
 215        .probe = cs53l32a_probe,
 216        .id_table = cs53l32a_id,
 217};
 218