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