diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-gpio.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-gpio.c | 324 |
1 files changed, 204 insertions, 120 deletions
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 74a44844ccaf..dc2850e87a7e 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c | |||
@@ -144,22 +144,9 @@ int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value) | |||
144 | return 0; | 144 | return 0; |
145 | } | 145 | } |
146 | 146 | ||
147 | void ivtv_gpio_init(struct ivtv *itv) | 147 | static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd) |
148 | { | 148 | { |
149 | u16 pin = 0; | 149 | return container_of(sd, struct ivtv, sd_gpio); |
150 | |||
151 | if (itv->card->xceive_pin) | ||
152 | pin = 1 << itv->card->xceive_pin; | ||
153 | |||
154 | if ((itv->card->gpio_init.direction | pin) == 0) | ||
155 | return; | ||
156 | |||
157 | IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", | ||
158 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); | ||
159 | |||
160 | /* init output data then direction */ | ||
161 | write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT); | ||
162 | write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR); | ||
163 | } | 150 | } |
164 | 151 | ||
165 | static struct v4l2_queryctrl gpio_ctrl_mute = { | 152 | static struct v4l2_queryctrl gpio_ctrl_mute = { |
@@ -173,134 +160,231 @@ static struct v4l2_queryctrl gpio_ctrl_mute = { | |||
173 | .flags = 0, | 160 | .flags = 0, |
174 | }; | 161 | }; |
175 | 162 | ||
176 | int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg) | 163 | static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq) |
177 | { | 164 | { |
178 | struct v4l2_tuner *tuner = arg; | 165 | struct ivtv *itv = sd_to_ivtv(sd); |
179 | struct v4l2_control *ctrl = arg; | ||
180 | struct v4l2_routing *route = arg; | ||
181 | u16 mask, data; | 166 | u16 mask, data; |
182 | 167 | ||
183 | switch (command) { | 168 | mask = itv->card->gpio_audio_freq.mask; |
184 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | 169 | switch (freq) { |
185 | mask = itv->card->gpio_audio_freq.mask; | 170 | case 32000: |
186 | switch (*(u32 *)arg) { | 171 | data = itv->card->gpio_audio_freq.f32000; |
187 | case 32000: | 172 | break; |
188 | data = itv->card->gpio_audio_freq.f32000; | 173 | case 44100: |
189 | break; | 174 | data = itv->card->gpio_audio_freq.f44100; |
190 | case 44100: | 175 | break; |
191 | data = itv->card->gpio_audio_freq.f44100; | 176 | case 48000: |
192 | break; | 177 | default: |
193 | case 48000: | 178 | data = itv->card->gpio_audio_freq.f48000; |
194 | default: | ||
195 | data = itv->card->gpio_audio_freq.f48000; | ||
196 | break; | ||
197 | } | ||
198 | break; | 179 | break; |
180 | } | ||
181 | if (mask) | ||
182 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
183 | return 0; | ||
184 | } | ||
199 | 185 | ||
200 | case VIDIOC_G_TUNER: | 186 | static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
201 | mask = itv->card->gpio_audio_detect.mask; | 187 | { |
202 | if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) | 188 | struct ivtv *itv = sd_to_ivtv(sd); |
203 | tuner->rxsubchans = V4L2_TUNER_MODE_STEREO | | 189 | u16 mask; |
204 | V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; | 190 | |
205 | else | 191 | mask = itv->card->gpio_audio_detect.mask; |
206 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO; | 192 | if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) |
207 | return 0; | 193 | vt->rxsubchans = V4L2_TUNER_MODE_STEREO | |
194 | V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; | ||
195 | else | ||
196 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
197 | return 0; | ||
198 | } | ||
208 | 199 | ||
209 | case VIDIOC_S_TUNER: | 200 | static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
210 | mask = itv->card->gpio_audio_mode.mask; | 201 | { |
211 | switch (tuner->audmode) { | 202 | struct ivtv *itv = sd_to_ivtv(sd); |
212 | case V4L2_TUNER_MODE_LANG1: | 203 | u16 mask, data; |
213 | data = itv->card->gpio_audio_mode.lang1; | ||
214 | break; | ||
215 | case V4L2_TUNER_MODE_LANG2: | ||
216 | data = itv->card->gpio_audio_mode.lang2; | ||
217 | break; | ||
218 | case V4L2_TUNER_MODE_MONO: | ||
219 | data = itv->card->gpio_audio_mode.mono; | ||
220 | break; | ||
221 | case V4L2_TUNER_MODE_STEREO: | ||
222 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
223 | default: | ||
224 | data = itv->card->gpio_audio_mode.stereo; | ||
225 | break; | ||
226 | } | ||
227 | break; | ||
228 | 204 | ||
229 | case AUDC_SET_RADIO: | 205 | mask = itv->card->gpio_audio_mode.mask; |
230 | mask = itv->card->gpio_audio_input.mask; | 206 | switch (vt->audmode) { |
231 | data = itv->card->gpio_audio_input.radio; | 207 | case V4L2_TUNER_MODE_LANG1: |
208 | data = itv->card->gpio_audio_mode.lang1; | ||
209 | break; | ||
210 | case V4L2_TUNER_MODE_LANG2: | ||
211 | data = itv->card->gpio_audio_mode.lang2; | ||
212 | break; | ||
213 | case V4L2_TUNER_MODE_MONO: | ||
214 | data = itv->card->gpio_audio_mode.mono; | ||
232 | break; | 215 | break; |
216 | case V4L2_TUNER_MODE_STEREO: | ||
217 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
218 | default: | ||
219 | data = itv->card->gpio_audio_mode.stereo; | ||
220 | break; | ||
221 | } | ||
222 | if (mask) | ||
223 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int subdev_s_radio(struct v4l2_subdev *sd) | ||
228 | { | ||
229 | struct ivtv *itv = sd_to_ivtv(sd); | ||
230 | u16 mask, data; | ||
231 | |||
232 | mask = itv->card->gpio_audio_input.mask; | ||
233 | data = itv->card->gpio_audio_input.radio; | ||
234 | if (mask) | ||
235 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
236 | return 0; | ||
237 | } | ||
233 | 238 | ||
234 | case VIDIOC_S_STD: | 239 | static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
235 | mask = itv->card->gpio_audio_input.mask; | 240 | { |
241 | struct ivtv *itv = sd_to_ivtv(sd); | ||
242 | u16 mask, data; | ||
243 | |||
244 | mask = itv->card->gpio_audio_input.mask; | ||
245 | data = itv->card->gpio_audio_input.tuner; | ||
246 | if (mask) | ||
247 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int subdev_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) | ||
252 | { | ||
253 | struct ivtv *itv = sd_to_ivtv(sd); | ||
254 | u16 mask, data; | ||
255 | |||
256 | if (route->input > 2) | ||
257 | return -EINVAL; | ||
258 | mask = itv->card->gpio_audio_input.mask; | ||
259 | switch (route->input) { | ||
260 | case 0: | ||
236 | data = itv->card->gpio_audio_input.tuner; | 261 | data = itv->card->gpio_audio_input.tuner; |
237 | break; | 262 | break; |
238 | 263 | case 1: | |
239 | case VIDIOC_INT_S_AUDIO_ROUTING: | 264 | data = itv->card->gpio_audio_input.linein; |
240 | if (route->input > 2) | 265 | break; |
241 | return -EINVAL; | 266 | case 2: |
242 | mask = itv->card->gpio_audio_input.mask; | 267 | default: |
243 | switch (route->input) { | 268 | data = itv->card->gpio_audio_input.radio; |
244 | case 0: | ||
245 | data = itv->card->gpio_audio_input.tuner; | ||
246 | break; | ||
247 | case 1: | ||
248 | data = itv->card->gpio_audio_input.linein; | ||
249 | break; | ||
250 | case 2: | ||
251 | default: | ||
252 | data = itv->card->gpio_audio_input.radio; | ||
253 | break; | ||
254 | } | ||
255 | break; | 269 | break; |
270 | } | ||
271 | if (mask) | ||
272 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
273 | return 0; | ||
274 | } | ||
256 | 275 | ||
257 | case VIDIOC_G_CTRL: | 276 | static int subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
258 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | 277 | { |
259 | return -EINVAL; | 278 | struct ivtv *itv = sd_to_ivtv(sd); |
260 | mask = itv->card->gpio_audio_mute.mask; | 279 | u16 mask, data; |
261 | data = itv->card->gpio_audio_mute.mute; | ||
262 | ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data; | ||
263 | return 0; | ||
264 | 280 | ||
265 | case VIDIOC_S_CTRL: | 281 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) |
266 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | 282 | return -EINVAL; |
267 | return -EINVAL; | 283 | mask = itv->card->gpio_audio_mute.mask; |
268 | mask = itv->card->gpio_audio_mute.mask; | 284 | data = itv->card->gpio_audio_mute.mute; |
269 | data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0; | 285 | ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data; |
270 | break; | 286 | return 0; |
287 | } | ||
271 | 288 | ||
272 | case VIDIOC_QUERYCTRL: | 289 | static int subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
273 | { | 290 | { |
274 | struct v4l2_queryctrl *qc = arg; | 291 | struct ivtv *itv = sd_to_ivtv(sd); |
292 | u16 mask, data; | ||
275 | 293 | ||
276 | if (qc->id != V4L2_CID_AUDIO_MUTE) | 294 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) |
277 | return -EINVAL; | 295 | return -EINVAL; |
278 | *qc = gpio_ctrl_mute; | 296 | mask = itv->card->gpio_audio_mute.mask; |
279 | return 0; | 297 | data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0; |
280 | } | 298 | if (mask) |
299 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
304 | { | ||
305 | if (qc->id != V4L2_CID_AUDIO_MUTE) | ||
306 | return -EINVAL; | ||
307 | *qc = gpio_ctrl_mute; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int subdev_log_status(struct v4l2_subdev *sd) | ||
312 | { | ||
313 | struct ivtv *itv = sd_to_ivtv(sd); | ||
281 | 314 | ||
282 | case VIDIOC_LOG_STATUS: | 315 | IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", |
283 | IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", | ||
284 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), | 316 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), |
285 | read_reg(IVTV_REG_GPIO_IN)); | 317 | read_reg(IVTV_REG_GPIO_IN)); |
286 | return 0; | 318 | return 0; |
319 | } | ||
287 | 320 | ||
288 | case VIDIOC_INT_S_VIDEO_ROUTING: | 321 | static int subdev_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) |
289 | if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */ | 322 | { |
290 | return -EINVAL; | 323 | struct ivtv *itv = sd_to_ivtv(sd); |
291 | mask = itv->card->gpio_video_input.mask; | 324 | u16 mask, data; |
292 | if (route->input == 0) | ||
293 | data = itv->card->gpio_video_input.tuner; | ||
294 | else if (route->input == 1) | ||
295 | data = itv->card->gpio_video_input.composite; | ||
296 | else | ||
297 | data = itv->card->gpio_video_input.svideo; | ||
298 | break; | ||
299 | 325 | ||
300 | default: | 326 | if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */ |
301 | return -EINVAL; | 327 | return -EINVAL; |
302 | } | 328 | mask = itv->card->gpio_video_input.mask; |
329 | if (route->input == 0) | ||
330 | data = itv->card->gpio_video_input.tuner; | ||
331 | else if (route->input == 1) | ||
332 | data = itv->card->gpio_video_input.composite; | ||
333 | else | ||
334 | data = itv->card->gpio_video_input.svideo; | ||
303 | if (mask) | 335 | if (mask) |
304 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | 336 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); |
305 | return 0; | 337 | return 0; |
306 | } | 338 | } |
339 | |||
340 | static const struct v4l2_subdev_core_ops subdev_core_ops = { | ||
341 | .log_status = subdev_log_status, | ||
342 | .g_ctrl = subdev_g_ctrl, | ||
343 | .s_ctrl = subdev_s_ctrl, | ||
344 | .queryctrl = subdev_queryctrl, | ||
345 | }; | ||
346 | |||
347 | static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = { | ||
348 | .s_std = subdev_s_std, | ||
349 | .s_radio = subdev_s_radio, | ||
350 | .g_tuner = subdev_g_tuner, | ||
351 | .s_tuner = subdev_s_tuner, | ||
352 | }; | ||
353 | |||
354 | static const struct v4l2_subdev_audio_ops subdev_audio_ops = { | ||
355 | .s_clock_freq = subdev_s_clock_freq, | ||
356 | .s_routing = subdev_s_audio_routing, | ||
357 | }; | ||
358 | |||
359 | static const struct v4l2_subdev_video_ops subdev_video_ops = { | ||
360 | .s_routing = subdev_s_video_routing, | ||
361 | }; | ||
362 | |||
363 | static const struct v4l2_subdev_ops subdev_ops = { | ||
364 | .core = &subdev_core_ops, | ||
365 | .tuner = &subdev_tuner_ops, | ||
366 | .audio = &subdev_audio_ops, | ||
367 | .video = &subdev_video_ops, | ||
368 | }; | ||
369 | |||
370 | int ivtv_gpio_init(struct ivtv *itv) | ||
371 | { | ||
372 | u16 pin = 0; | ||
373 | |||
374 | if (itv->card->xceive_pin) | ||
375 | pin = 1 << itv->card->xceive_pin; | ||
376 | |||
377 | if ((itv->card->gpio_init.direction | pin) == 0) | ||
378 | return 0; | ||
379 | |||
380 | IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", | ||
381 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); | ||
382 | |||
383 | /* init output data then direction */ | ||
384 | write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT); | ||
385 | write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR); | ||
386 | v4l2_subdev_init(&itv->sd_gpio, &subdev_ops); | ||
387 | snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name); | ||
388 | itv->sd_gpio.grp_id = IVTV_HW_GPIO; | ||
389 | return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio); | ||
390 | } | ||