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