diff options
| author | David Box <david.e.box@linux.intel.com> | 2015-01-15 04:12:16 -0500 |
|---|---|---|
| committer | Wolfram Sang <wsa@the-dreams.de> | 2015-01-26 06:26:16 -0500 |
| commit | c0601d285efe063def984f91b04de2d227f89526 (patch) | |
| tree | f405abc5b7a41d51893e3e59821781075b1571e6 /drivers/i2c | |
| parent | 72f0271576eeef40c81c2949e0a8abeaef9a7690 (diff) | |
i2c: designware: Add i2c bus locking support
Adds support for acquiring and releasing a hardware bus lock in the i2c
designware core transfer function. This is needed for i2c bus controllers
that are shared with but not controlled by the kernel.
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-core.c | 26 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 6 |
2 files changed, 32 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index e2799483dc45..fbb48fb138e7 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c | |||
| @@ -285,6 +285,15 @@ int i2c_dw_init(struct dw_i2c_dev *dev) | |||
| 285 | u32 hcnt, lcnt; | 285 | u32 hcnt, lcnt; |
| 286 | u32 reg; | 286 | u32 reg; |
| 287 | u32 sda_falling_time, scl_falling_time; | 287 | u32 sda_falling_time, scl_falling_time; |
| 288 | int ret; | ||
| 289 | |||
| 290 | if (dev->acquire_lock) { | ||
| 291 | ret = dev->acquire_lock(dev); | ||
| 292 | if (ret) { | ||
| 293 | dev_err(dev->dev, "couldn't acquire bus ownership\n"); | ||
| 294 | return ret; | ||
| 295 | } | ||
| 296 | } | ||
| 288 | 297 | ||
| 289 | input_clock_khz = dev->get_clk_rate_khz(dev); | 298 | input_clock_khz = dev->get_clk_rate_khz(dev); |
| 290 | 299 | ||
| @@ -298,6 +307,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev) | |||
| 298 | } else if (reg != DW_IC_COMP_TYPE_VALUE) { | 307 | } else if (reg != DW_IC_COMP_TYPE_VALUE) { |
| 299 | dev_err(dev->dev, "Unknown Synopsys component type: " | 308 | dev_err(dev->dev, "Unknown Synopsys component type: " |
| 300 | "0x%08x\n", reg); | 309 | "0x%08x\n", reg); |
| 310 | if (dev->release_lock) | ||
| 311 | dev->release_lock(dev); | ||
| 301 | return -ENODEV; | 312 | return -ENODEV; |
| 302 | } | 313 | } |
| 303 | 314 | ||
| @@ -364,6 +375,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev) | |||
| 364 | 375 | ||
| 365 | /* configure the i2c master */ | 376 | /* configure the i2c master */ |
| 366 | dw_writel(dev, dev->master_cfg , DW_IC_CON); | 377 | dw_writel(dev, dev->master_cfg , DW_IC_CON); |
| 378 | |||
| 379 | if (dev->release_lock) | ||
| 380 | dev->release_lock(dev); | ||
| 367 | return 0; | 381 | return 0; |
| 368 | } | 382 | } |
| 369 | EXPORT_SYMBOL_GPL(i2c_dw_init); | 383 | EXPORT_SYMBOL_GPL(i2c_dw_init); |
| @@ -627,6 +641,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |||
| 627 | dev->abort_source = 0; | 641 | dev->abort_source = 0; |
| 628 | dev->rx_outstanding = 0; | 642 | dev->rx_outstanding = 0; |
| 629 | 643 | ||
| 644 | if (dev->acquire_lock) { | ||
| 645 | ret = dev->acquire_lock(dev); | ||
| 646 | if (ret) { | ||
| 647 | dev_err(dev->dev, "couldn't acquire bus ownership\n"); | ||
| 648 | goto done_nolock; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 630 | ret = i2c_dw_wait_bus_not_busy(dev); | 652 | ret = i2c_dw_wait_bus_not_busy(dev); |
| 631 | if (ret < 0) | 653 | if (ret < 0) |
| 632 | goto done; | 654 | goto done; |
| @@ -672,6 +694,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |||
| 672 | ret = -EIO; | 694 | ret = -EIO; |
| 673 | 695 | ||
| 674 | done: | 696 | done: |
| 697 | if (dev->release_lock) | ||
| 698 | dev->release_lock(dev); | ||
| 699 | |||
| 700 | done_nolock: | ||
| 675 | pm_runtime_mark_last_busy(dev->dev); | 701 | pm_runtime_mark_last_busy(dev->dev); |
| 676 | pm_runtime_put_autosuspend(dev->dev); | 702 | pm_runtime_put_autosuspend(dev->dev); |
| 677 | mutex_unlock(&dev->lock); | 703 | mutex_unlock(&dev->lock); |
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 5a410ef17abd..ef8ba839e2d3 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h | |||
| @@ -61,6 +61,9 @@ | |||
| 61 | * @ss_lcnt: standard speed LCNT value | 61 | * @ss_lcnt: standard speed LCNT value |
| 62 | * @fs_hcnt: fast speed HCNT value | 62 | * @fs_hcnt: fast speed HCNT value |
| 63 | * @fs_lcnt: fast speed LCNT value | 63 | * @fs_lcnt: fast speed LCNT value |
| 64 | * @acquire_lock: function to acquire a hardware lock on the bus | ||
| 65 | * @release_lock: function to release a hardware lock on the bus | ||
| 66 | * @pm_runtime_disabled: true if pm runtime is disabled | ||
| 64 | * | 67 | * |
| 65 | * HCNT and LCNT parameters can be used if the platform knows more accurate | 68 | * HCNT and LCNT parameters can be used if the platform knows more accurate |
| 66 | * values than the one computed based only on the input clock frequency. | 69 | * values than the one computed based only on the input clock frequency. |
| @@ -101,6 +104,9 @@ struct dw_i2c_dev { | |||
| 101 | u16 ss_lcnt; | 104 | u16 ss_lcnt; |
| 102 | u16 fs_hcnt; | 105 | u16 fs_hcnt; |
| 103 | u16 fs_lcnt; | 106 | u16 fs_lcnt; |
| 107 | int (*acquire_lock)(struct dw_i2c_dev *dev); | ||
| 108 | void (*release_lock)(struct dw_i2c_dev *dev); | ||
| 109 | bool pm_runtime_disabled; | ||
| 104 | }; | 110 | }; |
| 105 | 111 | ||
| 106 | #define ACCESS_SWAP 0x00000001 | 112 | #define ACCESS_SWAP 0x00000001 |
