brintos

brintos / linux-shallow public Read only

0
0
Text · 18.8 KiB · ef489c5 Raw
745 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  mxl111sf-gpio.c - driver for the MaxLinear MXL111SF4 *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 0x8415#define MXL_GPIO_MUX_REG_1 0x8916#define MXL_GPIO_MUX_REG_2 0x8217 18#define MXL_GPIO_DIR_INPUT  019#define MXL_GPIO_DIR_OUTPUT 120 21 22static 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, 0x19, &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, 0x19, 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, 0x30, &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, 0x30, tmp);47		if (mxl_fail(ret))48			goto fail;49	} else50		ret = -EINVAL;51fail:52	return ret;53}54 55static 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, 0x23, &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, 0x2f, &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, 0x22, &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	}94fail:95	return ret;96}97 98struct mxl_gpio_cfg {99	u8 pin;100	u8 dir;101	u8 val;102};103 104static 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, &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, 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, &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, 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, &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, 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				       gpio_cfg->pin, gpio_cfg->val) :158		mxl111sf_get_gpi_state(state,159				       gpio_cfg->pin, &gpio_cfg->val);160	mxl_fail(ret);161fail:162	return ret;163}164 165static 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_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 201int 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, 0x17, &r17);210	if (mxl_fail(ret))211		goto fail;212	ret = mxl111sf_read_reg(state, 0x18, &r18);213	if (mxl_fail(ret))214		goto fail;215	ret = mxl111sf_read_reg(state, 0x12, &r12);216	if (mxl_fail(ret))217		goto fail;218	ret = mxl111sf_read_reg(state, 0x15, &r15);219	if (mxl_fail(ret))220		goto fail;221	ret = mxl111sf_read_reg(state, 0x82, &r82);222	if (mxl_fail(ret))223		goto fail;224	ret = mxl111sf_read_reg(state, 0x84, &r84);225	if (mxl_fail(ret))226		goto fail;227	ret = mxl111sf_read_reg(state, 0x89, &r89);228	if (mxl_fail(ret))229		goto fail;230	ret = mxl111sf_read_reg(state, 0x3D, &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, 0x17, r17);519	if (mxl_fail(ret))520		goto fail;521	ret = mxl111sf_write_reg(state, 0x18, r18);522	if (mxl_fail(ret))523		goto fail;524	ret = mxl111sf_write_reg(state, 0x12, r12);525	if (mxl_fail(ret))526		goto fail;527	ret = mxl111sf_write_reg(state, 0x15, r15);528	if (mxl_fail(ret))529		goto fail;530	ret = mxl111sf_write_reg(state, 0x82, r82);531	if (mxl_fail(ret))532		goto fail;533	ret = mxl111sf_write_reg(state, 0x84, r84);534	if (mxl_fail(ret))535		goto fail;536	ret = mxl111sf_write_reg(state, 0x89, r89);537	if (mxl_fail(ret))538		goto fail;539	ret = mxl111sf_write_reg(state, 0x3D, r3D);540	if (mxl_fail(ret))541		goto fail;542fail:543	return ret;544}545 546/* ------------------------------------------------------------------------- */547 548static 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 553static 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, i, (gpioval >> i) & 0x01);562		if (mxl_fail(ret))563			break;564	}565 566	return ret;567}568 569#define PCA9534_I2C_ADDR (0x40 >> 1)570static 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(&state->d->i2c_adap, msg, 2);585 586	/* prepare write buffer with current GPIO levels */587	msg[0].len = 2;588#if 0589	w[0] = 1;590#endif591	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(&state->d->i2c_adap, &msg[0], 1);601 602	return 0;603}604 605static 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 = 2612	};613 614	mxl_debug("()");615 616	i2c_transfer(&state->d->i2c_adap, &msg, 1);617 618	/* configure all pins as outputs */619	w[0] = 3;620	w[1] = 0;621 622	i2c_transfer(&state->d->i2c_adap, &msg, 1);623 624	return 0;625}626 627int 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 643static 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(&state->d->i2c_adap, msg, 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(&state->d->i2c_adap, msg, 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 685int 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 706int 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 0710 *	4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset           | default 0711 *	5 - ATSC_EN    | 1 = ATSC power enable, 0 = ATSC power off | default 0712 *	6 - MH_RESET#  | 1 = MH enable, 0 = MH Reset               | default 0713 *	7 - MH_EN      | 1 = MH power enable, 0 = MH power off     | default 0714 */715	mxl_debug("(%d)", mode);716 717	switch (mode) {718	case MXL111SF_GPIO_MOD_MH:719		mxl111sf_set_gpio(state, 4, 0);720		mxl111sf_set_gpio(state, 5, 0);721		msleep(50);722		mxl111sf_set_gpio(state, 7, 1);723		msleep(50);724		mxl111sf_set_gpio(state, 6, 1);725		msleep(50);726 727		mxl111sf_set_gpio(state, 3, 0);728		break;729	case MXL111SF_GPIO_MOD_ATSC:730		mxl111sf_set_gpio(state, 6, 0);731		mxl111sf_set_gpio(state, 7, 0);732		msleep(50);733		mxl111sf_set_gpio(state, 5, 1);734		msleep(50);735		mxl111sf_set_gpio(state, 4, 1);736		msleep(50);737		mxl111sf_set_gpio(state, 3, 1);738		break;739	default: /* DVBT / STANDBY */740		mxl111sf_init_port_expander(state);741		break;742	}743	return 0;744}745