diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/wm8775.c | 79 |
1 files changed, 50 insertions, 29 deletions
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 5c2ba599c0c7..23bad3fd6dc5 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/videodev2.h> | 35 | #include <linux/videodev2.h> |
36 | #include <media/v4l2-device.h> | 36 | #include <media/v4l2-device.h> |
37 | #include <media/v4l2-chip-ident.h> | 37 | #include <media/v4l2-chip-ident.h> |
38 | #include <media/v4l2-ctrls.h> | ||
38 | #include <media/v4l2-i2c-drv.h> | 39 | #include <media/v4l2-i2c-drv.h> |
39 | 40 | ||
40 | MODULE_DESCRIPTION("wm8775 driver"); | 41 | MODULE_DESCRIPTION("wm8775 driver"); |
@@ -53,8 +54,9 @@ enum { | |||
53 | 54 | ||
54 | struct wm8775_state { | 55 | struct wm8775_state { |
55 | struct v4l2_subdev sd; | 56 | struct v4l2_subdev sd; |
57 | struct v4l2_ctrl_handler hdl; | ||
58 | struct v4l2_ctrl *mute; | ||
56 | u8 input; /* Last selected input (0-0xf) */ | 59 | u8 input; /* Last selected input (0-0xf) */ |
57 | u8 muted; | ||
58 | }; | 60 | }; |
59 | 61 | ||
60 | static inline struct wm8775_state *to_state(struct v4l2_subdev *sd) | 62 | static inline struct wm8775_state *to_state(struct v4l2_subdev *sd) |
@@ -62,6 +64,11 @@ static inline struct wm8775_state *to_state(struct v4l2_subdev *sd) | |||
62 | return container_of(sd, struct wm8775_state, sd); | 64 | return container_of(sd, struct wm8775_state, sd); |
63 | } | 65 | } |
64 | 66 | ||
67 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
68 | { | ||
69 | return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd; | ||
70 | } | ||
71 | |||
65 | static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val) | 72 | static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val) |
66 | { | 73 | { |
67 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 74 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -95,7 +102,7 @@ static int wm8775_s_routing(struct v4l2_subdev *sd, | |||
95 | return -EINVAL; | 102 | return -EINVAL; |
96 | } | 103 | } |
97 | state->input = input; | 104 | state->input = input; |
98 | if (state->muted) | 105 | if (!v4l2_ctrl_g_ctrl(state->mute)) |
99 | return 0; | 106 | return 0; |
100 | wm8775_write(sd, R21, 0x0c0); | 107 | wm8775_write(sd, R21, 0x0c0); |
101 | wm8775_write(sd, R14, 0x1d4); | 108 | wm8775_write(sd, R14, 0x1d4); |
@@ -104,29 +111,21 @@ static int wm8775_s_routing(struct v4l2_subdev *sd, | |||
104 | return 0; | 111 | return 0; |
105 | } | 112 | } |
106 | 113 | ||
107 | static int wm8775_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 114 | static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl) |
108 | { | 115 | { |
116 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
109 | struct wm8775_state *state = to_state(sd); | 117 | struct wm8775_state *state = to_state(sd); |
110 | 118 | ||
111 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | 119 | switch (ctrl->id) { |
112 | return -EINVAL; | 120 | case V4L2_CID_AUDIO_MUTE: |
113 | ctrl->value = state->muted; | 121 | wm8775_write(sd, R21, 0x0c0); |
114 | return 0; | 122 | wm8775_write(sd, R14, 0x1d4); |
115 | } | 123 | wm8775_write(sd, R15, 0x1d4); |
116 | 124 | if (!ctrl->val) | |
117 | static int wm8775_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 125 | wm8775_write(sd, R21, 0x100 + state->input); |
118 | { | 126 | return 0; |
119 | struct wm8775_state *state = to_state(sd); | 127 | } |
120 | 128 | return -EINVAL; | |
121 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
122 | return -EINVAL; | ||
123 | state->muted = ctrl->value; | ||
124 | wm8775_write(sd, R21, 0x0c0); | ||
125 | wm8775_write(sd, R14, 0x1d4); | ||
126 | wm8775_write(sd, R15, 0x1d4); | ||
127 | if (!state->muted) | ||
128 | wm8775_write(sd, R21, 0x100 + state->input); | ||
129 | return 0; | ||
130 | } | 129 | } |
131 | 130 | ||
132 | static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 131 | static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
@@ -140,8 +139,8 @@ static int wm8775_log_status(struct v4l2_subdev *sd) | |||
140 | { | 139 | { |
141 | struct wm8775_state *state = to_state(sd); | 140 | struct wm8775_state *state = to_state(sd); |
142 | 141 | ||
143 | v4l2_info(sd, "Input: %d%s\n", state->input, | 142 | v4l2_info(sd, "Input: %d\n", state->input); |
144 | state->muted ? " (muted)" : ""); | 143 | v4l2_ctrl_handler_log_status(&state->hdl, sd->name); |
145 | return 0; | 144 | return 0; |
146 | } | 145 | } |
147 | 146 | ||
@@ -162,11 +161,20 @@ static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fre | |||
162 | 161 | ||
163 | /* ----------------------------------------------------------------------- */ | 162 | /* ----------------------------------------------------------------------- */ |
164 | 163 | ||
164 | static const struct v4l2_ctrl_ops wm8775_ctrl_ops = { | ||
165 | .s_ctrl = wm8775_s_ctrl, | ||
166 | }; | ||
167 | |||
165 | static const struct v4l2_subdev_core_ops wm8775_core_ops = { | 168 | static const struct v4l2_subdev_core_ops wm8775_core_ops = { |
166 | .log_status = wm8775_log_status, | 169 | .log_status = wm8775_log_status, |
167 | .g_chip_ident = wm8775_g_chip_ident, | 170 | .g_chip_ident = wm8775_g_chip_ident, |
168 | .g_ctrl = wm8775_g_ctrl, | 171 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
169 | .s_ctrl = wm8775_s_ctrl, | 172 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
173 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
174 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
175 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
176 | .queryctrl = v4l2_subdev_queryctrl, | ||
177 | .querymenu = v4l2_subdev_querymenu, | ||
170 | }; | 178 | }; |
171 | 179 | ||
172 | static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = { | 180 | static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = { |
@@ -205,13 +213,24 @@ static int wm8775_probe(struct i2c_client *client, | |||
205 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | 213 | v4l_info(client, "chip found @ 0x%02x (%s)\n", |
206 | client->addr << 1, client->adapter->name); | 214 | client->addr << 1, client->adapter->name); |
207 | 215 | ||
208 | state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); | 216 | state = kzalloc(sizeof(struct wm8775_state), GFP_KERNEL); |
209 | if (state == NULL) | 217 | if (state == NULL) |
210 | return -ENOMEM; | 218 | return -ENOMEM; |
211 | sd = &state->sd; | 219 | sd = &state->sd; |
212 | v4l2_i2c_subdev_init(sd, client, &wm8775_ops); | 220 | v4l2_i2c_subdev_init(sd, client, &wm8775_ops); |
213 | state->input = 2; | 221 | state->input = 2; |
214 | state->muted = 0; | 222 | |
223 | v4l2_ctrl_handler_init(&state->hdl, 1); | ||
224 | state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, | ||
225 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); | ||
226 | sd->ctrl_handler = &state->hdl; | ||
227 | if (state->hdl.error) { | ||
228 | int err = state->hdl.error; | ||
229 | |||
230 | v4l2_ctrl_handler_free(&state->hdl); | ||
231 | kfree(state); | ||
232 | return err; | ||
233 | } | ||
215 | 234 | ||
216 | /* Initialize wm8775 */ | 235 | /* Initialize wm8775 */ |
217 | 236 | ||
@@ -248,9 +267,11 @@ static int wm8775_probe(struct i2c_client *client, | |||
248 | static int wm8775_remove(struct i2c_client *client) | 267 | static int wm8775_remove(struct i2c_client *client) |
249 | { | 268 | { |
250 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 269 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
270 | struct wm8775_state *state = to_state(sd); | ||
251 | 271 | ||
252 | v4l2_device_unregister_subdev(sd); | 272 | v4l2_device_unregister_subdev(sd); |
253 | kfree(to_state(sd)); | 273 | v4l2_ctrl_handler_free(&state->hdl); |
274 | kfree(state); | ||
254 | return 0; | 275 | return 0; |
255 | } | 276 | } |
256 | 277 | ||