#define AF901x_GETFIELD(bitf, val) ((val >> AF901x_OFFST_##bitf) & \ ((1 << AF901x_WIDTH_##bitf) - 1)) #define AF901x_SETFIELD(bitf, mask, val)(mask = (mask & (~(((1 << AF901x_WIDTH_##bitf) - 1)<< \ AF901x_OFFST_##bitf))) | (val << AF901x_OFFST_##bitf)) #define AF901x_BYPASS_HOST2TUNER 0xd607 #define AF901x_WIDTH_BYPASS_HOST2TUNER 1 #define AF901x_OFFST_BYPASS_HOST2TUNER 2 #define AF901x_I2CREG_SEL_TUNER 0xd417 #define AF901x_WIDTH_I2CREG_SEL_TUNER 1 #define AF901x_OFFST_I2CREG_SEL_TUNER 3 /** * NOTE! What we do here is not a simple Tuner I2C Bus enable/disable ! * What's performed here is a 2 way switch kind of operation where * the bus is switched between the demodulator and the tuner * * Of course we have a workaround (we have to), the enable bit can be * used for enabling the tuner, which means the demodulator is disabled. * * A case where we get totally confused is when we have MASTER/SLAVE * combinations * * The worst problem that we can have here: once we switch the * tuner bypass ON and expecting an error and the transaction aborts, * The driver expects the device to be communicating to the demodulator, * but in reality we are talking to the tuner in fact. * * A workaround for this would be to cache the gate switched state * into the device state structure, whereby a possible operation * returned success state is used to switch the gate status back to the * original position, such that normal communication can continue with * the demodulator. * * But with all these workarounds don't we look ugly ? Any better ways * of accomplishing this ? */ static int af901x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { u8 reg; if (slave) { /** * Additionally, we need to tell the BCU that we are * talking to the SLAVE, How ? */ af901x_read_reg(state, AF901x_BYPASS_HOST2TUNER, ®); if (enable) reg = AF901x_SETFIELD(BYPASS_HOST2TUNER, reg, 1); else reg = AF901x_SETFIELD(BYPASS_HOST2TUNER, reg, 0); /** * Additionally, we need to tell the BCU that we are * talking to the SLAVE, How ? */ af901x_write_reg(state, AF901x_BYPASS_HOST2TUNER, reg); } else { /** * Additionally, we need to tell the BCU that we are * talking to the MASTER, How ? */ af901x_read_reg(state, AF901x_I2CREG_SEL_TUNER, ®); if (enable) reg = AF901x_GETFIELD(I2CREG_SEL_TUNER, reg, 1); else reg = AF901x_GETFIELD(I2CREG_SEL_TUNER, reg, 0); /** * Additionally, we need to tell the BCU that we are * talking to the MASTER, How ? */ af901x_write_reg(state, AF901x_I2CREG_SEL_TUNER, reg); } return 0; }