1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
65
66
67
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
144
145
146
147
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
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
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
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