Commit | Line | Data |
---|---|---|
4c66c920 MK |
1 | /* |
2 | * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF | |
3 | * | |
08e10972 | 4 | * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org> |
4c66c920 MK |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | ||
21 | #include "mxl111sf-gpio.h" | |
22 | #include "mxl111sf-i2c.h" | |
23 | #include "mxl111sf.h" | |
24 | ||
25 | /* ------------------------------------------------------------------------- */ | |
26 | ||
27 | #define MXL_GPIO_MUX_REG_0 0x84 | |
28 | #define MXL_GPIO_MUX_REG_1 0x89 | |
29 | #define MXL_GPIO_MUX_REG_2 0x82 | |
30 | ||
31 | #define MXL_GPIO_DIR_INPUT 0 | |
32 | #define MXL_GPIO_DIR_OUTPUT 1 | |
33 | ||
34 | ||
35 | static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val) | |
36 | { | |
37 | int ret; | |
38 | u8 tmp; | |
39 | ||
40 | mxl_debug_adv("(%d, %d)", pin, val); | |
41 | ||
42 | if ((pin > 0) && (pin < 8)) { | |
43 | ret = mxl111sf_read_reg(state, 0x19, &tmp); | |
44 | if (mxl_fail(ret)) | |
45 | goto fail; | |
46 | tmp &= ~(1 << (pin - 1)); | |
47 | tmp |= (val << (pin - 1)); | |
48 | ret = mxl111sf_write_reg(state, 0x19, tmp); | |
49 | if (mxl_fail(ret)) | |
50 | goto fail; | |
51 | } else if (pin <= 10) { | |
52 | if (pin == 0) | |
53 | pin += 7; | |
54 | ret = mxl111sf_read_reg(state, 0x30, &tmp); | |
55 | if (mxl_fail(ret)) | |
56 | goto fail; | |
57 | tmp &= ~(1 << (pin - 3)); | |
58 | tmp |= (val << (pin - 3)); | |
59 | ret = mxl111sf_write_reg(state, 0x30, tmp); | |
60 | if (mxl_fail(ret)) | |
61 | goto fail; | |
62 | } else | |
63 | ret = -EINVAL; | |
64 | fail: | |
65 | return ret; | |
66 | } | |
67 | ||
68 | static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val) | |
69 | { | |
70 | int ret; | |
71 | u8 tmp; | |
72 | ||
73 | mxl_debug("(0x%02x)", pin); | |
74 | ||
75 | *val = 0; | |
76 | ||
77 | switch (pin) { | |
78 | case 0: | |
79 | case 1: | |
80 | case 2: | |
81 | case 3: | |
82 | ret = mxl111sf_read_reg(state, 0x23, &tmp); | |
83 | if (mxl_fail(ret)) | |
84 | goto fail; | |
85 | *val = (tmp >> (pin + 4)) & 0x01; | |
86 | break; | |
87 | case 4: | |
88 | case 5: | |
89 | case 6: | |
90 | case 7: | |
91 | ret = mxl111sf_read_reg(state, 0x2f, &tmp); | |
92 | if (mxl_fail(ret)) | |
93 | goto fail; | |
94 | *val = (tmp >> pin) & 0x01; | |
95 | break; | |
96 | case 8: | |
97 | case 9: | |
98 | case 10: | |
99 | ret = mxl111sf_read_reg(state, 0x22, &tmp); | |
100 | if (mxl_fail(ret)) | |
101 | goto fail; | |
102 | *val = (tmp >> (pin - 3)) & 0x01; | |
103 | break; | |
104 | default: | |
105 | return -EINVAL; /* invalid pin */ | |
106 | } | |
107 | fail: | |
108 | return ret; | |
109 | } | |
110 | ||
111 | struct mxl_gpio_cfg { | |
112 | u8 pin; | |
113 | u8 dir; | |
114 | u8 val; | |
115 | }; | |
116 | ||
117 | static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state, | |
118 | struct mxl_gpio_cfg *gpio_cfg) | |
119 | { | |
120 | int ret; | |
121 | u8 tmp; | |
122 | ||
123 | mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir); | |
124 | ||
125 | switch (gpio_cfg->pin) { | |
126 | case 0: | |
127 | case 1: | |
128 | case 2: | |
129 | case 3: | |
130 | ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp); | |
131 | if (mxl_fail(ret)) | |
132 | goto fail; | |
133 | tmp &= ~(1 << (gpio_cfg->pin + 4)); | |
134 | tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4)); | |
135 | ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp); | |
136 | if (mxl_fail(ret)) | |
137 | goto fail; | |
138 | break; | |
139 | case 4: | |
140 | case 5: | |
141 | case 6: | |
142 | case 7: | |
143 | ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp); | |
144 | if (mxl_fail(ret)) | |
145 | goto fail; | |
146 | tmp &= ~(1 << gpio_cfg->pin); | |
147 | tmp |= (gpio_cfg->dir << gpio_cfg->pin); | |
148 | ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp); | |
149 | if (mxl_fail(ret)) | |
150 | goto fail; | |
151 | break; | |
152 | case 8: | |
153 | case 9: | |
154 | case 10: | |
155 | ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp); | |
156 | if (mxl_fail(ret)) | |
157 | goto fail; | |
158 | tmp &= ~(1 << (gpio_cfg->pin - 3)); | |
159 | tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3)); | |
160 | ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp); | |
161 | if (mxl_fail(ret)) | |
162 | goto fail; | |
163 | break; | |
164 | default: | |
165 | return -EINVAL; /* invalid pin */ | |
166 | } | |
167 | ||
168 | ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ? | |
169 | mxl111sf_set_gpo_state(state, | |
170 | gpio_cfg->pin, gpio_cfg->val) : | |
171 | mxl111sf_get_gpi_state(state, | |
172 | gpio_cfg->pin, &gpio_cfg->val); | |
173 | mxl_fail(ret); | |
174 | fail: | |
175 | return ret; | |
176 | } | |
177 | ||
178 | static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state, | |
179 | int gpio, int direction, int val) | |
180 | { | |
181 | struct mxl_gpio_cfg gpio_config = { | |
182 | .pin = gpio, | |
183 | .dir = direction, | |
184 | .val = val, | |
185 | }; | |
186 | ||
187 | mxl_debug("(%d, %d, %d)", gpio, direction, val); | |
188 | ||
189 | return mxl111sf_config_gpio_pins(state, &gpio_config); | |
190 | } | |
191 | ||
192 | /* ------------------------------------------------------------------------- */ | |
193 | ||
194 | #define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */ | |
195 | #define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */ | |
196 | #define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */ | |
197 | #define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */ | |
198 | #define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */ | |
199 | #define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */ | |
200 | #define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */ | |
201 | #define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */ | |
202 | #define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */ | |
203 | #define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */ | |
204 | #define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */ | |
205 | #define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */ | |
206 | #define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */ | |
207 | #define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */ | |
208 | #define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */ | |
209 | #define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */ | |
210 | #define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */ | |
211 | #define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */ | |
212 | #define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */ | |
213 | ||
214 | int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, | |
215 | enum mxl111sf_mux_config pin_mux_config) | |
216 | { | |
217 | u8 r12, r15, r17, r18, r3D, r82, r84, r89; | |
218 | int ret; | |
219 | ||
220 | mxl_debug("(%d)", pin_mux_config); | |
221 | ||
222 | ret = mxl111sf_read_reg(state, 0x17, &r17); | |
223 | if (mxl_fail(ret)) | |
224 | goto fail; | |
225 | ret = mxl111sf_read_reg(state, 0x18, &r18); | |
226 | if (mxl_fail(ret)) | |
227 | goto fail; | |
228 | ret = mxl111sf_read_reg(state, 0x12, &r12); | |
229 | if (mxl_fail(ret)) | |
230 | goto fail; | |
231 | ret = mxl111sf_read_reg(state, 0x15, &r15); | |
232 | if (mxl_fail(ret)) | |
233 | goto fail; | |
234 | ret = mxl111sf_read_reg(state, 0x82, &r82); | |
235 | if (mxl_fail(ret)) | |
236 | goto fail; | |
237 | ret = mxl111sf_read_reg(state, 0x84, &r84); | |
238 | if (mxl_fail(ret)) | |
239 | goto fail; | |
240 | ret = mxl111sf_read_reg(state, 0x89, &r89); | |
241 | if (mxl_fail(ret)) | |
242 | goto fail; | |
243 | ret = mxl111sf_read_reg(state, 0x3D, &r3D); | |
244 | if (mxl_fail(ret)) | |
245 | goto fail; | |
246 | ||
247 | switch (pin_mux_config) { | |
248 | case PIN_MUX_TS_OUT_PARALLEL: | |
249 | /* mpeg_mode = 1 */ | |
250 | r17 |= PIN_MUX_MPEG_MODE_MASK; | |
251 | /* mpeg_par_en = 1 */ | |
252 | r18 |= PIN_MUX_MPEG_PAR_EN_MASK; | |
253 | /* mpeg_ser_en = 0 */ | |
254 | r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; | |
255 | /* mpg_in_mux = 0 */ | |
256 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
257 | /* bt656_enable = 0 */ | |
258 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
259 | /* i2s_enable = 0 */ | |
260 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
261 | /* spi_mode = 0 */ | |
262 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
263 | /* mclk_en_ctrl = 1 */ | |
264 | r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; | |
265 | /* mperr_en_ctrl = 1 */ | |
266 | r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; | |
267 | /* mdval_en_ctrl = 1 */ | |
268 | r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; | |
269 | /* mpsyn_en_ctrl = 1 */ | |
270 | r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; | |
271 | /* mdat_en_ctrl[3:0] = 0xF */ | |
272 | r84 |= 0xF0; | |
273 | /* mdat_en_ctrl[7:4] = 0xF */ | |
274 | r89 |= 0xF0; | |
275 | break; | |
276 | case PIN_MUX_TS_OUT_SERIAL: | |
277 | /* mpeg_mode = 1 */ | |
278 | r17 |= PIN_MUX_MPEG_MODE_MASK; | |
279 | /* mpeg_par_en = 0 */ | |
280 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
281 | /* mpeg_ser_en = 1 */ | |
282 | r18 |= PIN_MUX_MPEG_SER_EN_MASK; | |
283 | /* mpg_in_mux = 0 */ | |
284 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
285 | /* bt656_enable = 0 */ | |
286 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
287 | /* i2s_enable = 0 */ | |
288 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
289 | /* spi_mode = 0 */ | |
290 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
291 | /* mclk_en_ctrl = 1 */ | |
292 | r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; | |
293 | /* mperr_en_ctrl = 1 */ | |
294 | r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; | |
295 | /* mdval_en_ctrl = 1 */ | |
296 | r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; | |
297 | /* mpsyn_en_ctrl = 1 */ | |
298 | r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; | |
299 | /* mdat_en_ctrl[3:0] = 0xF */ | |
300 | r84 |= 0xF0; | |
301 | /* mdat_en_ctrl[7:4] = 0xF */ | |
302 | r89 |= 0xF0; | |
303 | break; | |
304 | case PIN_MUX_GPIO_MODE: | |
305 | /* mpeg_mode = 0 */ | |
306 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
307 | /* mpeg_par_en = 0 */ | |
308 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
309 | /* mpeg_ser_en = 0 */ | |
310 | r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; | |
311 | /* mpg_in_mux = 0 */ | |
312 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
313 | /* bt656_enable = 0 */ | |
314 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
315 | /* i2s_enable = 0 */ | |
316 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
317 | /* spi_mode = 0 */ | |
318 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
319 | /* mclk_en_ctrl = 0 */ | |
320 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
321 | /* mperr_en_ctrl = 0 */ | |
322 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
323 | /* mdval_en_ctrl = 0 */ | |
324 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
325 | /* mpsyn_en_ctrl = 0 */ | |
326 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
327 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
328 | r84 &= 0x0F; | |
329 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
330 | r89 &= 0x0F; | |
331 | break; | |
332 | case PIN_MUX_TS_SERIAL_IN_MODE_0: | |
333 | /* mpeg_mode = 0 */ | |
334 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
335 | /* mpeg_par_en = 0 */ | |
336 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
337 | /* mpeg_ser_en = 1 */ | |
338 | r18 |= PIN_MUX_MPEG_SER_EN_MASK; | |
339 | /* mpg_in_mux = 0 */ | |
340 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
341 | /* bt656_enable = 0 */ | |
342 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
343 | /* i2s_enable = 0 */ | |
344 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
345 | /* spi_mode = 0 */ | |
346 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
347 | /* mclk_en_ctrl = 0 */ | |
348 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
349 | /* mperr_en_ctrl = 0 */ | |
350 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
351 | /* mdval_en_ctrl = 0 */ | |
352 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
353 | /* mpsyn_en_ctrl = 0 */ | |
354 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
355 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
356 | r84 &= 0x0F; | |
357 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
358 | r89 &= 0x0F; | |
359 | break; | |
360 | case PIN_MUX_TS_SERIAL_IN_MODE_1: | |
361 | /* mpeg_mode = 0 */ | |
362 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
363 | /* mpeg_par_en = 0 */ | |
364 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
365 | /* mpeg_ser_en = 1 */ | |
366 | r18 |= PIN_MUX_MPEG_SER_EN_MASK; | |
367 | /* mpg_in_mux = 1 */ | |
368 | r3D |= PIN_MUX_MPG_IN_MUX_MASK; | |
369 | /* bt656_enable = 0 */ | |
370 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
371 | /* i2s_enable = 0 */ | |
372 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
373 | /* spi_mode = 0 */ | |
374 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
375 | /* mclk_en_ctrl = 0 */ | |
376 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
377 | /* mperr_en_ctrl = 0 */ | |
378 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
379 | /* mdval_en_ctrl = 0 */ | |
380 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
381 | /* mpsyn_en_ctrl = 0 */ | |
382 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
383 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
384 | r84 &= 0x0F; | |
385 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
386 | r89 &= 0x0F; | |
387 | break; | |
388 | case PIN_MUX_TS_SPI_IN_MODE_1: | |
389 | /* mpeg_mode = 0 */ | |
390 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
391 | /* mpeg_par_en = 0 */ | |
392 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
393 | /* mpeg_ser_en = 1 */ | |
394 | r18 |= PIN_MUX_MPEG_SER_EN_MASK; | |
395 | /* mpg_in_mux = 1 */ | |
396 | r3D |= PIN_MUX_MPG_IN_MUX_MASK; | |
397 | /* bt656_enable = 0 */ | |
398 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
399 | /* i2s_enable = 1 */ | |
400 | r15 |= PIN_MUX_I2S_ENABLE_MASK; | |
401 | /* spi_mode = 1 */ | |
402 | r3D |= PIN_MUX_SPI_MODE_MASK; | |
403 | /* mclk_en_ctrl = 0 */ | |
404 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
405 | /* mperr_en_ctrl = 0 */ | |
406 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
407 | /* mdval_en_ctrl = 0 */ | |
408 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
409 | /* mpsyn_en_ctrl = 0 */ | |
410 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
411 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
412 | r84 &= 0x0F; | |
413 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
414 | r89 &= 0x0F; | |
415 | break; | |
416 | case PIN_MUX_TS_SPI_IN_MODE_0: | |
417 | /* mpeg_mode = 0 */ | |
418 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
419 | /* mpeg_par_en = 0 */ | |
420 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
421 | /* mpeg_ser_en = 1 */ | |
422 | r18 |= PIN_MUX_MPEG_SER_EN_MASK; | |
423 | /* mpg_in_mux = 0 */ | |
424 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
425 | /* bt656_enable = 0 */ | |
426 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
427 | /* i2s_enable = 1 */ | |
428 | r15 |= PIN_MUX_I2S_ENABLE_MASK; | |
429 | /* spi_mode = 1 */ | |
430 | r3D |= PIN_MUX_SPI_MODE_MASK; | |
431 | /* mclk_en_ctrl = 0 */ | |
432 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
433 | /* mperr_en_ctrl = 0 */ | |
434 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
435 | /* mdval_en_ctrl = 0 */ | |
436 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
437 | /* mpsyn_en_ctrl = 0 */ | |
438 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
439 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
440 | r84 &= 0x0F; | |
441 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
442 | r89 &= 0x0F; | |
443 | break; | |
444 | case PIN_MUX_TS_PARALLEL_IN: | |
445 | /* mpeg_mode = 0 */ | |
446 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
447 | /* mpeg_par_en = 1 */ | |
448 | r18 |= PIN_MUX_MPEG_PAR_EN_MASK; | |
449 | /* mpeg_ser_en = 0 */ | |
450 | r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; | |
451 | /* mpg_in_mux = 0 */ | |
452 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
453 | /* bt656_enable = 0 */ | |
454 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
455 | /* i2s_enable = 0 */ | |
456 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
457 | /* spi_mode = 0 */ | |
458 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
459 | /* mclk_en_ctrl = 0 */ | |
460 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
461 | /* mperr_en_ctrl = 0 */ | |
462 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
463 | /* mdval_en_ctrl = 0 */ | |
464 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
465 | /* mpsyn_en_ctrl = 0 */ | |
466 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
467 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
468 | r84 &= 0x0F; | |
469 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
470 | r89 &= 0x0F; | |
471 | break; | |
472 | case PIN_MUX_BT656_I2S_MODE: | |
473 | /* mpeg_mode = 0 */ | |
474 | r17 &= ~PIN_MUX_MPEG_MODE_MASK; | |
475 | /* mpeg_par_en = 0 */ | |
476 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
477 | /* mpeg_ser_en = 0 */ | |
478 | r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; | |
479 | /* mpg_in_mux = 0 */ | |
480 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
481 | /* bt656_enable = 1 */ | |
482 | r12 |= PIN_MUX_BT656_ENABLE_MASK; | |
483 | /* i2s_enable = 1 */ | |
484 | r15 |= PIN_MUX_I2S_ENABLE_MASK; | |
485 | /* spi_mode = 0 */ | |
486 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
487 | /* mclk_en_ctrl = 0 */ | |
488 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
489 | /* mperr_en_ctrl = 0 */ | |
490 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
491 | /* mdval_en_ctrl = 0 */ | |
492 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
493 | /* mpsyn_en_ctrl = 0 */ | |
494 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
495 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
496 | r84 &= 0x0F; | |
497 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
498 | r89 &= 0x0F; | |
499 | break; | |
500 | case PIN_MUX_DEFAULT: | |
501 | default: | |
502 | /* mpeg_mode = 1 */ | |
503 | r17 |= PIN_MUX_MPEG_MODE_MASK; | |
504 | /* mpeg_par_en = 0 */ | |
505 | r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; | |
506 | /* mpeg_ser_en = 0 */ | |
507 | r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; | |
508 | /* mpg_in_mux = 0 */ | |
509 | r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; | |
510 | /* bt656_enable = 0 */ | |
511 | r12 &= ~PIN_MUX_BT656_ENABLE_MASK; | |
512 | /* i2s_enable = 0 */ | |
513 | r15 &= ~PIN_MUX_I2S_ENABLE_MASK; | |
514 | /* spi_mode = 0 */ | |
515 | r3D &= ~PIN_MUX_SPI_MODE_MASK; | |
516 | /* mclk_en_ctrl = 0 */ | |
517 | r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; | |
518 | /* mperr_en_ctrl = 0 */ | |
519 | r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; | |
520 | /* mdval_en_ctrl = 0 */ | |
521 | r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; | |
522 | /* mpsyn_en_ctrl = 0 */ | |
523 | r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; | |
524 | /* mdat_en_ctrl[3:0] = 0x0 */ | |
525 | r84 &= 0x0F; | |
526 | /* mdat_en_ctrl[7:4] = 0x0 */ | |
527 | r89 &= 0x0F; | |
528 | break; | |
529 | } | |
530 | ||
531 | ret = mxl111sf_write_reg(state, 0x17, r17); | |
532 | if (mxl_fail(ret)) | |
533 | goto fail; | |
534 | ret = mxl111sf_write_reg(state, 0x18, r18); | |
535 | if (mxl_fail(ret)) | |
536 | goto fail; | |
537 | ret = mxl111sf_write_reg(state, 0x12, r12); | |
538 | if (mxl_fail(ret)) | |
539 | goto fail; | |
540 | ret = mxl111sf_write_reg(state, 0x15, r15); | |
541 | if (mxl_fail(ret)) | |
542 | goto fail; | |
543 | ret = mxl111sf_write_reg(state, 0x82, r82); | |
544 | if (mxl_fail(ret)) | |
545 | goto fail; | |
546 | ret = mxl111sf_write_reg(state, 0x84, r84); | |
547 | if (mxl_fail(ret)) | |
548 | goto fail; | |
549 | ret = mxl111sf_write_reg(state, 0x89, r89); | |
550 | if (mxl_fail(ret)) | |
551 | goto fail; | |
552 | ret = mxl111sf_write_reg(state, 0x3D, r3D); | |
553 | if (mxl_fail(ret)) | |
554 | goto fail; | |
555 | fail: | |
556 | return ret; | |
557 | } | |
558 | ||
559 | /* ------------------------------------------------------------------------- */ | |
560 | ||
561 | static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val) | |
562 | { | |
563 | return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val); | |
564 | } | |
565 | ||
566 | static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state) | |
567 | { | |
568 | u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */ | |
569 | int i, ret; | |
570 | ||
571 | mxl_debug("()"); | |
572 | ||
573 | for (i = 3; i < 8; i++) { | |
574 | ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01); | |
575 | if (mxl_fail(ret)) | |
576 | break; | |
577 | } | |
578 | ||
579 | return ret; | |
580 | } | |
581 | ||
582 | #define PCA9534_I2C_ADDR (0x40 >> 1) | |
583 | static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val) | |
584 | { | |
585 | u8 w[2] = { 1, 0 }; | |
586 | u8 r = 0; | |
587 | struct i2c_msg msg[] = { | |
588 | { .addr = PCA9534_I2C_ADDR, | |
589 | .flags = 0, .buf = w, .len = 1 }, | |
590 | { .addr = PCA9534_I2C_ADDR, | |
591 | .flags = I2C_M_RD, .buf = &r, .len = 1 }, | |
592 | }; | |
593 | ||
594 | mxl_debug("(%d, %d)", gpio, val); | |
595 | ||
596 | /* read current GPIO levels from flip-flop */ | |
597 | i2c_transfer(&state->d->i2c_adap, msg, 2); | |
598 | ||
599 | /* prepare write buffer with current GPIO levels */ | |
600 | msg[0].len = 2; | |
601 | #if 0 | |
602 | w[0] = 1; | |
603 | #endif | |
604 | w[1] = r; | |
605 | ||
606 | /* clear the desired GPIO */ | |
607 | w[1] &= ~(1 << gpio); | |
608 | ||
609 | /* set the desired GPIO value */ | |
610 | w[1] |= ((val ? 1 : 0) << gpio); | |
611 | ||
612 | /* write new GPIO levels to flip-flop */ | |
613 | i2c_transfer(&state->d->i2c_adap, &msg[0], 1); | |
614 | ||
615 | return 0; | |
616 | } | |
617 | ||
618 | static int pca9534_init_port_expander(struct mxl111sf_state *state) | |
619 | { | |
620 | u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */ | |
621 | ||
622 | struct i2c_msg msg = { | |
623 | .addr = PCA9534_I2C_ADDR, | |
624 | .flags = 0, .buf = w, .len = 2 | |
625 | }; | |
626 | ||
627 | mxl_debug("()"); | |
628 | ||
629 | i2c_transfer(&state->d->i2c_adap, &msg, 1); | |
630 | ||
631 | /* configure all pins as outputs */ | |
632 | w[0] = 3; | |
633 | w[1] = 0; | |
634 | ||
635 | i2c_transfer(&state->d->i2c_adap, &msg, 1); | |
636 | ||
637 | return 0; | |
638 | } | |
639 | ||
640 | int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val) | |
641 | { | |
642 | mxl_debug("(%d, %d)", gpio, val); | |
643 | ||
644 | switch (state->gpio_port_expander) { | |
645 | default: | |
646 | mxl_printk(KERN_ERR, | |
647 | "gpio_port_expander undefined, assuming PCA9534"); | |
648 | /* fall-thru */ | |
649 | case mxl111sf_PCA9534: | |
650 | return pca9534_set_gpio(state, gpio, val); | |
651 | case mxl111sf_gpio_hw: | |
652 | return mxl111sf_hw_set_gpio(state, gpio, val); | |
653 | } | |
654 | } | |
655 | ||
656 | static int mxl111sf_probe_port_expander(struct mxl111sf_state *state) | |
657 | { | |
658 | int ret; | |
659 | u8 w = 1; | |
660 | u8 r = 0; | |
661 | struct i2c_msg msg[] = { | |
662 | { .flags = 0, .buf = &w, .len = 1 }, | |
663 | { .flags = I2C_M_RD, .buf = &r, .len = 1 }, | |
664 | }; | |
665 | ||
666 | mxl_debug("()"); | |
667 | ||
668 | msg[0].addr = 0x70 >> 1; | |
669 | msg[1].addr = 0x70 >> 1; | |
670 | ||
671 | /* read current GPIO levels from flip-flop */ | |
672 | ret = i2c_transfer(&state->d->i2c_adap, msg, 2); | |
673 | if (ret == 2) { | |
674 | state->port_expander_addr = msg[0].addr; | |
675 | state->gpio_port_expander = mxl111sf_PCA9534; | |
676 | mxl_debug("found port expander at 0x%02x", | |
677 | state->port_expander_addr); | |
678 | return 0; | |
679 | } | |
680 | ||
681 | msg[0].addr = 0x40 >> 1; | |
682 | msg[1].addr = 0x40 >> 1; | |
683 | ||
684 | ret = i2c_transfer(&state->d->i2c_adap, msg, 2); | |
685 | if (ret == 2) { | |
686 | state->port_expander_addr = msg[0].addr; | |
687 | state->gpio_port_expander = mxl111sf_PCA9534; | |
688 | mxl_debug("found port expander at 0x%02x", | |
689 | state->port_expander_addr); | |
690 | return 0; | |
691 | } | |
692 | state->port_expander_addr = 0xff; | |
693 | state->gpio_port_expander = mxl111sf_gpio_hw; | |
694 | mxl_debug("using hardware gpio"); | |
695 | return 0; | |
696 | } | |
697 | ||
698 | int mxl111sf_init_port_expander(struct mxl111sf_state *state) | |
699 | { | |
700 | mxl_debug("()"); | |
701 | ||
702 | if (0x00 == state->port_expander_addr) | |
703 | mxl111sf_probe_port_expander(state); | |
704 | ||
705 | switch (state->gpio_port_expander) { | |
706 | default: | |
707 | mxl_printk(KERN_ERR, | |
708 | "gpio_port_expander undefined, assuming PCA9534"); | |
709 | /* fall-thru */ | |
710 | case mxl111sf_PCA9534: | |
711 | return pca9534_init_port_expander(state); | |
712 | case mxl111sf_gpio_hw: | |
713 | return mxl111sf_hw_gpio_initialize(state); | |
714 | } | |
715 | } | |
716 | ||
717 | /* ------------------------------------------------------------------------ */ | |
718 | ||
719 | int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) | |
720 | { | |
721 | /* GPO: | |
722 | * 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0 | |
723 | * 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0 | |
724 | * 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0 | |
725 | * 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0 | |
726 | * 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0 | |
727 | */ | |
728 | mxl_debug("(%d)", mode); | |
729 | ||
730 | switch (mode) { | |
731 | case MXL111SF_GPIO_MOD_MH: | |
732 | mxl111sf_set_gpio(state, 4, 0); | |
733 | mxl111sf_set_gpio(state, 5, 0); | |
734 | msleep(50); | |
735 | mxl111sf_set_gpio(state, 7, 1); | |
736 | msleep(50); | |
737 | mxl111sf_set_gpio(state, 6, 1); | |
738 | msleep(50); | |
739 | ||
740 | mxl111sf_set_gpio(state, 3, 0); | |
741 | break; | |
742 | case MXL111SF_GPIO_MOD_ATSC: | |
743 | mxl111sf_set_gpio(state, 6, 0); | |
744 | mxl111sf_set_gpio(state, 7, 0); | |
745 | msleep(50); | |
746 | mxl111sf_set_gpio(state, 5, 1); | |
747 | msleep(50); | |
748 | mxl111sf_set_gpio(state, 4, 1); | |
749 | msleep(50); | |
750 | mxl111sf_set_gpio(state, 3, 1); | |
751 | break; | |
752 | default: /* DVBT / STANDBY */ | |
753 | mxl111sf_init_port_expander(state); | |
754 | break; | |
755 | } | |
756 | return 0; | |
757 | } |