1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include <linux/module.h>
29#include <linux/types.h>
30#include <linux/ioctl.h>
31#include <asm/uaccess.h>
32#include <linux/i2c.h>
33#include <linux/i2c-id.h>
34#include <linux/videodev2.h>
35#include <media/v4l2-device.h>
36#include <media/v4l2-chip-ident.h>
37#include <media/v4l2-i2c-drv.h>
38
39MODULE_DESCRIPTION("wm8775 driver");
40MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
41MODULE_LICENSE("GPL");
42
43
44
45
46
47enum {
48 R7 = 7, R11 = 11,
49 R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
50 TOT_REGS
51};
52
53struct wm8775_state {
54 struct v4l2_subdev sd;
55 u8 input;
56 u8 muted;
57};
58
59static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
60{
61 return container_of(sd, struct wm8775_state, sd);
62}
63
64static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
65{
66 struct i2c_client *client = v4l2_get_subdevdata(sd);
67 int i;
68
69 if (reg < 0 || reg >= TOT_REGS) {
70 v4l2_err(sd, "Invalid register R%d\n", reg);
71 return -1;
72 }
73
74 for (i = 0; i < 3; i++)
75 if (i2c_smbus_write_byte_data(client,
76 (reg << 1) | (val >> 8), val & 0xff) == 0)
77 return 0;
78 v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
79 return -1;
80}
81
82static int wm8775_s_routing(struct v4l2_subdev *sd,
83 u32 input, u32 output, u32 config)
84{
85 struct wm8775_state *state = to_state(sd);
86
87
88
89
90
91
92 if (input > 15) {
93 v4l2_err(sd, "Invalid input %d.\n", input);
94 return -EINVAL;
95 }
96 state->input = input;
97 if (state->muted)
98 return 0;
99 wm8775_write(sd, R21, 0x0c0);
100 wm8775_write(sd, R14, 0x1d4);
101 wm8775_write(sd, R15, 0x1d4);
102 wm8775_write(sd, R21, 0x100 + state->input);
103 return 0;
104}
105
106static int wm8775_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
107{
108 struct wm8775_state *state = to_state(sd);
109
110 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
111 return -EINVAL;
112 ctrl->value = state->muted;
113 return 0;
114}
115
116static int wm8775_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
117{
118 struct wm8775_state *state = to_state(sd);
119
120 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
121 return -EINVAL;
122 state->muted = ctrl->value;
123 wm8775_write(sd, R21, 0x0c0);
124 wm8775_write(sd, R14, 0x1d4);
125 wm8775_write(sd, R15, 0x1d4);
126 if (!state->muted)
127 wm8775_write(sd, R21, 0x100 + state->input);
128 return 0;
129}
130
131static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
132{
133 struct i2c_client *client = v4l2_get_subdevdata(sd);
134
135 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
136}
137
138static int wm8775_log_status(struct v4l2_subdev *sd)
139{
140 struct wm8775_state *state = to_state(sd);
141
142 v4l2_info(sd, "Input: %d%s\n", state->input,
143 state->muted ? " (muted)" : "");
144 return 0;
145}
146
147static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
148{
149 struct wm8775_state *state = to_state(sd);
150
151
152
153
154
155 wm8775_write(sd, R21, 0x0c0);
156 wm8775_write(sd, R14, 0x1d4);
157 wm8775_write(sd, R15, 0x1d4);
158 wm8775_write(sd, R21, 0x100 + state->input);
159 return 0;
160}
161
162
163
164static const struct v4l2_subdev_core_ops wm8775_core_ops = {
165 .log_status = wm8775_log_status,
166 .g_chip_ident = wm8775_g_chip_ident,
167 .g_ctrl = wm8775_g_ctrl,
168 .s_ctrl = wm8775_s_ctrl,
169};
170
171static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
172 .s_frequency = wm8775_s_frequency,
173};
174
175static const struct v4l2_subdev_audio_ops wm8775_audio_ops = {
176 .s_routing = wm8775_s_routing,
177};
178
179static const struct v4l2_subdev_ops wm8775_ops = {
180 .core = &wm8775_core_ops,
181 .tuner = &wm8775_tuner_ops,
182 .audio = &wm8775_audio_ops,
183};
184
185
186
187
188
189
190
191
192
193
194static int wm8775_probe(struct i2c_client *client,
195 const struct i2c_device_id *id)
196{
197 struct wm8775_state *state;
198 struct v4l2_subdev *sd;
199
200
201 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
202 return -EIO;
203
204 v4l_info(client, "chip found @ 0x%02x (%s)\n",
205 client->addr << 1, client->adapter->name);
206
207 state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
208 if (state == NULL)
209 return -ENOMEM;
210 sd = &state->sd;
211 v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
212 state->input = 2;
213 state->muted = 0;
214
215
216
217
218 wm8775_write(sd, R23, 0x000);
219
220 wm8775_write(sd, R7, 0x000);
221
222 wm8775_write(sd, R11, 0x021);
223
224 wm8775_write(sd, R12, 0x102);
225
226 wm8775_write(sd, R13, 0x000);
227
228 wm8775_write(sd, R14, 0x1d4);
229
230 wm8775_write(sd, R15, 0x1d4);
231
232 wm8775_write(sd, R16, 0x1bf);
233
234
235 wm8775_write(sd, R17, 0x185);
236
237 wm8775_write(sd, R18, 0x0a2);
238
239 wm8775_write(sd, R19, 0x005);
240
241 wm8775_write(sd, R20, 0x07a);
242
243 wm8775_write(sd, R21, 0x102);
244 return 0;
245}
246
247static int wm8775_remove(struct i2c_client *client)
248{
249 struct v4l2_subdev *sd = i2c_get_clientdata(client);
250
251 v4l2_device_unregister_subdev(sd);
252 kfree(to_state(sd));
253 return 0;
254}
255
256static const struct i2c_device_id wm8775_id[] = {
257 { "wm8775", 0 },
258 { }
259};
260MODULE_DEVICE_TABLE(i2c, wm8775_id);
261
262static struct v4l2_i2c_driver_data v4l2_i2c_data = {
263 .name = "wm8775",
264 .probe = wm8775_probe,
265 .remove = wm8775_remove,
266 .id_table = wm8775_id,
267};
268