aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/wm8775.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/wm8775.c')
-rw-r--r--drivers/media/video/wm8775.c221
1 files changed, 133 insertions, 88 deletions
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 48df661d4fc3..d0220b0ec0bc 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -32,7 +32,7 @@
32#include <linux/i2c.h> 32#include <linux/i2c.h>
33#include <linux/i2c-id.h> 33#include <linux/i2c-id.h>
34#include <linux/videodev2.h> 34#include <linux/videodev2.h>
35#include <media/v4l2-common.h> 35#include <media/v4l2-device.h>
36#include <media/v4l2-chip-ident.h> 36#include <media/v4l2-chip-ident.h>
37#include <media/v4l2-i2c-drv-legacy.h> 37#include <media/v4l2-i2c-drv-legacy.h>
38 38
@@ -54,16 +54,23 @@ enum {
54}; 54};
55 55
56struct wm8775_state { 56struct wm8775_state {
57 struct v4l2_subdev sd;
57 u8 input; /* Last selected input (0-0xf) */ 58 u8 input; /* Last selected input (0-0xf) */
58 u8 muted; 59 u8 muted;
59}; 60};
60 61
61static int wm8775_write(struct i2c_client *client, int reg, u16 val) 62static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
62{ 63{
64 return container_of(sd, struct wm8775_state, sd);
65}
66
67static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
68{
69 struct i2c_client *client = v4l2_get_subdevdata(sd);
63 int i; 70 int i;
64 71
65 if (reg < 0 || reg >= TOT_REGS) { 72 if (reg < 0 || reg >= TOT_REGS) {
66 v4l_err(client, "Invalid register R%d\n", reg); 73 v4l2_err(sd, "Invalid register R%d\n", reg);
67 return -1; 74 return -1;
68 } 75 }
69 76
@@ -71,84 +78,117 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
71 if (i2c_smbus_write_byte_data(client, 78 if (i2c_smbus_write_byte_data(client,
72 (reg << 1) | (val >> 8), val & 0xff) == 0) 79 (reg << 1) | (val >> 8), val & 0xff) == 0)
73 return 0; 80 return 0;
74 v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); 81 v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
75 return -1; 82 return -1;
76} 83}
77 84
78static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) 85static int wm8775_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
79{ 86{
80 struct wm8775_state *state = i2c_get_clientdata(client); 87 struct wm8775_state *state = to_state(sd);
81 struct v4l2_routing *route = arg; 88
82 struct v4l2_control *ctrl = arg; 89 /* There are 4 inputs and one output. Zero or more inputs
83 90 are multiplexed together to the output. Hence there are
84 switch (cmd) { 91 16 combinations.
85 case VIDIOC_INT_G_AUDIO_ROUTING: 92 If only one input is active (the normal case) then the
86 route->input = state->input; 93 input values 1, 2, 4 or 8 should be used. */
87 route->output = 0; 94 if (route->input > 15) {
88 break; 95 v4l2_err(sd, "Invalid input %d.\n", route->input);
89
90 case VIDIOC_INT_S_AUDIO_ROUTING:
91 /* There are 4 inputs and one output. Zero or more inputs
92 are multiplexed together to the output. Hence there are
93 16 combinations.
94 If only one input is active (the normal case) then the
95 input values 1, 2, 4 or 8 should be used. */
96 if (route->input > 15) {
97 v4l_err(client, "Invalid input %d.\n", route->input);
98 return -EINVAL;
99 }
100 state->input = route->input;
101 if (state->muted)
102 break;
103 wm8775_write(client, R21, 0x0c0);
104 wm8775_write(client, R14, 0x1d4);
105 wm8775_write(client, R15, 0x1d4);
106 wm8775_write(client, R21, 0x100 + state->input);
107 break;
108
109 case VIDIOC_G_CTRL:
110 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
111 return -EINVAL;
112 ctrl->value = state->muted;
113 break;
114
115 case VIDIOC_S_CTRL:
116 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
117 return -EINVAL;
118 state->muted = ctrl->value;
119 wm8775_write(client, R21, 0x0c0);
120 wm8775_write(client, R14, 0x1d4);
121 wm8775_write(client, R15, 0x1d4);
122 if (!state->muted)
123 wm8775_write(client, R21, 0x100 + state->input);
124 break;
125
126 case VIDIOC_G_CHIP_IDENT:
127 return v4l2_chip_ident_i2c_client(client,
128 arg, V4L2_IDENT_WM8775, 0);
129
130 case VIDIOC_LOG_STATUS:
131 v4l_info(client, "Input: %d%s\n", state->input,
132 state->muted ? " (muted)" : "");
133 break;
134
135 case VIDIOC_S_FREQUENCY:
136 /* If I remove this, then it can happen that I have no
137 sound the first time I tune from static to a valid channel.
138 It's difficult to reproduce and is almost certainly related
139 to the zero cross detect circuit. */
140 wm8775_write(client, R21, 0x0c0);
141 wm8775_write(client, R14, 0x1d4);
142 wm8775_write(client, R15, 0x1d4);
143 wm8775_write(client, R21, 0x100 + state->input);
144 break;
145
146 default:
147 return -EINVAL; 96 return -EINVAL;
148 } 97 }
98 state->input = route->input;
99 if (state->muted)
100 return 0;
101 wm8775_write(sd, R21, 0x0c0);
102 wm8775_write(sd, R14, 0x1d4);
103 wm8775_write(sd, R15, 0x1d4);
104 wm8775_write(sd, R21, 0x100 + state->input);
105 return 0;
106}
107
108static int wm8775_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
109{
110 struct wm8775_state *state = to_state(sd);
111
112 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
113 return -EINVAL;
114 ctrl->value = state->muted;
115 return 0;
116}
117
118static int wm8775_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
119{
120 struct wm8775_state *state = to_state(sd);
121
122 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
123 return -EINVAL;
124 state->muted = ctrl->value;
125 wm8775_write(sd, R21, 0x0c0);
126 wm8775_write(sd, R14, 0x1d4);
127 wm8775_write(sd, R15, 0x1d4);
128 if (!state->muted)
129 wm8775_write(sd, R21, 0x100 + state->input);
130 return 0;
131}
132
133static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
134{
135 struct i2c_client *client = v4l2_get_subdevdata(sd);
136
137 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
138}
139
140static int wm8775_log_status(struct v4l2_subdev *sd)
141{
142 struct wm8775_state *state = to_state(sd);
143
144 v4l2_info(sd, "Input: %d%s\n", state->input,
145 state->muted ? " (muted)" : "");
149 return 0; 146 return 0;
150} 147}
151 148
149static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
150{
151 struct wm8775_state *state = to_state(sd);
152
153 /* If I remove this, then it can happen that I have no
154 sound the first time I tune from static to a valid channel.
155 It's difficult to reproduce and is almost certainly related
156 to the zero cross detect circuit. */
157 wm8775_write(sd, R21, 0x0c0);
158 wm8775_write(sd, R14, 0x1d4);
159 wm8775_write(sd, R15, 0x1d4);
160 wm8775_write(sd, R21, 0x100 + state->input);
161 return 0;
162}
163
164static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
165{
166 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
167}
168
169/* ----------------------------------------------------------------------- */
170
171static const struct v4l2_subdev_core_ops wm8775_core_ops = {
172 .log_status = wm8775_log_status,
173 .g_chip_ident = wm8775_g_chip_ident,
174 .g_ctrl = wm8775_g_ctrl,
175 .s_ctrl = wm8775_s_ctrl,
176};
177
178static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
179 .s_frequency = wm8775_s_frequency,
180};
181
182static const struct v4l2_subdev_audio_ops wm8775_audio_ops = {
183 .s_routing = wm8775_s_routing,
184};
185
186static const struct v4l2_subdev_ops wm8775_ops = {
187 .core = &wm8775_core_ops,
188 .tuner = &wm8775_tuner_ops,
189 .audio = &wm8775_audio_ops,
190};
191
152/* ----------------------------------------------------------------------- */ 192/* ----------------------------------------------------------------------- */
153 193
154/* i2c implementation */ 194/* i2c implementation */
@@ -162,56 +202,61 @@ static int wm8775_probe(struct i2c_client *client,
162 const struct i2c_device_id *id) 202 const struct i2c_device_id *id)
163{ 203{
164 struct wm8775_state *state; 204 struct wm8775_state *state;
205 struct v4l2_subdev *sd;
165 206
166 /* Check if the adapter supports the needed features */ 207 /* Check if the adapter supports the needed features */
167 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 208 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
168 return -EIO; 209 return -EIO;
169 210
170 v4l_info(client, "chip found @ 0x%x (%s)\n", 211 v4l_info(client, "chip found @ 0x%02x (%s)\n",
171 client->addr << 1, client->adapter->name); 212 client->addr << 1, client->adapter->name);
172 213
173 state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); 214 state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
174 if (state == NULL) 215 if (state == NULL)
175 return -ENOMEM; 216 return -ENOMEM;
217 sd = &state->sd;
218 v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
176 state->input = 2; 219 state->input = 2;
177 state->muted = 0; 220 state->muted = 0;
178 i2c_set_clientdata(client, state);
179 221
180 /* Initialize wm8775 */ 222 /* Initialize wm8775 */
181 223
182 /* RESET */ 224 /* RESET */
183 wm8775_write(client, R23, 0x000); 225 wm8775_write(sd, R23, 0x000);
184 /* Disable zero cross detect timeout */ 226 /* Disable zero cross detect timeout */
185 wm8775_write(client, R7, 0x000); 227 wm8775_write(sd, R7, 0x000);
186 /* Left justified, 24-bit mode */ 228 /* Left justified, 24-bit mode */
187 wm8775_write(client, R11, 0x021); 229 wm8775_write(sd, R11, 0x021);
188 /* Master mode, clock ratio 256fs */ 230 /* Master mode, clock ratio 256fs */
189 wm8775_write(client, R12, 0x102); 231 wm8775_write(sd, R12, 0x102);
190 /* Powered up */ 232 /* Powered up */
191 wm8775_write(client, R13, 0x000); 233 wm8775_write(sd, R13, 0x000);
192 /* ADC gain +2.5dB, enable zero cross */ 234 /* ADC gain +2.5dB, enable zero cross */
193 wm8775_write(client, R14, 0x1d4); 235 wm8775_write(sd, R14, 0x1d4);
194 /* ADC gain +2.5dB, enable zero cross */ 236 /* ADC gain +2.5dB, enable zero cross */
195 wm8775_write(client, R15, 0x1d4); 237 wm8775_write(sd, R15, 0x1d4);
196 /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ 238 /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
197 wm8775_write(client, R16, 0x1bf); 239 wm8775_write(sd, R16, 0x1bf);
198 /* Enable gain control, use zero cross detection, 240 /* Enable gain control, use zero cross detection,
199 ALC hold time 42.6 ms */ 241 ALC hold time 42.6 ms */
200 wm8775_write(client, R17, 0x185); 242 wm8775_write(sd, R17, 0x185);
201 /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ 243 /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
202 wm8775_write(client, R18, 0x0a2); 244 wm8775_write(sd, R18, 0x0a2);
203 /* Enable noise gate, threshold -72dBfs */ 245 /* Enable noise gate, threshold -72dBfs */
204 wm8775_write(client, R19, 0x005); 246 wm8775_write(sd, R19, 0x005);
205 /* Transient window 4ms, lower PGA gain limit -1dB */ 247 /* Transient window 4ms, lower PGA gain limit -1dB */
206 wm8775_write(client, R20, 0x07a); 248 wm8775_write(sd, R20, 0x07a);
207 /* LRBOTH = 1, use input 2. */ 249 /* LRBOTH = 1, use input 2. */
208 wm8775_write(client, R21, 0x102); 250 wm8775_write(sd, R21, 0x102);
209 return 0; 251 return 0;
210} 252}
211 253
212static int wm8775_remove(struct i2c_client *client) 254static int wm8775_remove(struct i2c_client *client)
213{ 255{
214 kfree(i2c_get_clientdata(client)); 256 struct v4l2_subdev *sd = i2c_get_clientdata(client);
257
258 v4l2_device_unregister_subdev(sd);
259 kfree(to_state(sd));
215 return 0; 260 return 0;
216} 261}
217 262