Add set LNB tone support.
Test:
dvbtune -s dvbs2 -i 1110000 -r 30000 -m psk8 -p h
SPACECAST2# i2cget -y 0 0x60 0
0x9c
dvbtune -s dvbs2 -i 1110000 -r 30000 -m psk8 -p v
SPACECAST2# i2cget -y 0 0x60 0
0x98
dvbtune -s dvbs2 -i 1110000 -r 30000 -m psk8 -p h
SPACECAST2# i2cget -y 0 0x60 0
0x90
dvbtune -s dvbs2 -i 1110000 -r 30000 -m psk8 -t
SPACECAST2# i2cget -y 0 0x60 0
0xb0
Google-Bug-Id: 19432272
Change-Id: Ibbc11ce2de4626e0014263a058557024eb6f9452
diff --git a/drivers/media/dvb/dvb-usb/sc100.c b/drivers/media/dvb/dvb-usb/sc100.c
index 82aad08..2905f27 100644
--- a/drivers/media/dvb/dvb-usb/sc100.c
+++ b/drivers/media/dvb/dvb-usb/sc100.c
@@ -13,7 +13,6 @@
#include "dvbsky_m88rs6000.h"
#include "mach/comcerto-2000.h"
-#define SC100_VOLTAGE_CTRL (0x60)
#define SC100_READ_MSG 0
#define SC100_WRITE_MSG 1
#define SC100_MAC_ADDR_INDEX 1
@@ -25,37 +24,141 @@
/* debug */
static int dvb_usb_sc100_debug;
module_param_named(debug, dvb_usb_sc100_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
- DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info)." DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+/* Control register for LNP settings
+ * B7: I2C Control
+ * 1 - enabled, 0 - disabled
+ * B6: Reserved
+ * B5: Tone Gate
+ * 1 - on, 0 - off
+ * B4: Tone Mode
+ * 1 - internal, 0 - external
+ * B3: LNP output voltage
+ * 1 - enabled, 0 - disabled
+ * B2-1: Output voltage selection
+ * 0 - 13V, 4 - 18V
+ */
+#define LNB_I2C_ADDRESS (0x60)
+#define LNB_CONTROL_REGISTER_1 (0x00)
+#define LNB_CONTROL_REGISTER_1_I2C_CONTROL_MASK (0x80)
+#define LNB_CONTROL_REGISTER_1_I2C_CONTROL_SHIFT (0x07)
+#define LNB_CONTROL_REGISTER_1_I2C_CONTROL_ENABLED (0x01)
+#define LNB_CONTROL_REGISTER_1_I2C_CONTROL_DISABLED (0x00)
+#define LNB_CONTROL_REGISTER_1_TONE_GATE_MASK (0x20)
+#define LNB_CONTROL_REGISTER_1_TONE_GATE_SHIFT (0x05)
+#define LNB_CONTROL_REGISTER_1_TONE_GATE_ON (0x01)
+#define LNB_CONTROL_REGISTER_1_TONE_GATE_OFF (0x00)
+#define LNB_CONTROL_REGISTER_1_TONE_MODE_MASK (0x10)
+#define LNB_CONTROL_REGISTER_1_TONE_MODE_SHIFT (0x4)
+#define LNB_CONTROL_REGISTER_1_TONE_MODE_INTERNAL (0x01)
+#define LNB_CONTROL_REGISTER_1_TONE_MODE_EXTERNAL (0x00)
+#define LNB_CONTROL_REGISTER_1_LNB_OUTPUT_VOLTAGE_MASK (0x08)
+#define LNB_CONTROL_REGISTER_1_LNB_OUTPUT_VOLTAGE_SHIFT (0x03)
+#define LNB_CONTROL_REGISTER_1_LNB_OUTPUT_VOLTAGE_ON (0x01)
+#define LNB_CONTROL_REGISTER_1_LNB_OUTPUT_VOLTAGE_OFF 0x00
+#define LNB_CONTROL_REGISTER_1_LNB_VOLTAGE_SELECTION_MASK 0x07
+#define LNB_CONTROL_REGISTER_1_LNB_VOLTAGE_SELECTION_SHIFT 0x00
+#define LNB_CONTROL_REGISTER_1_LNB_VOLTAGE_SELECTION_13V 0x00
+#define LNB_CONTROL_REGISTER_1_LNB_VOLTAGE_SELECTION_18V 0x04
+#define LNB_FIELD_SET(data, field, value) \
+{ \
+ data &= ~(LNB_CONTROL_REGISTER_1_ ## field ## _MASK); \
+ data |= LNB_CONTROL_REGISTER_1_ ## field ## _ ## value \
+ << (LNB_CONTROL_REGISTER_1_ ## field ## _ ## SHIFT); \
+}
+
+struct i2c_adapter *i2c_adap;
+
static int sc100_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
{
return comcerto_mac_addr_get(mac, SC100_MAC_ADDR_INDEX);
};
+static int sc100_writereg(u8 reg, u8 data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = { .addr = LNB_I2C_ADDRESS,
+ .flags = 0, .buf = buf, .len = 2 };
+ int ret;
+
+ deb_info("%s: [W] R:0x%02x, V:0x%02x", __func__, reg, data);
+
+ ret = i2c_transfer(i2c_adap, &msg, 1);
+ if (ret != 1) {
+ err("%s: [W] R:0x%02x, V:0x02x, E:%d", __func__, reg, data, ret);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static u8 sc100_readreg(u8 reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ { .addr = LNB_I2C_ADDRESS, .flags = 0, .buf = b0, .len = 1 },
+ { .addr = LNB_I2C_ADDRESS, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+ };
+ ret = i2c_transfer(i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ err("%s: [R] R:0x%x, E:%d", __func__, reg, ret);
+ return ret;
+ }
+ deb_info("%s: [R] R:0x%02x, V:0x%02x", __func__, reg, b1[0]);
+
+ return b1[0];
+}
+
+static int sc100_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ u8 lnb_reg = sc100_readreg(LNB_CONTROL_REGISTER_1);
+ switch (tone) {
+ case SEC_TONE_ON:
+ info("%s: LNB TONE=ON\n", __func__);
+ LNB_FIELD_SET(lnb_reg, I2C_CONTROL, ENABLED);
+ LNB_FIELD_SET(lnb_reg, TONE_GATE, ON);
+ LNB_FIELD_SET(lnb_reg, TONE_MODE, INTERNAL);
+ break;
+ case SEC_TONE_OFF:
+ info("%s: LNB TONE=OFF\n", __func__);
+ LNB_FIELD_SET(lnb_reg, I2C_CONTROL, ENABLED);
+ LNB_FIELD_SET(lnb_reg, TONE_GATE, OFF);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return sc100_writereg(LNB_CONTROL_REGISTER_1, lnb_reg);
+}
+
static int sc100_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- static u8 command_13v[] = {0x00, 0x88};
- static u8 command_18v[] = {0x00, 0x8c};
- static u8 command_off[] = {0x00, 0x80};
- struct i2c_msg msg = {
- .addr = SC100_VOLTAGE_CTRL,
- .flags = 0,
- .buf = command_off,
- .len = 2,
- };
- struct i2c_adapter *i2c_adap = i2c_get_adapter(0);
-
- if (voltage == SEC_VOLTAGE_18)
- msg.buf = command_18v;
- else if (voltage == SEC_VOLTAGE_13)
- msg.buf = command_13v;
-
- i2c_transfer(i2c_adap, &msg, 1);
-
- return 0;
+ u8 lnb_reg = sc100_readreg(LNB_CONTROL_REGISTER_1);
+ switch (voltage) {
+ case SEC_VOLTAGE_18:
+ info("%s: LNB VOLTAGE=18V\n", __func__);
+ LNB_FIELD_SET(lnb_reg, I2C_CONTROL, ENABLED);
+ LNB_FIELD_SET(lnb_reg, LNB_OUTPUT_VOLTAGE, ON);
+ LNB_FIELD_SET(lnb_reg, LNB_VOLTAGE_SELECTION, 18V);
+ break;
+ case SEC_VOLTAGE_13:
+ info("%s: LNB VOLTAGE=13V\n", __func__);
+ LNB_FIELD_SET(lnb_reg, I2C_CONTROL, ENABLED);
+ LNB_FIELD_SET(lnb_reg, LNB_OUTPUT_VOLTAGE, ON);
+ LNB_FIELD_SET(lnb_reg, LNB_VOLTAGE_SELECTION, 13V);
+ break;
+ default:
+ info("%s: LNB VOLTAGE=OFF\n", __func__);
+ LNB_FIELD_SET(lnb_reg, I2C_CONTROL, ENABLED);
+ LNB_FIELD_SET(lnb_reg, LNB_OUTPUT_VOLTAGE, OFF);
+ break;
+ }
+ return sc100_writereg(LNB_CONTROL_REGISTER_1, lnb_reg);
}
static struct dvbsky_m88rs6000_config sc100_config = {
@@ -70,10 +173,12 @@
static int sc100_frontend_attach(struct dvb_usb_adapter *d)
{
- struct i2c_adapter *i2c_adap = i2c_get_adapter(0);
+ /* Initializes i2c adapter when the frontend is attached. */
+ i2c_adap = i2c_get_adapter(0);
d->fe_adap[0].fe = dvb_attach(dvbsky_m88rs6000_attach, &sc100_config,
i2c_adap);
if (d->fe_adap[0].fe != NULL) {
+ d->fe_adap[0].fe->ops.set_tone = sc100_set_tone;
d->fe_adap[0].fe->ops.set_voltage = sc100_set_voltage;
info("Attached SC100!\n");
return 0;
diff --git a/drivers/media/dvb/dvb-usb/sc100.h b/drivers/media/dvb/dvb-usb/sc100.h
index 083397b..fbc229b 100644
--- a/drivers/media/dvb/dvb-usb/sc100.h
+++ b/drivers/media/dvb/dvb-usb/sc100.h
@@ -4,6 +4,5 @@
#define DVB_USB_LOG_PREFIX "sc100"
#include "dvb-usb.h"
-#define deb_xfer(args...) dprintk(dvb_usb_sc100_debug, 0x02, args)
-#define deb_rc(args...) dprintk(dvb_usb_sc100_debug, 0x04, args)
+#define deb_info(args...) dprintk(dvb_usb_sc100_debug, 0x01, args)
#endif
diff --git a/drivers/media/dvb/frontends/dvbsky_m88rs6000.c b/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
index 954c914..d3fbdcc 100644
--- a/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
+++ b/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
@@ -610,6 +610,9 @@
return -EINVAL;
}
+ if(state->config->set_tone)
+ state->config->set_tone(fe, tone);
+
data_a1 = m88rs6000_readreg(state, 0xa1);
data_a2 = m88rs6000_readreg(state, 0xa2);
diff --git a/drivers/media/dvb/frontends/dvbsky_m88rs6000.h b/drivers/media/dvb/frontends/dvbsky_m88rs6000.h
index f433519..e7e7f53 100644
--- a/drivers/media/dvb/frontends/dvbsky_m88rs6000.h
+++ b/drivers/media/dvb/frontends/dvbsky_m88rs6000.h
@@ -18,6 +18,8 @@
u8 tuner_readstops;
/* Set device param to start dma */
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+ /* Set LNB tone */
+ int (*set_tone)(struct dvb_frontend *fe, const fe_sec_tone_mode_t t);
/* Set LNB voltage */
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
};