aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/mn88472/mn88472.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/mn88472/mn88472.c')
-rw-r--r--drivers/staging/media/mn88472/mn88472.c95
1 files changed, 82 insertions, 13 deletions
diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c
index 6eebe564e557..a4cfcf57c99c 100644
--- a/drivers/staging/media/mn88472/mn88472.c
+++ b/drivers/staging/media/mn88472/mn88472.c
@@ -19,7 +19,7 @@
static int mn88472_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
- s->min_delay_ms = 400;
+ s->min_delay_ms = 800;
return 0;
}
@@ -178,8 +178,32 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
ret = regmap_write(dev->regmap[0], 0x46, 0x00);
ret = regmap_write(dev->regmap[0], 0xae, 0x00);
- ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
- ret = regmap_write(dev->regmap[0], 0xd9, 0xe3);
+
+ switch (dev->ts_mode) {
+ case SERIAL_TS_MODE:
+ ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
+ break;
+ case PARALLEL_TS_MODE:
+ ret = regmap_write(dev->regmap[2], 0x08, 0x00);
+ break;
+ default:
+ dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ switch (dev->ts_clock) {
+ case VARIABLE_TS_CLOCK:
+ ret = regmap_write(dev->regmap[0], 0xd9, 0xe3);
+ break;
+ case FIXED_TS_CLOCK:
+ ret = regmap_write(dev->regmap[0], 0xd9, 0xe1);
+ break;
+ default:
+ dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock);
+ ret = -EINVAL;
+ goto err;
+ }
/* Reset demod */
ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
@@ -201,6 +225,7 @@ static int mn88472_read_status(struct dvb_frontend *fe, fe_status_t *status)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
unsigned int utmp;
+ int lock = 0;
*status = 0;
@@ -211,21 +236,36 @@ static int mn88472_read_status(struct dvb_frontend *fe, fe_status_t *status)
switch (c->delivery_system) {
case SYS_DVBT:
+ ret = regmap_read(dev->regmap[0], 0x7F, &utmp);
+ if (ret)
+ goto err;
+ if ((utmp & 0xF) >= 0x09)
+ lock = 1;
+ break;
case SYS_DVBT2:
- /* FIXME: implement me */
- utmp = 0x08; /* DVB-C lock value */
+ ret = regmap_read(dev->regmap[2], 0x92, &utmp);
+ if (ret)
+ goto err;
+ if ((utmp & 0xF) >= 0x07)
+ *status |= FE_HAS_SIGNAL;
+ if ((utmp & 0xF) >= 0x0a)
+ *status |= FE_HAS_CARRIER;
+ if ((utmp & 0xF) >= 0x0d)
+ *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
break;
case SYS_DVBC_ANNEX_A:
ret = regmap_read(dev->regmap[1], 0x84, &utmp);
if (ret)
goto err;
+ if ((utmp & 0xF) >= 0x08)
+ lock = 1;
break;
default:
ret = -EINVAL;
goto err;
}
- if (utmp == 0x08)
+ if (lock)
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
FE_HAS_SYNC | FE_HAS_LOCK;
@@ -242,6 +282,7 @@ static int mn88472_init(struct dvb_frontend *fe)
int ret, len, remaining;
const struct firmware *fw = NULL;
u8 *fw_file = MN88472_FIRMWARE;
+ unsigned int tmp;
dev_dbg(&client->dev, "\n");
@@ -257,6 +298,17 @@ static int mn88472_init(struct dvb_frontend *fe)
if (ret)
goto err;
+ /* check if firmware is already running */
+ ret = regmap_read(dev->regmap[0], 0xf5, &tmp);
+ if (ret)
+ goto err;
+
+ if (!(tmp & 0x1)) {
+ dev_info(&client->dev, "firmware already running\n");
+ dev->warm = true;
+ return 0;
+ }
+
/* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, &client->dev);
if (ret) {
@@ -270,26 +322,40 @@ static int mn88472_init(struct dvb_frontend *fe)
ret = regmap_write(dev->regmap[0], 0xf5, 0x03);
if (ret)
- goto err;
+ goto firmware_release;
for (remaining = fw->size; remaining > 0;
remaining -= (dev->i2c_wr_max - 1)) {
len = remaining;
if (len > (dev->i2c_wr_max - 1))
- len = (dev->i2c_wr_max - 1);
+ len = dev->i2c_wr_max - 1;
ret = regmap_bulk_write(dev->regmap[0], 0xf6,
&fw->data[fw->size - remaining], len);
if (ret) {
dev_err(&client->dev,
"firmware download failed=%d\n", ret);
- goto err;
+ goto firmware_release;
}
}
+ /* parity check of firmware */
+ ret = regmap_read(dev->regmap[0], 0xf8, &tmp);
+ if (ret) {
+ dev_err(&client->dev,
+ "parity reg read failed=%d\n", ret);
+ goto err;
+ }
+ if (tmp & 0x10) {
+ dev_err(&client->dev,
+ "firmware parity check failed=0x%x\n", tmp);
+ goto err;
+ }
+ dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp);
+
ret = regmap_write(dev->regmap[0], 0xf5, 0x00);
if (ret)
- goto err;
+ goto firmware_release;
release_firmware(fw);
fw = NULL;
@@ -298,10 +364,9 @@ static int mn88472_init(struct dvb_frontend *fe)
dev->warm = true;
return 0;
+firmware_release:
+ release_firmware(fw);
err:
- if (fw)
- release_firmware(fw);
-
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
@@ -336,6 +401,8 @@ static struct dvb_frontend_ops mn88472_ops = {
.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
.info = {
.name = "Panasonic MN88472",
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 7200000,
.caps = FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
@@ -396,6 +463,8 @@ static int mn88472_probe(struct i2c_client *client,
dev->i2c_wr_max = config->i2c_wr_max;
dev->xtal = config->xtal;
+ dev->ts_mode = config->ts_mode;
+ dev->ts_clock = config->ts_clock;
dev->client[0] = client;
dev->regmap[0] = regmap_init_i2c(dev->client[0], &regmap_config);
if (IS_ERR(dev->regmap[0])) {