These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / media / dvb-frontends / si2168.c
index 5db588e..821a8f4 100644 (file)
 
 static const struct dvb_frontend_ops si2168_ops;
 
+/* Own I2C adapter locking is needed because of I2C gate logic. */
+static int si2168_i2c_master_send_unlocked(const struct i2c_client *client,
+                                          const char *buf, int count)
+{
+       int ret;
+       struct i2c_msg msg = {
+               .addr = client->addr,
+               .flags = 0,
+               .len = count,
+               .buf = (char *)buf,
+       };
+
+       ret = __i2c_transfer(client->adapter, &msg, 1);
+       return (ret == 1) ? count : ret;
+}
+
+static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client,
+                                          char *buf, int count)
+{
+       int ret;
+       struct i2c_msg msg = {
+               .addr = client->addr,
+               .flags = I2C_M_RD,
+               .len = count,
+               .buf = buf,
+       };
+
+       ret = __i2c_transfer(client->adapter, &msg, 1);
+       return (ret == 1) ? count : ret;
+}
+
 /* execute firmware command */
-static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
+static int si2168_cmd_execute_unlocked(struct i2c_client *client,
+                                      struct si2168_cmd *cmd)
 {
-       struct si2168_dev *dev = i2c_get_clientdata(client);
        int ret;
        unsigned long timeout;
 
-       mutex_lock(&dev->i2c_mutex);
-
        if (cmd->wlen) {
                /* write cmd and args for firmware */
-               ret = i2c_master_send(client, cmd->args, cmd->wlen);
+               ret = si2168_i2c_master_send_unlocked(client, cmd->args,
+                                                     cmd->wlen);
                if (ret < 0) {
-                       goto err_mutex_unlock;
+                       goto err;
                } else if (ret != cmd->wlen) {
                        ret = -EREMOTEIO;
-                       goto err_mutex_unlock;
+                       goto err;
                }
        }
 
@@ -43,12 +73,13 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
                #define TIMEOUT 70
                timeout = jiffies + msecs_to_jiffies(TIMEOUT);
                while (!time_after(jiffies, timeout)) {
-                       ret = i2c_master_recv(client, cmd->args, cmd->rlen);
+                       ret = si2168_i2c_master_recv_unlocked(client, cmd->args,
+                                                             cmd->rlen);
                        if (ret < 0) {
-                               goto err_mutex_unlock;
+                               goto err;
                        } else if (ret != cmd->rlen) {
                                ret = -EREMOTEIO;
-                               goto err_mutex_unlock;
+                               goto err;
                        }
 
                        /* firmware ready? */
@@ -60,22 +91,36 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
                                jiffies_to_msecs(jiffies) -
                                (jiffies_to_msecs(timeout) - TIMEOUT));
 
+               /* error bit set? */
+               if ((cmd->args[0] >> 6) & 0x01) {
+                       ret = -EREMOTEIO;
+                       goto err;
+               }
+
                if (!((cmd->args[0] >> 7) & 0x01)) {
                        ret = -ETIMEDOUT;
-                       goto err_mutex_unlock;
+                       goto err;
                }
        }
 
-       mutex_unlock(&dev->i2c_mutex);
        return 0;
-
-err_mutex_unlock:
-       mutex_unlock(&dev->i2c_mutex);
+err:
        dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
-static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
+static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
+{
+       int ret;
+
+       i2c_lock_adapter(client->adapter);
+       ret = si2168_cmd_execute_unlocked(client, cmd);
+       i2c_unlock_adapter(client->adapter);
+
+       return ret;
+}
+
+static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
        struct i2c_client *client = fe->demodulator_priv;
        struct si2168_dev *dev = i2c_get_clientdata(client);
