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/slab.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/videodev2.h>
  31#include <media/v4l2-device.h>
  32#include <media/v4l2-chip-ident.h>
  33#include <media/v4l2-i2c-drv.h>
  34
  35MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
  36MODULE_AUTHOR("Martin Vaughan");
  37MODULE_LICENSE("GPL");
  38
  39static int debug;
  40
  41module_param(debug, bool, 0644);
  42
  43MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
  44
  45
  46/* ----------------------------------------------------------------------- */
  47
  48static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
  49{
  50        struct i2c_client *client = v4l2_get_subdevdata(sd);
  51
  52        return i2c_smbus_write_byte_data(client, reg, value);
  53}
  54
  55static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
  56{
  57        struct i2c_client *client = v4l2_get_subdevdata(sd);
  58
  59        return i2c_smbus_read_byte_data(client, reg);
  60}
  61
  62static int cs53l32a_s_routing(struct v4l2_subdev *sd,
  63                              u32 input, u32 output, u32 config)
  64{
  65        /* There are 2 physical inputs, but the second input can be
  66           placed in two modes, the first mode bypasses the PGA (gain),
  67           the second goes through the PGA. Hence there are three
  68           possible inputs to choose from. */
  69        if (input > 2) {
  70                v4l2_err(sd, "Invalid input %d.\n", input);
  71                return -EINVAL;
  72        }
  73        cs53l32a_write(sd, 0x01, 0x01 + (input << 4));
  74        return 0;
  75}
  76
  77static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  78{
  79        if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
  80                ctrl->value = (cs53l32a_read(sd, 0x03) & 0xc0) != 0;
  81                return 0;
  82        }
  83        if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
  84                return -EINVAL;
  85        ctrl->value = (s8)cs53l32a_read(sd, 0x04);
  86        return 0;
  87}
  88
  89static int cs53l32a_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  90{
  91        if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
  92                cs53l32a_write(sd, 0x03, ctrl->value ? 0xf0 : 0x30);
  93                return 0;
  94        }
  95        if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
  96                return -EINVAL;
  97        if (ctrl->value > 12 || ctrl->value < -96)
  98                return -EINVAL;
  99        cs53l32a_write(sd, 0x04, (u8) ctrl->value);
 100        cs53l32a_write(sd, 0x05, (u8) ctrl->value);
 101        return 0;
 102}
 103
 104static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 105{
 106        struct i2c_client *client = v4l2_get_subdevdata(sd);
 107
 108        return v4l2_chip_ident_i2c_client(client,
 109                        chip, V4L2_IDENT_CS53l32A, 0);
 110}
 111
 112static int cs53l32a_log_status(struct v4l2_subdev *sd)
 113{
 114        u8 v = cs53l32a_read(sd, 0x01);
 115        u8 m = cs53l32a_read(sd, 0x03);
 116        s8 vol = cs53l32a_read(sd, 0x04);
 117
 118        v4l2_info(sd, "Input:  %d%s\n", (v >> 4) & 3,
 119                        (m & 0xC0) ? " (muted)" : "");
 120        v4l2_info(sd, "Volume: %d dB\n", vol);
 121        return 0;
 122}
 123
 124/* ----------------------------------------------------------------------- */
 125
 126static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
 127        .log_status = cs53l32a_log_status,
 128        .g_chip_ident = cs53l32a_g_chip_ident,
 129        .g_ctrl = cs53l32a_g_ctrl,
 130        .s_ctrl = cs53l32a_s_ctrl,
 131};
 132
 133static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
 134        .s_routing = cs53l32a_s_routing,
 135};
 136
 137static const struct v4l2_subdev_ops cs53l32a_ops = {
 138        .core = &cs53l32a_core_ops,
 139        .audio = &cs53l32a_audio_ops,
 140};
 141
 142/* ----------------------------------------------------------------------- */
 143
 144/* i2c implementation */
 145
 146/*
 147 * Generic i2c probe
 148 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 149 */
 150
 151static int cs53l32a_probe(struct i2c_client *client,
 152                          const struct i2c_device_id *id)
 153{
 154        struct v4l2_subdev *sd;
 155        int i;
 156
 157        /* Check if the adapter supports the needed features */
 158        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 159                return -EIO;
 160
 161        if (!id)
 162                strlcpy(client->name, "cs53l32a", sizeof(client->name));
 163
 164        v4l_info(client, "chip found @ 0x%x (%s)\n",
 165                        client->addr << 1, client->adapter->name);
 166
 167        sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
 168        if (sd == NULL)
 169                return -ENOMEM;
 170        v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
 171
 172        for (i = 1; i <= 7; i++) {
 173                u8 v = cs53l32a_read(sd, i);
 174
 175                v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
 176        }
 177
 178        /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
 179
 180        cs53l32a_write(sd, 0x01, (u8) 0x21);
 181        cs53l32a_write(sd, 0x02, (u8) 0x29);
 182        cs53l32a_write(sd, 0x03, (u8) 0x30);
 183        cs53l32a_write(sd, 0x04, (u8) 0x00);
 184        cs53l32a_write(sd, 0x05, (u8) 0x00);
 185        cs53l32a_write(sd, 0x06, (u8) 0x00);
 186        cs53l32a_write(sd, 0x07, (u8) 0x00);
 187
 188        /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
 189
 190        for (i = 1; i <= 7; i++) {
 191                u8 v = cs53l32a_read(sd, i);
 192
 193                v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
 194        }
 195        return 0;
 196}
 197
 198static int cs53l32a_remove(struct i2c_client *client)
 199{
 200        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 201
 202        v4l2_device_unregister_subdev(sd);
 203        kfree(sd);
 204        return 0;
 205}
 206
 207static const struct i2c_device_id cs53l32a_id[] = {
 208        { "cs53l32a", 0 },
 209        { }
 210};
 211MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
 212
 213static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 214        .name = "cs53l32a",
 215        .remove = cs53l32a_remove,
 216        .probe = cs53l32a_probe,
 217        .id_table = cs53l32a_id,
 218};
 219