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