@@ -457,6 +502,10 @@ static int si2168_init(struct dvb_frontend *fe)
                /* firmware is in the new format */
                for (remaining = fw->size; remaining > 0; remaining -= 17) {
                        len = fw->data[fw->size - remaining];
+                       if (len > SI2168_ARGLEN) {
+                               ret = -EINVAL;
+                               break;
+                       }
                        memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
                        cmd.wlen = len;
                        cmd.rlen = 1;
@@ -508,6 +557,8 @@ static int si2168_init(struct dvb_frontend *fe)
        /* set ts mode */
        memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
        cmd.args[4] |= dev->ts_mode;
+       if (dev->ts_clock_gapped)
+               cmd.args[4] |= 0x40;
        cmd.wlen = 6;
        cmd.rlen = 4;
        ret = si2168_cmd_execute(client, &cmd);
@@ -561,60 +612,46 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
 
 /*
  * I2C gate logic
- * We must use unlocked i2c_transfer() here because I2C lock is already taken
- * by tuner driver.
+ * We must use unlocked I2C I/O because I2C adapter lock is already taken
+ * by the caller (usually tuner driver).
  */
 static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 {
        struct i2c_client *client = mux_priv;
-       struct si2168_dev *dev = i2c_get_clientdata(client);
        int ret;
-       struct i2c_msg gate_open_msg = {
-               .addr = client->addr,
-               .flags = 0,
-               .len = 3,
-               .buf = "\xc0\x0d\x01",
-       };
-
-       mutex_lock(&dev->i2c_mutex);
+       struct si2168_cmd cmd;
 
-       /* open tuner I2C gate */
-       ret = __i2c_transfer(client->adapter, &gate_open_msg, 1);
-       if (ret != 1) {
-               dev_warn(&client->dev, "i2c write failed=%d\n", ret);
-               if (ret >= 0)
-                       ret = -EREMOTEIO;
-       } else {
-               ret = 0;
-       }
+       /* open I2C gate */
+       memcpy(cmd.args, "\xc0\x0d\x01", 3);
+       cmd.wlen = 3;
+       cmd.rlen = 0;
+       ret = si2168_cmd_execute_unlocked(client, &cmd);
+       if (ret)
+               goto err;
 
+       return 0;
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
 {
        struct i2c_client *client = mux_priv;
-       struct si2168_dev *dev = i2c_get_clientdata(client);
        int ret;
-       struct i2c_msg gate_close_msg = {
-               .addr = client->addr,
-               .flags = 0,
-               .len = 3,
-               .buf = "\xc0\x0d\x00",
-       };
-
-       /* close tuner I2C gate */
-       ret = __i2c_transfer(client->adapter, &gate_close_msg, 1);
-       if (ret != 1) {
-               dev_warn(&client->dev, "i2c write failed=%d\n", ret);
-               if (ret >= 0)
-                       ret = -EREMOTEIO;
-       } else {
-               ret = 0;
-       }
+       struct si2168_cmd cmd;
 
-       mutex_unlock(&dev->i2c_mutex);
+       /* close I2C gate */
+       memcpy(cmd.args, "\xc0\x0d\x00", 3);
+       cmd.wlen = 3;
+       cmd.rlen = 0;
+       ret = si2168_cmd_execute_unlocked(client, &cmd);
+       if (ret)
+               goto err;
 
+       return 0;
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -671,8 +708,6 @@ static int si2168_probe(struct i2c_client *client,
                goto err;
        }
 
-       mutex_init(&dev->i2c_mutex);
-
        /* create mux i2c adapter for tuner */
        dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                        client, 0, 0, 0, si2168_select, si2168_deselect);
@@ -688,6 +723,7 @@ static int si2168_probe(struct i2c_client *client,
        *config->fe = &dev->fe;
        dev->ts_mode = config->ts_mode;
        dev->ts_clock_inv = config->ts_clock_inv;
+       dev->ts_clock_gapped = config->ts_clock_gapped;
        dev->fw_loaded = false;
 
        i2c_set_clientdata(client, dev);
@@ -725,7 +761,6 @@ MODULE_DEVICE_TABLE(i2c, si2168_id_table);
 
 static struct i2c_driver si2168_driver = {
        .driver = {
-               .owner  = THIS_MODULE,
                .name   = "si2168",
        },
        .probe          = si2168_probe,