diff options
| author | Daniel Kurtz <djkurtz@chromium.org> | 2012-11-15 07:13:30 -0500 |
|---|---|---|
| committer | Wolfram Sang <w.sang@pengutronix.de> | 2012-11-16 07:08:48 -0500 |
| commit | 9bcd04bfbbd5599de011176b846ed00ac15a234c (patch) | |
| tree | cdf492904dc6b6a457f01d0e268cb55a3cba2002 | |
| parent | 2693ac69880a33d4d9df6f128415b65e745f00ba (diff) | |
i2c: s3c2410: grab adapter lock while changing i2c clock
We probably don't want to change I2C frequency while a transfer is in
progress. The current implementation grabs a spinlock, but that only
protected the writes to IICCON when starting a message, it didn't protect
against clock changes in the middle of a transaction.
Note: The i2c-core already grabs the adapter lock before calling
s3c24xx_i2c_doxfer(), which ensures that only one caller is issuing a
xfer at a time. This means it is not necessary to disable interrupts
(spin_lock_irqsave) when changing frequencies, since there won't be
any i2c interrupts if there is no on-going xfer.
Lastly, i2c_lock_adapter() may cause the cpufreq_transition to sleep if
if a xfer is in progress, but this is ok since cpufreq notifiers are
called in a kernel thread, and there are already cases where it could
sleep, such as when using i2c to update the output of a voltage
regulator.
Note: the cpufreq part of this change has no functional affect on
exynos, where the i2c clock is independent of the cpufreq.
But, there is a slight perfomance boost since we no longer need to
lock/unlock an additional spinlock.
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
| -rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 10 |
1 files changed, 2 insertions, 8 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 40e2d40bbdb5..86e60f598c51 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
| @@ -60,7 +60,6 @@ enum s3c24xx_i2c_state { | |||
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | struct s3c24xx_i2c { | 62 | struct s3c24xx_i2c { |
| 63 | spinlock_t lock; | ||
| 64 | wait_queue_head_t wait; | 63 | wait_queue_head_t wait; |
| 65 | unsigned int quirks; | 64 | unsigned int quirks; |
| 66 | unsigned int suspended:1; | 65 | unsigned int suspended:1; |
| @@ -541,8 +540,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, | |||
| 541 | goto out; | 540 | goto out; |
| 542 | } | 541 | } |
| 543 | 542 | ||
| 544 | spin_lock_irq(&i2c->lock); | ||
| 545 | |||
| 546 | i2c->msg = msgs; | 543 | i2c->msg = msgs; |
| 547 | i2c->msg_num = num; | 544 | i2c->msg_num = num; |
| 548 | i2c->msg_ptr = 0; | 545 | i2c->msg_ptr = 0; |
| @@ -551,7 +548,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, | |||
| 551 | 548 | ||
| 552 | s3c24xx_i2c_enable_irq(i2c); | 549 | s3c24xx_i2c_enable_irq(i2c); |
| 553 | s3c24xx_i2c_message_start(i2c, msgs); | 550 | s3c24xx_i2c_message_start(i2c, msgs); |
| 554 | spin_unlock_irq(&i2c->lock); | ||
| 555 | 551 | ||
| 556 | timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); | 552 | timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); |
| 557 | 553 | ||
| @@ -741,7 +737,6 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, | |||
| 741 | unsigned long val, void *data) | 737 | unsigned long val, void *data) |
| 742 | { | 738 | { |
| 743 | struct s3c24xx_i2c *i2c = freq_to_i2c(nb); | 739 | struct s3c24xx_i2c *i2c = freq_to_i2c(nb); |
| 744 | unsigned long flags; | ||
| 745 | unsigned int got; | 740 | unsigned int got; |
| 746 | int delta_f; | 741 | int delta_f; |
| 747 | int ret; | 742 | int ret; |
| @@ -755,9 +750,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, | |||
| 755 | 750 | ||
| 756 | if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || | 751 | if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || |
| 757 | (val == CPUFREQ_PRECHANGE && delta_f > 0)) { | 752 | (val == CPUFREQ_PRECHANGE && delta_f > 0)) { |
| 758 | spin_lock_irqsave(&i2c->lock, flags); | 753 | i2c_lock_adapter(&i2c->adap); |
| 759 | ret = s3c24xx_i2c_clockrate(i2c, &got); | 754 | ret = s3c24xx_i2c_clockrate(i2c, &got); |
| 760 | spin_unlock_irqrestore(&i2c->lock, flags); | 755 | i2c_unlock_adapter(&i2c->adap); |
| 761 | 756 | ||
| 762 | if (ret < 0) | 757 | if (ret < 0) |
| 763 | dev_err(i2c->dev, "cannot find frequency\n"); | 758 | dev_err(i2c->dev, "cannot find frequency\n"); |
| @@ -962,7 +957,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
| 962 | i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; | 957 | i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; |
| 963 | i2c->tx_setup = 50; | 958 | i2c->tx_setup = 50; |
| 964 | 959 | ||
| 965 | spin_lock_init(&i2c->lock); | ||
| 966 | init_waitqueue_head(&i2c->wait); | 960 | init_waitqueue_head(&i2c->wait); |
| 967 | 961 | ||
| 968 | /* find the clock and enable it */ | 962 | /* find the clock and enable it */ |
