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