aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/wm8739.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/wm8739.c')
-rw-r--r--drivers/media/video/wm8739.c179
1 files changed, 62 insertions, 117 deletions
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index a11b99b4226b..d5965543ecab 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -27,11 +27,11 @@
27#include <linux/ioctl.h> 27#include <linux/ioctl.h>
28#include <asm/uaccess.h> 28#include <asm/uaccess.h>
29#include <linux/i2c.h> 29#include <linux/i2c.h>
30#include <linux/i2c-id.h>
31#include <linux/videodev2.h> 30#include <linux/videodev2.h>
32#include <media/v4l2-device.h> 31#include <media/v4l2-device.h>
33#include <media/v4l2-chip-ident.h> 32#include <media/v4l2-chip-ident.h>
34#include <media/v4l2-i2c-drv.h> 33#include <media/v4l2-i2c-drv.h>
34#include <media/v4l2-ctrls.h>
35 35
36MODULE_DESCRIPTION("wm8739 driver"); 36MODULE_DESCRIPTION("wm8739 driver");
37MODULE_AUTHOR("T. Adachi, Hans Verkuil"); 37MODULE_AUTHOR("T. Adachi, Hans Verkuil");
@@ -54,12 +54,14 @@ enum {
54 54
55struct wm8739_state { 55struct wm8739_state {
56 struct v4l2_subdev sd; 56 struct v4l2_subdev sd;
57 struct v4l2_ctrl_handler hdl;
58 struct {
59 /* audio cluster */
60 struct v4l2_ctrl *volume;
61 struct v4l2_ctrl *mute;
62 struct v4l2_ctrl *balance;
63 };
57 u32 clock_freq; 64 u32 clock_freq;
58 u8 muted;
59 u16 volume;
60 u16 balance;
61 u8 vol_l; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
62 u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
63}; 65};
64 66
65static inline struct wm8739_state *to_state(struct v4l2_subdev *sd) 67static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
@@ -67,6 +69,11 @@ static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
67 return container_of(sd, struct wm8739_state, sd); 69 return container_of(sd, struct wm8739_state, sd);
68} 70}
69 71
72static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
73{
74 return &container_of(ctrl->handler, struct wm8739_state, hdl)->sd;
75}
76
70/* ------------------------------------------------------------------------ */ 77/* ------------------------------------------------------------------------ */
71 78
72static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val) 79static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
@@ -89,58 +96,17 @@ static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
89 return -1; 96 return -1;
90} 97}
91 98
92/* write regs to set audio volume etc */ 99static int wm8739_s_ctrl(struct v4l2_ctrl *ctrl)
93static void wm8739_set_audio(struct v4l2_subdev *sd)
94{
95 struct wm8739_state *state = to_state(sd);
96 u16 mute = state->muted ? 0x80 : 0;
97
98 /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
99 * Default setting: 0x17 = 0 dB
100 */
101 wm8739_write(sd, R0, (state->vol_l & 0x1f) | mute);
102 wm8739_write(sd, R1, (state->vol_r & 0x1f) | mute);
103}
104
105static int wm8739_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
106{
107 struct wm8739_state *state = to_state(sd);
108
109 switch (ctrl->id) {
110 case V4L2_CID_AUDIO_MUTE:
111 ctrl->value = state->muted;
112 break;
113
114 case V4L2_CID_AUDIO_VOLUME:
115 ctrl->value = state->volume;
116 break;
117
118 case V4L2_CID_AUDIO_BALANCE:
119 ctrl->value = state->balance;
120 break;
121
122 default:
123 return -EINVAL;
124 }
125 return 0;
126}
127
128static int wm8739_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
129{ 100{
101 struct v4l2_subdev *sd = to_sd(ctrl);
130 struct wm8739_state *state = to_state(sd); 102 struct wm8739_state *state = to_state(sd);
131 unsigned int work_l, work_r; 103 unsigned int work_l, work_r;
104 u8 vol_l; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
105 u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
106 u16 mute;
132 107
133 switch (ctrl->id) { 108 switch (ctrl->id) {
134 case V4L2_CID_AUDIO_MUTE:
135 state->muted = ctrl->value;
136 break;
137
138 case V4L2_CID_AUDIO_VOLUME: 109 case V4L2_CID_AUDIO_VOLUME:
139 state->volume = ctrl->value;
140 break;
141
142 case V4L2_CID_AUDIO_BALANCE:
143 state->balance = ctrl->value;
144 break; 110 break;
145 111
146 default: 112 default:
@@ -148,52 +114,25 @@ static int wm8739_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
148 } 114 }
149 115
150 /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */ 116 /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */
151 work_l = (min(65536 - state->balance, 32768) * state->volume) / 32768; 117 work_l = (min(65536 - state->balance->val, 32768) * state->volume->val) / 32768;
152 work_r = (min(state->balance, (u16)32768) * state->volume) / 32768; 118 work_r = (min(state->balance->val, 32768) * state->volume->val) / 32768;
153 119
154 state->vol_l = (long)work_l * 31 / 65535; 120 vol_l = (long)work_l * 31 / 65535;
155 state->vol_r = (long)work_r * 31 / 65535; 121 vol_r = (long)work_r * 31 / 65535;
156 122
157 /* set audio volume etc. */ 123 /* set audio volume etc. */
158 wm8739_set_audio(sd); 124 mute = state->mute->val ? 0x80 : 0;
125
126 /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
127 * Default setting: 0x17 = 0 dB
128 */
129 wm8739_write(sd, R0, (vol_l & 0x1f) | mute);
130 wm8739_write(sd, R1, (vol_r & 0x1f) | mute);
159 return 0; 131 return 0;
160} 132}
161 133
162/* ------------------------------------------------------------------------ */ 134/* ------------------------------------------------------------------------ */
163 135
164static struct v4l2_queryctrl wm8739_qctrl[] = {
165 {
166 .id = V4L2_CID_AUDIO_VOLUME,
167 .name = "Volume",
168 .minimum = 0,
169 .maximum = 65535,
170 .step = 65535/100,
171 .default_value = 58880,
172 .flags = 0,
173 .type = V4L2_CTRL_TYPE_INTEGER,
174 }, {
175 .id = V4L2_CID_AUDIO_MUTE,
176 .name = "Mute",
177 .minimum = 0,
178 .maximum = 1,
179 .step = 1,
180 .default_value = 1,
181 .flags = 0,
182 .type = V4L2_CTRL_TYPE_BOOLEAN,
183 }, {
184 .id = V4L2_CID_AUDIO_BALANCE,
185 .name = "Balance",
186 .minimum = 0,
187 .maximum = 65535,
188 .step = 65535/100,
189 .default_value = 32768,
190 .flags = 0,
191 .type = V4L2_CTRL_TYPE_INTEGER,
192 }
193};
194
195/* ------------------------------------------------------------------------ */
196
197static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq) 136static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
198{ 137{
199 struct wm8739_state *state = to_state(sd); 138 struct wm8739_state *state = to_state(sd);
@@ -222,18 +161,6 @@ static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
222 return 0; 161 return 0;
223} 162}
224 163
225static int wm8739_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
226{
227 int i;
228
229 for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
230 if (qc->id && qc->id == wm8739_qctrl[i].id) {
231 memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
232 return 0;
233 }
234 return -EINVAL;
235}
236
237static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) 164static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
238{ 165{
239 struct i2c_client *client = v4l2_get_subdevdata(sd); 166 struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -246,21 +173,26 @@ static int wm8739_log_status(struct v4l2_subdev *sd)
246 struct wm8739_state *state = to_state(sd); 173 struct wm8739_state *state = to_state(sd);
247 174
248 v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq); 175 v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq);
249 v4l2_info(sd, "Volume L: %02x%s\n", state->vol_l & 0x1f, 176 v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
250 state->muted ? " (muted)" : "");
251 v4l2_info(sd, "Volume R: %02x%s\n", state->vol_r & 0x1f,
252 state->muted ? " (muted)" : "");
253 return 0; 177 return 0;
254} 178}
255 179
256/* ----------------------------------------------------------------------- */ 180/* ----------------------------------------------------------------------- */
257 181
182static const struct v4l2_ctrl_ops wm8739_ctrl_ops = {
183 .s_ctrl = wm8739_s_ctrl,
184};
185
258static const struct v4l2_subdev_core_ops wm8739_core_ops = { 186static const struct v4l2_subdev_core_ops wm8739_core_ops = {
259 .log_status = wm8739_log_status, 187 .log_status = wm8739_log_status,
260 .g_chip_ident = wm8739_g_chip_ident, 188 .g_chip_ident = wm8739_g_chip_ident,
261 .queryctrl = wm8739_queryctrl, 189 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
262 .g_ctrl = wm8739_g_ctrl, 190 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
263 .s_ctrl = wm8739_s_ctrl, 191 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
192 .g_ctrl = v4l2_subdev_g_ctrl,
193 .s_ctrl = v4l2_subdev_s_ctrl,
194 .queryctrl = v4l2_subdev_queryctrl,
195 .querymenu = v4l2_subdev_querymenu,
264}; 196};
265 197
266static const struct v4l2_subdev_audio_ops wm8739_audio_ops = { 198static const struct v4l2_subdev_audio_ops wm8739_audio_ops = {
@@ -289,17 +221,28 @@ static int wm8739_probe(struct i2c_client *client,
289 v4l_info(client, "chip found @ 0x%x (%s)\n", 221 v4l_info(client, "chip found @ 0x%x (%s)\n",
290 client->addr << 1, client->adapter->name); 222 client->addr << 1, client->adapter->name);
291 223
292 state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); 224 state = kzalloc(sizeof(struct wm8739_state), GFP_KERNEL);
293 if (state == NULL) 225 if (state == NULL)
294 return -ENOMEM; 226 return -ENOMEM;
295 sd = &state->sd; 227 sd = &state->sd;
296 v4l2_i2c_subdev_init(sd, client, &wm8739_ops); 228 v4l2_i2c_subdev_init(sd, client, &wm8739_ops);
297 state->vol_l = 0x17; /* 0dB */ 229 v4l2_ctrl_handler_init(&state->hdl, 2);
298 state->vol_r = 0x17; /* 0dB */ 230 state->volume = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
299 state->muted = 0; 231 V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 50736);
300 state->balance = 32768; 232 state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
301 /* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */ 233 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
302 state->volume = ((long)state->vol_l + 1) * 65535 / 31; 234 state->balance = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
235 V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
236 sd->ctrl_handler = &state->hdl;
237 if (state->hdl.error) {
238 int err = state->hdl.error;
239
240 v4l2_ctrl_handler_free(&state->hdl);
241 kfree(state);
242 return err;
243 }
244 v4l2_ctrl_cluster(3, &state->volume);
245
303 state->clock_freq = 48000; 246 state->clock_freq = 48000;
304 247
305 /* Initialize wm8739 */ 248 /* Initialize wm8739 */
@@ -318,15 +261,17 @@ static int wm8739_probe(struct i2c_client *client,
318 /* activate */ 261 /* activate */
319 wm8739_write(sd, R9, 0x001); 262 wm8739_write(sd, R9, 0x001);
320 /* set volume/mute */ 263 /* set volume/mute */
321 wm8739_set_audio(sd); 264 v4l2_ctrl_handler_setup(&state->hdl);
322 return 0; 265 return 0;
323} 266}
324 267
325static int wm8739_remove(struct i2c_client *client) 268static int wm8739_remove(struct i2c_client *client)
326{ 269{
327 struct v4l2_subdev *sd = i2c_get_clientdata(client); 270 struct v4l2_subdev *sd = i2c_get_clientdata(client);
271 struct wm8739_state *state = to_state(sd);
328 272
329 v4l2_device_unregister_subdev(sd); 273 v4l2_device_unregister_subdev(sd);
274 v4l2_ctrl_handler_free(&state->hdl);
330 kfree(to_state(sd)); 275 kfree(to_state(sd));
331 return 0; 276 return 0;
332} 277}