linux/drivers/media/video/cs5345.c
<<
>>
Prefs
   1/*
   2 * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC
   3 * Copyright (C) 2007 Hans Verkuil
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   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
  21#include <linux/module.h>
  22#include <linux/kernel.h>
  23#include <linux/i2c.h>
  24#include <linux/videodev2.h>
  25#include <media/v4l2-device.h>
  26#include <media/v4l2-chip-ident.h>
  27#include <media/v4l2-i2c-drv.h>
  28
  29MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
  30MODULE_AUTHOR("Hans Verkuil");
  31MODULE_LICENSE("GPL");
  32
  33static int debug;
  34
  35module_param(debug, bool, 0644);
  36
  37MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
  38
  39
  40/* ----------------------------------------------------------------------- */
  41
  42static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value)
  43{
  44        struct i2c_client *client = v4l2_get_subdevdata(sd);
  45
  46        return i2c_smbus_write_byte_data(client, reg, value);
  47}
  48
  49static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
  50{
  51        struct i2c_client *client = v4l2_get_subdevdata(sd);
  52
  53        return i2c_smbus_read_byte_data(client, reg);
  54}
  55
  56static int cs5345_s_routing(struct v4l2_subdev *sd,
  57                            u32 input, u32 output, u32 config)
  58{
  59        if ((input & 0xf) > 6) {
  60                v4l2_err(sd, "Invalid input %d.\n", input);
  61                return -EINVAL;
  62        }
  63        cs5345_write(sd, 0x09, input & 0xf);
  64        cs5345_write(sd, 0x05, input & 0xf0);
  65        return 0;
  66}
  67
  68static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  69{
  70        if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
  71                ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0;
  72                return 0;
  73        }
  74        if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
  75                return -EINVAL;
  76        ctrl->value = cs5345_read(sd, 0x07) & 0x3f;
  77        if (ctrl->value >= 32)
  78                ctrl->value = ctrl->value - 64;
  79        return 0;
  80}
  81
  82static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  83{
  84        if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
  85                cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0);
  86                return 0;
  87        }
  88        if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
  89                return -EINVAL;
  90        if (ctrl->value > 24 || ctrl->value < -24)
  91                return -EINVAL;
  92        cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f);
  93        cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f);
  94        return 0;
  95}
  96
  97#ifdef CONFIG_VIDEO_ADV_DEBUG
  98static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
  99{
 100        struct i2c_client *client = v4l2_get_subdevdata(sd);
 101
 102        if (!v4l2_chip_match_i2c_client(client, &reg->match))
 103                return -EINVAL;
 104        if (!capable(CAP_SYS_ADMIN))
 105                return -EPERM;
 106        reg->size = 1;
 107        reg->val = cs5345_read(sd, reg->reg & 0x1f);
 108        return 0;
 109}
 110
 111static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 112{
 113        struct i2c_client *client = v4l2_get_subdevdata(sd);
 114
 115        if (!v4l2_chip_match_i2c_client(client, &reg->match))
 116                return -EINVAL;
 117        if (!capable(CAP_SYS_ADMIN))
 118                return -EPERM;
 119        cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
 120        return 0;
 121}
 122#endif
 123
 124static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 125{
 126        struct i2c_client *client = v4l2_get_subdevdata(sd);
 127
 128        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
 129}
 130
 131static int cs5345_log_status(struct v4l2_subdev *sd)
 132{
 133        u8 v = cs5345_read(sd, 0x09) & 7;
 134        u8 m = cs5345_read(sd, 0x04);
 135        int vol = cs5345_read(sd, 0x08) & 0x3f;
 136
 137        v4l2_info(sd, "Input:  %d%s\n", v,
 138                        (m & 0x80) ? " (muted)" : "");
 139        if (vol >= 32)
 140                vol = vol - 64;
 141        v4l2_info(sd, "Volume: %d dB\n", vol);
 142        return 0;
 143}
 144
 145/* ----------------------------------------------------------------------- */
 146
 147static const struct v4l2_subdev_core_ops cs5345_core_ops = {
 148        .log_status = cs5345_log_status,
 149        .g_chip_ident = cs5345_g_chip_ident,
 150        .g_ctrl = cs5345_g_ctrl,
 151        .s_ctrl = cs5345_s_ctrl,
 152#ifdef CONFIG_VIDEO_ADV_DEBUG
 153        .g_register = cs5345_g_register,
 154        .s_register = cs5345_s_register,
 155#endif
 156};
 157
 158static const struct v4l2_subdev_audio_ops cs5345_audio_ops = {
 159        .s_routing = cs5345_s_routing,
 160};
 161
 162static const struct v4l2_subdev_ops cs5345_ops = {
 163        .core = &cs5345_core_ops,
 164        .audio = &cs5345_audio_ops,
 165};
 166
 167/* ----------------------------------------------------------------------- */
 168
 169static int cs5345_probe(struct i2c_client *client,
 170                        const struct i2c_device_id *id)
 171{
 172        struct v4l2_subdev *sd;
 173
 174        /* Check if the adapter supports the needed features */
 175        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 176                return -EIO;
 177
 178        v4l_info(client, "chip found @ 0x%x (%s)\n",
 179                        client->addr << 1, client->adapter->name);
 180
 181        sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
 182        if (sd == NULL)
 183                return -ENOMEM;
 184        v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
 185
 186        cs5345_write(sd, 0x02, 0x00);
 187        cs5345_write(sd, 0x04, 0x01);
 188        cs5345_write(sd, 0x09, 0x01);
 189        return 0;
 190}
 191
 192/* ----------------------------------------------------------------------- */
 193
 194static int cs5345_remove(struct i2c_client *client)
 195{
 196        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 197
 198        v4l2_device_unregister_subdev(sd);
 199        kfree(sd);
 200        return 0;
 201}
 202
 203/* ----------------------------------------------------------------------- */
 204
 205static const struct i2c_device_id cs5345_id[] = {
 206        { "cs5345", 0 },
 207        { }
 208};
 209MODULE_DEVICE_TABLE(i2c, cs5345_id);
 210
 211static struct v4l2_i2c_driver_data v4l2_i2c_data = {
 212        .name = "cs5345",
 213        .probe = cs5345_probe,
 214        .remove = cs5345_remove,
 215        .id_table = cs5345_id,
 216};
 217