]>
Commit | Line | Data |
---|---|---|
1c1e45d1 HV |
1 | /* |
2 | * cx18 gpio functions | |
3 | * | |
4 | * Derived from ivtv-gpio.c | |
5 | * | |
6 | * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> | |
6afdeaf8 | 7 | * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> |
1c1e45d1 HV |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
1c1e45d1 HV |
18 | */ |
19 | ||
20 | #include "cx18-driver.h" | |
b1526421 | 21 | #include "cx18-io.h" |
1c1e45d1 HV |
22 | #include "cx18-cards.h" |
23 | #include "cx18-gpio.h" | |
24 | #include "tuner-xc2028.h" | |
25 | ||
26 | /********************* GPIO stuffs *********************/ | |
27 | ||
28 | /* GPIO registers */ | |
29 | #define CX18_REG_GPIO_IN 0xc72010 | |
30 | #define CX18_REG_GPIO_OUT1 0xc78100 | |
31 | #define CX18_REG_GPIO_DIR1 0xc78108 | |
32 | #define CX18_REG_GPIO_OUT2 0xc78104 | |
33 | #define CX18_REG_GPIO_DIR2 0xc7810c | |
34 | ||
35 | /* | |
36 | * HVR-1600 GPIO pins, courtesy of Hauppauge: | |
37 | * | |
38 | * gpio0: zilog ir process reset pin | |
39 | * gpio1: zilog programming pin (you should never use this) | |
40 | * gpio12: cx24227 reset pin | |
41 | * gpio13: cs5345 reset pin | |
42 | */ | |
43 | ||
eefe1010 AW |
44 | /* |
45 | * File scope utility functions | |
46 | */ | |
9dcbf35a HV |
47 | static void gpio_write(struct cx18 *cx) |
48 | { | |
ced07371 AW |
49 | u32 dir_lo = cx->gpio_dir & 0xffff; |
50 | u32 val_lo = cx->gpio_val & 0xffff; | |
51 | u32 dir_hi = cx->gpio_dir >> 16; | |
52 | u32 val_hi = cx->gpio_val >> 16; | |
ba60bc67 | 53 | |
ced07371 AW |
54 | cx18_write_reg_expect(cx, dir_lo << 16, |
55 | CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo); | |
56 | cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo, | |
57 | CX18_REG_GPIO_OUT1, val_lo, dir_lo); | |
58 | cx18_write_reg_expect(cx, dir_hi << 16, | |
59 | CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi); | |
60 | cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi, | |
61 | CX18_REG_GPIO_OUT2, val_hi, dir_hi); | |
9dcbf35a HV |
62 | } |
63 | ||
eefe1010 | 64 | static void gpio_update(struct cx18 *cx, u32 mask, u32 data) |
1f09e8a2 | 65 | { |
eefe1010 AW |
66 | if (mask == 0) |
67 | return; | |
1f09e8a2 | 68 | |
eefe1010 AW |
69 | mutex_lock(&cx->gpio_lock); |
70 | cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask); | |
71 | gpio_write(cx); | |
72 | mutex_unlock(&cx->gpio_lock); | |
73 | } | |
74 | ||
75 | static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi, | |
76 | unsigned int assert_msecs, | |
77 | unsigned int recovery_msecs) | |
78 | { | |
79 | u32 mask; | |
1f09e8a2 | 80 | |
eefe1010 AW |
81 | mask = active_lo | active_hi; |
82 | if (mask == 0) | |
1f09e8a2 AW |
83 | return; |
84 | ||
eefe1010 AW |
85 | /* |
86 | * Assuming that active_hi and active_lo are a subsets of the bits in | |
87 | * gpio_dir. Also assumes that active_lo and active_hi don't overlap | |
88 | * in any bit position | |
89 | */ | |
1f09e8a2 AW |
90 | |
91 | /* Assert */ | |
eefe1010 AW |
92 | gpio_update(cx, mask, ~active_lo); |
93 | schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs)); | |
1f09e8a2 AW |
94 | |
95 | /* Deassert */ | |
eefe1010 AW |
96 | gpio_update(cx, mask, ~active_hi); |
97 | schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs)); | |
98 | } | |
99 | ||
100 | /* | |
101 | * GPIO Multiplexer - logical device | |
102 | */ | |
103 | static int gpiomux_log_status(struct v4l2_subdev *sd) | |
104 | { | |
105 | struct cx18 *cx = v4l2_get_subdevdata(sd); | |
106 | ||
107 | mutex_lock(&cx->gpio_lock); | |
6246d4e1 AW |
108 | CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", |
109 | cx->gpio_dir, cx->gpio_val); | |
8abdd00d | 110 | mutex_unlock(&cx->gpio_lock); |
eefe1010 | 111 | return 0; |
1f09e8a2 AW |
112 | } |
113 | ||
eefe1010 | 114 | static int gpiomux_s_radio(struct v4l2_subdev *sd) |
02fa272f | 115 | { |
eefe1010 | 116 | struct cx18 *cx = v4l2_get_subdevdata(sd); |
02fa272f | 117 | |
eefe1010 AW |
118 | /* |
119 | * FIXME - work out the cx->active/audio_input mess - this is | |
120 | * intended to handle the switch to radio mode and set the | |
121 | * audio routing, but we need to update the state in cx | |
122 | */ | |
123 | gpio_update(cx, cx->card->gpio_audio_input.mask, | |
124 | cx->card->gpio_audio_input.radio); | |
125 | return 0; | |
126 | } | |
02fa272f | 127 | |
eefe1010 AW |
128 | static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
129 | { | |
130 | struct cx18 *cx = v4l2_get_subdevdata(sd); | |
131 | u32 data; | |
02fa272f | 132 | |
eefe1010 AW |
133 | switch (cx->card->audio_inputs[cx->audio_input].muxer_input) { |
134 | case 1: | |
135 | data = cx->card->gpio_audio_input.linein; | |
136 | break; | |
137 | case 0: | |
138 | data = cx->card->gpio_audio_input.tuner; | |
139 | break; | |
140 | default: | |
141 | /* | |
142 | * FIXME - work out the cx->active/audio_input mess - this is | |
143 | * intended to handle the switch from radio mode and set the | |
144 | * audio routing, but we need to update the state in cx | |
145 | */ | |
146 | data = cx->card->gpio_audio_input.tuner; | |
147 | break; | |
148 | } | |
149 | gpio_update(cx, cx->card->gpio_audio_input.mask, data); | |
150 | return 0; | |
151 | } | |
02fa272f | 152 | |
eefe1010 | 153 | static int gpiomux_s_audio_routing(struct v4l2_subdev *sd, |
5325b427 | 154 | u32 input, u32 output, u32 config) |
eefe1010 AW |
155 | { |
156 | struct cx18 *cx = v4l2_get_subdevdata(sd); | |
157 | u32 data; | |
158 | ||
5325b427 | 159 | switch (input) { |
eefe1010 AW |
160 | case 0: |
161 | data = cx->card->gpio_audio_input.tuner; | |
162 | break; | |
163 | case 1: | |
164 | data = cx->card->gpio_audio_input.linein; | |
165 | break; | |
166 | case 2: | |
167 | data = cx->card->gpio_audio_input.radio; | |
168 | break; | |
169 | default: | |
170 | return -EINVAL; | |
171 | } | |
172 | gpio_update(cx, cx->card->gpio_audio_input.mask, data); | |
173 | return 0; | |
174 | } | |
175 | ||
176 | static const struct v4l2_subdev_core_ops gpiomux_core_ops = { | |
177 | .log_status = gpiomux_log_status, | |
178 | }; | |
179 | ||
180 | static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = { | |
eefe1010 AW |
181 | .s_radio = gpiomux_s_radio, |
182 | }; | |
183 | ||
184 | static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = { | |
185 | .s_routing = gpiomux_s_audio_routing, | |
186 | }; | |
187 | ||
8774bed9 LP |
188 | static const struct v4l2_subdev_video_ops gpiomux_video_ops = { |
189 | .s_std = gpiomux_s_std, | |
190 | }; | |
191 | ||
eefe1010 AW |
192 | static const struct v4l2_subdev_ops gpiomux_ops = { |
193 | .core = &gpiomux_core_ops, | |
194 | .tuner = &gpiomux_tuner_ops, | |
195 | .audio = &gpiomux_audio_ops, | |
8774bed9 | 196 | .video = &gpiomux_video_ops, |
eefe1010 AW |
197 | }; |
198 | ||
199 | /* | |
200 | * GPIO Reset Controller - logical device | |
201 | */ | |
202 | static int resetctrl_log_status(struct v4l2_subdev *sd) | |
203 | { | |
204 | struct cx18 *cx = v4l2_get_subdevdata(sd); | |
02fa272f | 205 | |
02fa272f | 206 | mutex_lock(&cx->gpio_lock); |
6246d4e1 AW |
207 | CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", |
208 | cx->gpio_dir, cx->gpio_val); | |
02fa272f | 209 | mutex_unlock(&cx->gpio_lock); |
eefe1010 | 210 | return 0; |
02fa272f | 211 | } |
02fa272f | 212 | |
eefe1010 AW |
213 | static int resetctrl_reset(struct v4l2_subdev *sd, u32 val) |
214 | { | |
215 | struct cx18 *cx = v4l2_get_subdevdata(sd); | |
216 | const struct cx18_gpio_i2c_slave_reset *p; | |
217 | ||
218 | p = &cx->card->gpio_i2c_slave_reset; | |
219 | switch (val) { | |
220 | case CX18_GPIO_RESET_I2C: | |
221 | gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask, | |
222 | p->msecs_asserted, p->msecs_recovery); | |
223 | break; | |
224 | case CX18_GPIO_RESET_Z8F0811: | |
225 | /* | |
226 | * Assert timing for the Z8F0811 on HVR-1600 boards: | |
227 | * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to | |
228 | * initiate | |
229 | * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock | |
230 | * cycles (6,601,085 nanoseconds ~= 7 milliseconds) | |
231 | * 3. DBG pin must be high before chip exits reset for normal | |
232 | * operation. DBG is open drain and hopefully pulled high | |
233 | * since we don't normally drive it (GPIO 1?) for the | |
234 | * HVR-1600 | |
235 | * 4. Z8F0811 won't exit reset until RESET is deasserted | |
236 | * 5. Zilog comes out of reset, loads reset vector address and | |
237 | * executes from there. Required recovery delay unknown. | |
238 | */ | |
239 | gpio_reset_seq(cx, p->ir_reset_mask, 0, | |
240 | p->msecs_asserted, p->msecs_recovery); | |
241 | break; | |
242 | case CX18_GPIO_RESET_XC2028: | |
243 | if (cx->card->tuners[0].tuner == TUNER_XC2028) | |
244 | gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0, | |
245 | 1, 1); | |
246 | break; | |
247 | } | |
248 | return 0; | |
249 | } | |
250 | ||
251 | static const struct v4l2_subdev_core_ops resetctrl_core_ops = { | |
252 | .log_status = resetctrl_log_status, | |
253 | .reset = resetctrl_reset, | |
254 | }; | |
255 | ||
256 | static const struct v4l2_subdev_ops resetctrl_ops = { | |
257 | .core = &resetctrl_core_ops, | |
258 | }; | |
259 | ||
260 | /* | |
261 | * External entry points | |
262 | */ | |
1c1e45d1 HV |
263 | void cx18_gpio_init(struct cx18 *cx) |
264 | { | |
8abdd00d | 265 | mutex_lock(&cx->gpio_lock); |
ba60bc67 HV |
266 | cx->gpio_dir = cx->card->gpio_init.direction; |
267 | cx->gpio_val = cx->card->gpio_init.initial_value; | |
9dcbf35a | 268 | |
4ecc2473 | 269 | if (cx->card->tuners[0].tuner == TUNER_XC2028) { |
ba60bc67 HV |
270 | cx->gpio_dir |= 1 << cx->card->xceive_pin; |
271 | cx->gpio_val |= 1 << cx->card->xceive_pin; | |
7f3917f6 HV |
272 | } |
273 | ||
8abdd00d AW |
274 | if (cx->gpio_dir == 0) { |
275 | mutex_unlock(&cx->gpio_lock); | |
1c1e45d1 | 276 | return; |
8abdd00d | 277 | } |
1c1e45d1 | 278 | |
9dcbf35a | 279 | CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n", |
b1526421 AW |
280 | cx18_read_reg(cx, CX18_REG_GPIO_DIR1), |
281 | cx18_read_reg(cx, CX18_REG_GPIO_DIR2), | |
282 | cx18_read_reg(cx, CX18_REG_GPIO_OUT1), | |
283 | cx18_read_reg(cx, CX18_REG_GPIO_OUT2)); | |
9dcbf35a HV |
284 | |
285 | gpio_write(cx); | |
8abdd00d | 286 | mutex_unlock(&cx->gpio_lock); |
1c1e45d1 HV |
287 | } |
288 | ||
eefe1010 AW |
289 | int cx18_gpio_register(struct cx18 *cx, u32 hw) |
290 | { | |
291 | struct v4l2_subdev *sd; | |
292 | const struct v4l2_subdev_ops *ops; | |
293 | char *str; | |
294 | ||
295 | switch (hw) { | |
296 | case CX18_HW_GPIO_MUX: | |
297 | sd = &cx->sd_gpiomux; | |
298 | ops = &gpiomux_ops; | |
6246d4e1 | 299 | str = "gpio-mux"; |
eefe1010 AW |
300 | break; |
301 | case CX18_HW_GPIO_RESET_CTRL: | |
302 | sd = &cx->sd_resetctrl; | |
303 | ops = &resetctrl_ops; | |
6246d4e1 | 304 | str = "gpio-reset-ctrl"; |
eefe1010 AW |
305 | break; |
306 | default: | |
307 | return -EINVAL; | |
308 | } | |
309 | ||
310 | v4l2_subdev_init(sd, ops); | |
311 | v4l2_set_subdevdata(sd, cx); | |
312 | snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str); | |
313 | sd->grp_id = hw; | |
314 | return v4l2_device_register_subdev(&cx->v4l2_dev, sd); | |
315 | } | |
316 | ||
317 | void cx18_reset_ir_gpio(void *data) | |
318 | { | |
319 | struct cx18 *cx = to_cx18((struct v4l2_device *)data); | |
320 | ||
321 | if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0) | |
322 | return; | |
323 | ||
324 | CX18_DEBUG_INFO("Resetting IR microcontroller\n"); | |
325 | ||
326 | v4l2_subdev_call(&cx->sd_resetctrl, | |
327 | core, reset, CX18_GPIO_RESET_Z8F0811); | |
328 | } | |
329 | EXPORT_SYMBOL(cx18_reset_ir_gpio); | |
330 | /* This symbol is exported for use by lirc_pvr150 for the IR-blaster */ | |
331 | ||
1c1e45d1 | 332 | /* Xceive tuner reset function */ |
d7cba043 | 333 | int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value) |
1c1e45d1 HV |
334 | { |
335 | struct i2c_algo_bit_data *algo = dev; | |
9dcbf35a HV |
336 | struct cx18_i2c_algo_callback_data *cb_data = algo->data; |
337 | struct cx18 *cx = cb_data->cx; | |
1c1e45d1 | 338 | |
eefe1010 AW |
339 | if (cmd != XC2028_TUNER_RESET || |
340 | cx->card->tuners[0].tuner != TUNER_XC2028) | |
1c1e45d1 | 341 | return 0; |
9dcbf35a | 342 | |
eefe1010 AW |
343 | CX18_DEBUG_INFO("Resetting XCeive tuner\n"); |
344 | return v4l2_subdev_call(&cx->sd_resetctrl, | |
345 | core, reset, CX18_GPIO_RESET_XC2028); | |
03c28085 | 346 | } |