diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/busses/i2c-bcm2835.c | 12 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-cadence.c | 9 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 13 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 15 | ||||
| -rw-r--r-- | drivers/i2c/i2c-dev.c | 6 |
5 files changed, 44 insertions, 11 deletions
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index ec6e69aa3a8e..d2fbb4bb4a43 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c | |||
| @@ -183,6 +183,15 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev) | |||
| 183 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); | 183 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev) | ||
| 187 | { | ||
| 188 | i2c_dev->curr_msg = NULL; | ||
| 189 | i2c_dev->num_msgs = 0; | ||
| 190 | |||
| 191 | i2c_dev->msg_buf = NULL; | ||
| 192 | i2c_dev->msg_buf_remaining = 0; | ||
| 193 | } | ||
| 194 | |||
| 186 | /* | 195 | /* |
| 187 | * Note about I2C_C_CLEAR on error: | 196 | * Note about I2C_C_CLEAR on error: |
| 188 | * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in | 197 | * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in |
| @@ -283,6 +292,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
| 283 | 292 | ||
| 284 | time_left = wait_for_completion_timeout(&i2c_dev->completion, | 293 | time_left = wait_for_completion_timeout(&i2c_dev->completion, |
| 285 | adap->timeout); | 294 | adap->timeout); |
| 295 | |||
| 296 | bcm2835_i2c_finish_transfer(i2c_dev); | ||
| 297 | |||
| 286 | if (!time_left) { | 298 | if (!time_left) { |
| 287 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, | 299 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, |
| 288 | BCM2835_I2C_C_CLEAR); | 300 | BCM2835_I2C_C_CLEAR); |
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index b13605718291..d917cefc5a19 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c | |||
| @@ -382,8 +382,10 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) | |||
| 382 | * Check for the message size against FIFO depth and set the | 382 | * Check for the message size against FIFO depth and set the |
| 383 | * 'hold bus' bit if it is greater than FIFO depth. | 383 | * 'hold bus' bit if it is greater than FIFO depth. |
| 384 | */ | 384 | */ |
| 385 | if (id->recv_count > CDNS_I2C_FIFO_DEPTH) | 385 | if ((id->recv_count > CDNS_I2C_FIFO_DEPTH) || id->bus_hold_flag) |
| 386 | ctrl_reg |= CDNS_I2C_CR_HOLD; | 386 | ctrl_reg |= CDNS_I2C_CR_HOLD; |
| 387 | else | ||
| 388 | ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD; | ||
| 387 | 389 | ||
| 388 | cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); | 390 | cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); |
| 389 | 391 | ||
| @@ -440,8 +442,11 @@ static void cdns_i2c_msend(struct cdns_i2c *id) | |||
| 440 | * Check for the message size against FIFO depth and set the | 442 | * Check for the message size against FIFO depth and set the |
| 441 | * 'hold bus' bit if it is greater than FIFO depth. | 443 | * 'hold bus' bit if it is greater than FIFO depth. |
| 442 | */ | 444 | */ |
| 443 | if (id->send_count > CDNS_I2C_FIFO_DEPTH) | 445 | if ((id->send_count > CDNS_I2C_FIFO_DEPTH) || id->bus_hold_flag) |
| 444 | ctrl_reg |= CDNS_I2C_CR_HOLD; | 446 | ctrl_reg |= CDNS_I2C_CR_HOLD; |
| 447 | else | ||
| 448 | ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD; | ||
| 449 | |||
| 445 | cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); | 450 | cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); |
| 446 | 451 | ||
| 447 | /* Clear the interrupts in interrupt status register. */ | 452 | /* Clear the interrupts in interrupt status register. */ |
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b1086bfb0465..cd9c65f3d404 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
| @@ -1500,8 +1500,7 @@ static int omap_i2c_remove(struct platform_device *pdev) | |||
| 1500 | return 0; | 1500 | return 0; |
| 1501 | } | 1501 | } |
| 1502 | 1502 | ||
| 1503 | #ifdef CONFIG_PM | 1503 | static int __maybe_unused omap_i2c_runtime_suspend(struct device *dev) |
| 1504 | static int omap_i2c_runtime_suspend(struct device *dev) | ||
| 1505 | { | 1504 | { |
| 1506 | struct omap_i2c_dev *omap = dev_get_drvdata(dev); | 1505 | struct omap_i2c_dev *omap = dev_get_drvdata(dev); |
| 1507 | 1506 | ||
| @@ -1527,7 +1526,7 @@ static int omap_i2c_runtime_suspend(struct device *dev) | |||
| 1527 | return 0; | 1526 | return 0; |
| 1528 | } | 1527 | } |
| 1529 | 1528 | ||
| 1530 | static int omap_i2c_runtime_resume(struct device *dev) | 1529 | static int __maybe_unused omap_i2c_runtime_resume(struct device *dev) |
| 1531 | { | 1530 | { |
| 1532 | struct omap_i2c_dev *omap = dev_get_drvdata(dev); | 1531 | struct omap_i2c_dev *omap = dev_get_drvdata(dev); |
| 1533 | 1532 | ||
| @@ -1542,20 +1541,18 @@ static int omap_i2c_runtime_resume(struct device *dev) | |||
| 1542 | } | 1541 | } |
| 1543 | 1542 | ||
| 1544 | static const struct dev_pm_ops omap_i2c_pm_ops = { | 1543 | static const struct dev_pm_ops omap_i2c_pm_ops = { |
| 1544 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
| 1545 | pm_runtime_force_resume) | ||
| 1545 | SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, | 1546 | SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, |
| 1546 | omap_i2c_runtime_resume, NULL) | 1547 | omap_i2c_runtime_resume, NULL) |
| 1547 | }; | 1548 | }; |
| 1548 | #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) | ||
| 1549 | #else | ||
| 1550 | #define OMAP_I2C_PM_OPS NULL | ||
| 1551 | #endif /* CONFIG_PM */ | ||
| 1552 | 1549 | ||
| 1553 | static struct platform_driver omap_i2c_driver = { | 1550 | static struct platform_driver omap_i2c_driver = { |
| 1554 | .probe = omap_i2c_probe, | 1551 | .probe = omap_i2c_probe, |
| 1555 | .remove = omap_i2c_remove, | 1552 | .remove = omap_i2c_remove, |
| 1556 | .driver = { | 1553 | .driver = { |
| 1557 | .name = "omap_i2c", | 1554 | .name = "omap_i2c", |
| 1558 | .pm = OMAP_I2C_PM_OPS, | 1555 | .pm = &omap_i2c_pm_ops, |
| 1559 | .of_match_table = of_match_ptr(omap_i2c_of_match), | 1556 | .of_match_table = of_match_ptr(omap_i2c_of_match), |
| 1560 | }, | 1557 | }, |
| 1561 | }; | 1558 | }; |
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index e417ebf7628c..c77adbbea0c7 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c | |||
| @@ -155,6 +155,8 @@ enum msg_end_type { | |||
| 155 | * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that | 155 | * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that |
| 156 | * provides additional features and allows for longer messages to | 156 | * provides additional features and allows for longer messages to |
| 157 | * be transferred in one go. | 157 | * be transferred in one go. |
| 158 | * @quirks: i2c adapter quirks for limiting write/read transfer size and not | ||
| 159 | * allowing 0 length transfers. | ||
| 158 | */ | 160 | */ |
| 159 | struct tegra_i2c_hw_feature { | 161 | struct tegra_i2c_hw_feature { |
| 160 | bool has_continue_xfer_support; | 162 | bool has_continue_xfer_support; |
| @@ -167,6 +169,7 @@ struct tegra_i2c_hw_feature { | |||
| 167 | bool has_multi_master_mode; | 169 | bool has_multi_master_mode; |
| 168 | bool has_slcg_override_reg; | 170 | bool has_slcg_override_reg; |
| 169 | bool has_mst_fifo; | 171 | bool has_mst_fifo; |
| 172 | const struct i2c_adapter_quirks *quirks; | ||
| 170 | }; | 173 | }; |
| 171 | 174 | ||
| 172 | /** | 175 | /** |
| @@ -837,6 +840,10 @@ static const struct i2c_adapter_quirks tegra_i2c_quirks = { | |||
| 837 | .max_write_len = 4096, | 840 | .max_write_len = 4096, |
| 838 | }; | 841 | }; |
| 839 | 842 | ||
| 843 | static const struct i2c_adapter_quirks tegra194_i2c_quirks = { | ||
| 844 | .flags = I2C_AQ_NO_ZERO_LEN, | ||
| 845 | }; | ||
| 846 | |||
| 840 | static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { | 847 | static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { |
| 841 | .has_continue_xfer_support = false, | 848 | .has_continue_xfer_support = false, |
| 842 | .has_per_pkt_xfer_complete_irq = false, | 849 | .has_per_pkt_xfer_complete_irq = false, |
| @@ -848,6 +855,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { | |||
| 848 | .has_multi_master_mode = false, | 855 | .has_multi_master_mode = false, |
| 849 | .has_slcg_override_reg = false, | 856 | .has_slcg_override_reg = false, |
| 850 | .has_mst_fifo = false, | 857 | .has_mst_fifo = false, |
| 858 | .quirks = &tegra_i2c_quirks, | ||
| 851 | }; | 859 | }; |
| 852 | 860 | ||
| 853 | static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { | 861 | static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { |
| @@ -861,6 +869,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { | |||
| 861 | .has_multi_master_mode = false, | 869 | .has_multi_master_mode = false, |
| 862 | .has_slcg_override_reg = false, | 870 | .has_slcg_override_reg = false, |
| 863 | .has_mst_fifo = false, | 871 | .has_mst_fifo = false, |
| 872 | .quirks = &tegra_i2c_quirks, | ||
| 864 | }; | 873 | }; |
| 865 | 874 | ||
| 866 | static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { | 875 | static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { |
| @@ -874,6 +883,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { | |||
| 874 | .has_multi_master_mode = false, | 883 | .has_multi_master_mode = false, |
| 875 | .has_slcg_override_reg = false, | 884 | .has_slcg_override_reg = false, |
| 876 | .has_mst_fifo = false, | 885 | .has_mst_fifo = false, |
| 886 | .quirks = &tegra_i2c_quirks, | ||
| 877 | }; | 887 | }; |
| 878 | 888 | ||
| 879 | static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { | 889 | static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { |
| @@ -887,6 +897,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { | |||
| 887 | .has_multi_master_mode = false, | 897 | .has_multi_master_mode = false, |
| 888 | .has_slcg_override_reg = true, | 898 | .has_slcg_override_reg = true, |
| 889 | .has_mst_fifo = false, | 899 | .has_mst_fifo = false, |
| 900 | .quirks = &tegra_i2c_quirks, | ||
| 890 | }; | 901 | }; |
| 891 | 902 | ||
| 892 | static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { | 903 | static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { |
| @@ -900,6 +911,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { | |||
| 900 | .has_multi_master_mode = true, | 911 | .has_multi_master_mode = true, |
| 901 | .has_slcg_override_reg = true, | 912 | .has_slcg_override_reg = true, |
| 902 | .has_mst_fifo = false, | 913 | .has_mst_fifo = false, |
| 914 | .quirks = &tegra_i2c_quirks, | ||
| 903 | }; | 915 | }; |
| 904 | 916 | ||
| 905 | static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { | 917 | static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { |
| @@ -913,6 +925,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { | |||
| 913 | .has_multi_master_mode = true, | 925 | .has_multi_master_mode = true, |
| 914 | .has_slcg_override_reg = true, | 926 | .has_slcg_override_reg = true, |
| 915 | .has_mst_fifo = true, | 927 | .has_mst_fifo = true, |
| 928 | .quirks = &tegra194_i2c_quirks, | ||
| 916 | }; | 929 | }; |
| 917 | 930 | ||
| 918 | /* Match table for of_platform binding */ | 931 | /* Match table for of_platform binding */ |
| @@ -964,7 +977,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) | |||
| 964 | i2c_dev->base = base; | 977 | i2c_dev->base = base; |
| 965 | i2c_dev->div_clk = div_clk; | 978 | i2c_dev->div_clk = div_clk; |
| 966 | i2c_dev->adapter.algo = &tegra_i2c_algo; | 979 | i2c_dev->adapter.algo = &tegra_i2c_algo; |
| 967 | i2c_dev->adapter.quirks = &tegra_i2c_quirks; | ||
| 968 | i2c_dev->irq = irq; | 980 | i2c_dev->irq = irq; |
| 969 | i2c_dev->cont_id = pdev->id; | 981 | i2c_dev->cont_id = pdev->id; |
| 970 | i2c_dev->dev = &pdev->dev; | 982 | i2c_dev->dev = &pdev->dev; |
| @@ -980,6 +992,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) | |||
| 980 | i2c_dev->hw = of_device_get_match_data(&pdev->dev); | 992 | i2c_dev->hw = of_device_get_match_data(&pdev->dev); |
| 981 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, | 993 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, |
| 982 | "nvidia,tegra20-i2c-dvc"); | 994 | "nvidia,tegra20-i2c-dvc"); |
| 995 | i2c_dev->adapter.quirks = i2c_dev->hw->quirks; | ||
| 983 | init_completion(&i2c_dev->msg_complete); | 996 | init_completion(&i2c_dev->msg_complete); |
| 984 | spin_lock_init(&i2c_dev->xfer_lock); | 997 | spin_lock_init(&i2c_dev->xfer_lock); |
| 985 | 998 | ||
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 1aca742fde4a..ccd76c71af09 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
| @@ -470,9 +470,15 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 470 | data_arg.data); | 470 | data_arg.data); |
| 471 | } | 471 | } |
| 472 | case I2C_RETRIES: | 472 | case I2C_RETRIES: |
| 473 | if (arg > INT_MAX) | ||
| 474 | return -EINVAL; | ||
| 475 | |||
| 473 | client->adapter->retries = arg; | 476 | client->adapter->retries = arg; |
| 474 | break; | 477 | break; |
| 475 | case I2C_TIMEOUT: | 478 | case I2C_TIMEOUT: |
| 479 | if (arg > INT_MAX) | ||
| 480 | return -EINVAL; | ||
| 481 | |||
| 476 | /* For historical reasons, user-space sets the timeout | 482 | /* For historical reasons, user-space sets the timeout |
| 477 | * value in units of 10 ms. | 483 | * value in units of 10 ms. |
| 478 | */ | 484 | */ |
