|
@@ -25,6 +25,7 @@
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/videodev2.h>
|
|
#include <linux/videodev2.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
|
|
+#include <linux/workqueue.h>
|
|
#include <linux/dvb/frontend.h>
|
|
#include <linux/dvb/frontend.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/i2c.h>
|
|
|
|
|
|
@@ -65,12 +66,18 @@ struct xc5000_priv {
|
|
u16 pll_register_no;
|
|
u16 pll_register_no;
|
|
u8 init_status_supported;
|
|
u8 init_status_supported;
|
|
u8 fw_checksum_supported;
|
|
u8 fw_checksum_supported;
|
|
|
|
+
|
|
|
|
+ struct dvb_frontend *fe;
|
|
|
|
+ struct delayed_work timer_sleep;
|
|
};
|
|
};
|
|
|
|
|
|
/* Misc Defines */
|
|
/* Misc Defines */
|
|
#define MAX_TV_STANDARD 24
|
|
#define MAX_TV_STANDARD 24
|
|
#define XC_MAX_I2C_WRITE_LENGTH 64
|
|
#define XC_MAX_I2C_WRITE_LENGTH 64
|
|
|
|
|
|
|
|
+/* Time to suspend after the .sleep callback is called */
|
|
|
|
+#define XC5000_SLEEP_TIME 5000 /* ms */
|
|
|
|
+
|
|
/* Signal Types */
|
|
/* Signal Types */
|
|
#define XC_RF_MODE_AIR 0
|
|
#define XC_RF_MODE_AIR 0
|
|
#define XC_RF_MODE_CABLE 1
|
|
#define XC_RF_MODE_CABLE 1
|
|
@@ -1096,6 +1103,8 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
|
|
u16 pll_lock_status;
|
|
u16 pll_lock_status;
|
|
u16 fw_ck;
|
|
u16 fw_ck;
|
|
|
|
|
|
|
|
+ cancel_delayed_work(&priv->timer_sleep);
|
|
|
|
+
|
|
if (force || xc5000_is_firmware_loaded(fe) != 0) {
|
|
if (force || xc5000_is_firmware_loaded(fe) != 0) {
|
|
|
|
|
|
fw_retry:
|
|
fw_retry:
|
|
@@ -1164,27 +1173,39 @@ fw_retry:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-static int xc5000_sleep(struct dvb_frontend *fe)
|
|
|
|
|
|
+static void xc5000_do_timer_sleep(struct work_struct *timer_sleep)
|
|
{
|
|
{
|
|
|
|
+ struct xc5000_priv *priv =container_of(timer_sleep, struct xc5000_priv,
|
|
|
|
+ timer_sleep.work);
|
|
|
|
+ struct dvb_frontend *fe = priv->fe;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
dprintk(1, "%s()\n", __func__);
|
|
dprintk(1, "%s()\n", __func__);
|
|
|
|
|
|
- /* Avoid firmware reload on slow devices */
|
|
|
|
- if (no_poweroff)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
/* According to Xceive technical support, the "powerdown" register
|
|
/* According to Xceive technical support, the "powerdown" register
|
|
was removed in newer versions of the firmware. The "supported"
|
|
was removed in newer versions of the firmware. The "supported"
|
|
way to sleep the tuner is to pull the reset pin low for 10ms */
|
|
way to sleep the tuner is to pull the reset pin low for 10ms */
|
|
ret = xc5000_tuner_reset(fe);
|
|
ret = xc5000_tuner_reset(fe);
|
|
- if (ret != 0) {
|
|
|
|
|
|
+ if (ret != 0)
|
|
printk(KERN_ERR
|
|
printk(KERN_ERR
|
|
"xc5000: %s() unable to shutdown tuner\n",
|
|
"xc5000: %s() unable to shutdown tuner\n",
|
|
__func__);
|
|
__func__);
|
|
- return -EREMOTEIO;
|
|
|
|
- } else
|
|
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int xc5000_sleep(struct dvb_frontend *fe)
|
|
|
|
+{
|
|
|
|
+ struct xc5000_priv *priv = fe->tuner_priv;
|
|
|
|
+
|
|
|
|
+ dprintk(1, "%s()\n", __func__);
|
|
|
|
+
|
|
|
|
+ /* Avoid firmware reload on slow devices */
|
|
|
|
+ if (no_poweroff)
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+ schedule_delayed_work(&priv->timer_sleep,
|
|
|
|
+ msecs_to_jiffies(XC5000_SLEEP_TIME));
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int xc5000_init(struct dvb_frontend *fe)
|
|
static int xc5000_init(struct dvb_frontend *fe)
|
|
@@ -1211,8 +1232,10 @@ static int xc5000_release(struct dvb_frontend *fe)
|
|
|
|
|
|
mutex_lock(&xc5000_list_mutex);
|
|
mutex_lock(&xc5000_list_mutex);
|
|
|
|
|
|
- if (priv)
|
|
|
|
|
|
+ if (priv) {
|
|
|
|
+ cancel_delayed_work(&priv->timer_sleep);
|
|
hybrid_tuner_release_state(priv);
|
|
hybrid_tuner_release_state(priv);
|
|
|
|
+ }
|
|
|
|
|
|
mutex_unlock(&xc5000_list_mutex);
|
|
mutex_unlock(&xc5000_list_mutex);
|
|
|
|
|
|
@@ -1284,6 +1307,8 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
|
/* new tuner instance */
|
|
/* new tuner instance */
|
|
priv->bandwidth = 6000000;
|
|
priv->bandwidth = 6000000;
|
|
fe->tuner_priv = priv;
|
|
fe->tuner_priv = priv;
|
|
|
|
+ priv->fe = fe;
|
|
|
|
+ INIT_DELAYED_WORK(&priv->timer_sleep, xc5000_do_timer_sleep);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
/* existing tuner instance */
|
|
/* existing tuner instance */
|