1/*
2 *  mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
3 *
4 *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
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
35static 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;
64fail:
65	return ret;
66}
67
68static 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	}
107fail:
108	return ret;
109}
110
111struct mxl_gpio_cfg {
112	u8 pin;
113	u8 dir;
114	u8 val;
115};
116
117static 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);
174fail:
175	return ret;
176}
177
178static 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
214int 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;
555fail:
556	return ret;
557}
558
559/* ------------------------------------------------------------------------- */
560
561static 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
566static 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)
583static 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
618static 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
640int 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
656static 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
698int 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
719int 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}
758
759/*
760 * Local variables:
761 * c-basic-offset: 8
762 * End:
763 */
764