965 lines
31 KiB
Diff
965 lines
31 KiB
Diff
From e2474541032db65d02bf88b6a8c2f954654b443f Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:08 +0200
|
|
Subject: [PATCH 31155/39886] i2c: bcm2835: Fix hang for writing messages
|
|
larger than 16 bytes
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Writing messages larger than the FIFO size results in a hang, rendering
|
|
the machine unusable. This is because the RXD status flag is set on the
|
|
first interrupt which results in bcm2835_drain_rxfifo() stealing bytes
|
|
from the buffer. The controller continues to trigger interrupts waiting
|
|
for the missing bytes, but bcm2835_fill_txfifo() has none to give.
|
|
In this situation wait_for_completion_timeout() apparently is unable to
|
|
stop the madness.
|
|
|
|
The BCM2835 ARM Peripherals datasheet has this to say about the flags:
|
|
TXD: is set when the FIFO has space for at least one byte of data.
|
|
RXD: is set when the FIFO contains at least one byte of data.
|
|
TXW: is set during a write transfer and the FIFO is less than full.
|
|
RXR: is set during a read transfer and the FIFO is or more full.
|
|
|
|
Implementing the logic from the downstream i2c-bcm2708 driver solved
|
|
the hang problem.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Reviewed-by: Martin Sperl <kernel@martin.sperl.org>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++--------
|
|
1 file changed, 14 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index d4f3239..f283b71 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -64,6 +64,7 @@ struct bcm2835_i2c_dev {
|
|
int irq;
|
|
struct i2c_adapter adapter;
|
|
struct completion completion;
|
|
+ struct i2c_msg *curr_msg;
|
|
u32 msg_err;
|
|
u8 *msg_buf;
|
|
size_t msg_buf_remaining;
|
|
@@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
- if (val & BCM2835_I2C_S_RXD) {
|
|
- bcm2835_drain_rxfifo(i2c_dev);
|
|
- if (!(val & BCM2835_I2C_S_DONE))
|
|
- return IRQ_HANDLED;
|
|
- }
|
|
-
|
|
if (val & BCM2835_I2C_S_DONE) {
|
|
- if (i2c_dev->msg_buf_remaining)
|
|
+ if (i2c_dev->curr_msg->flags & I2C_M_RD) {
|
|
+ bcm2835_drain_rxfifo(i2c_dev);
|
|
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
|
|
+ }
|
|
+
|
|
+ if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining)
|
|
i2c_dev->msg_err = BCM2835_I2C_S_LEN;
|
|
else
|
|
i2c_dev->msg_err = 0;
|
|
@@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
- if (val & BCM2835_I2C_S_TXD) {
|
|
+ if (val & BCM2835_I2C_S_TXW) {
|
|
bcm2835_fill_txfifo(i2c_dev);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
+ if (val & BCM2835_I2C_S_RXR) {
|
|
+ bcm2835_drain_rxfifo(i2c_dev);
|
|
+ return IRQ_HANDLED;
|
|
+ }
|
|
+
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
@@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
u32 c;
|
|
unsigned long time_left;
|
|
|
|
+ i2c_dev->curr_msg = msg;
|
|
i2c_dev->msg_buf = msg->buf;
|
|
i2c_dev->msg_buf_remaining = msg->len;
|
|
reinit_completion(&i2c_dev->completion);
|
|
--
|
|
2.9.3
|
|
|
|
From d4030d75c7cbb434b2a3e5f6af5065879d2615a5 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:09 +0200
|
|
Subject: [PATCH 31156/39886] i2c: bcm2835: Protect against unexpected TXW/RXR
|
|
interrupts
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
If an unexpected TXW or RXR interrupt occurs (msg_buf_remaining == 0),
|
|
the driver has no way to fill/drain the FIFO to stop the interrupts.
|
|
In this case the controller has to be disabled and the transfer
|
|
completed to avoid hang.
|
|
|
|
(CLKT | ERR) and DONE interrupts are completed in their own paths, and
|
|
the controller is disabled in the transfer function after completion.
|
|
Unite the code paths and do disabling inside the interrupt routine.
|
|
|
|
Clear interrupt status bits in the united completion path instead of
|
|
trying to do it on every interrupt which isn't necessary.
|
|
Only CLKT, ERR and DONE can be cleared that way.
|
|
|
|
Add the status value to the error value in case of TXW/RXR errors to
|
|
distinguish them from the other S_LEN error.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 40 +++++++++++++++++++++++++++++++---------
|
|
1 file changed, 31 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index f283b71..d2ba1a4 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -50,8 +50,6 @@
|
|
#define BCM2835_I2C_S_CLKT BIT(9)
|
|
#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */
|
|
|
|
-#define BCM2835_I2C_BITMSK_S 0x03FF
|
|
-
|
|
#define BCM2835_I2C_CDIV_MIN 0x0002
|
|
#define BCM2835_I2C_CDIV_MAX 0xFFFE
|
|
|
|
@@ -111,20 +109,26 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev)
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * Note about I2C_C_CLEAR on error:
|
|
+ * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in
|
|
+ * non-idle state and I2C_C_READ, it sets an abort_rx flag and runs through
|
|
+ * the state machine to send a NACK and a STOP. Since we're setting CLEAR
|
|
+ * without I2CEN, that NACK will be hanging around queued up for next time
|
|
+ * we start the engine.
|
|
+ */
|
|
+
|
|
static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
|
{
|
|
struct bcm2835_i2c_dev *i2c_dev = data;
|
|
u32 val, err;
|
|
|
|
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
|
|
- val &= BCM2835_I2C_BITMSK_S;
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val);
|
|
|
|
err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
|
|
if (err) {
|
|
i2c_dev->msg_err = err;
|
|
- complete(&i2c_dev->completion);
|
|
- return IRQ_HANDLED;
|
|
+ goto complete;
|
|
}
|
|
|
|
if (val & BCM2835_I2C_S_DONE) {
|
|
@@ -137,21 +141,38 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
|
i2c_dev->msg_err = BCM2835_I2C_S_LEN;
|
|
else
|
|
i2c_dev->msg_err = 0;
|
|
- complete(&i2c_dev->completion);
|
|
- return IRQ_HANDLED;
|
|
+ goto complete;
|
|
}
|
|
|
|
if (val & BCM2835_I2C_S_TXW) {
|
|
+ if (!i2c_dev->msg_buf_remaining) {
|
|
+ i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
|
|
+ goto complete;
|
|
+ }
|
|
+
|
|
bcm2835_fill_txfifo(i2c_dev);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
if (val & BCM2835_I2C_S_RXR) {
|
|
+ if (!i2c_dev->msg_buf_remaining) {
|
|
+ i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
|
|
+ goto complete;
|
|
+ }
|
|
+
|
|
bcm2835_drain_rxfifo(i2c_dev);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
return IRQ_NONE;
|
|
+
|
|
+complete:
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT |
|
|
+ BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE);
|
|
+ complete(&i2c_dev->completion);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
}
|
|
|
|
static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
@@ -181,8 +202,9 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
|
|
time_left = wait_for_completion_timeout(&i2c_dev->completion,
|
|
BCM2835_I2C_TIMEOUT);
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
|
|
if (!time_left) {
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
|
|
+ BCM2835_I2C_C_CLEAR);
|
|
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
--
|
|
2.9.3
|
|
|
|
From 23c9540b3ad1d7473fe40df80074d0fb0bf04869 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:10 +0200
|
|
Subject: [PATCH 31157/39886] i2c: bcm2835: Use dev_dbg logging on transfer
|
|
errors
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Writing to an AT24C32 generates on average 2x i2c transfer errors per
|
|
32-byte page write. Which amounts to a lot for a 4k write. This is due
|
|
to the fact that the chip doesn't respond during it's internal write
|
|
cycle when the at24 driver tries and retries the next write.
|
|
Only a handful drivers use dev_err() on transfer error, so switch to
|
|
dev_dbg() instead.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index d2ba1a4..54d510a 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -216,7 +216,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
(msg->flags & I2C_M_IGNORE_NAK))
|
|
return 0;
|
|
|
|
- dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
|
|
+ dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
|
|
|
|
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
|
|
return -EREMOTEIO;
|
|
--
|
|
2.9.3
|
|
|
|
From 8d2cc5cc6ee5c0fc48a96bb29af55fc700f66fdf Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:11 +0200
|
|
Subject: [PATCH 31158/39886] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
The controller can't support this flag, so remove it.
|
|
|
|
Documentation/i2c/i2c-protocol states that all of the message is sent:
|
|
|
|
I2C_M_IGNORE_NAK:
|
|
Normally message is interrupted immediately if there is [NA] from the
|
|
client. Setting this flag treats any [NA] as [A], and all of
|
|
message is sent.
|
|
|
|
>From the BCM2835 ARM Peripherals datasheet:
|
|
|
|
The ERR field is set when the slave fails to acknowledge either
|
|
its address or a data byte written to it.
|
|
|
|
So when the controller doesn't receive an ack, it sets ERR and raises
|
|
an interrupt. In other words, the whole message is not sent.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 4 ----
|
|
1 file changed, 4 deletions(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index 54d510a..565ef69 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -212,10 +212,6 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
if (likely(!i2c_dev->msg_err))
|
|
return 0;
|
|
|
|
- if ((i2c_dev->msg_err & BCM2835_I2C_S_ERR) &&
|
|
- (msg->flags & I2C_M_IGNORE_NAK))
|
|
- return 0;
|
|
-
|
|
dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
|
|
|
|
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
|
|
--
|
|
2.9.3
|
|
|
|
From ee05fea21b017b81a9477569b6a0c2d8e2946ac9 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:12 +0200
|
|
Subject: [PATCH 31159/39886] i2c: bcm2835: Add support for Repeated Start
|
|
Condition
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Documentation/i2c/i2c-protocol states that Combined transactions should
|
|
separate messages with a Start bit and end the whole transaction with a
|
|
Stop bit. This patch adds support for issuing only a Start between
|
|
messages instead of a Stop followed by a Start.
|
|
|
|
This implementation differs from downstream i2c-bcm2708 in 2 respects:
|
|
- it uses an interrupt to detect that the transfer is active instead
|
|
of using polling. There is no interrupt for Transfer Active, but by
|
|
not prefilling the FIFO it's possible to use the TXW interrupt.
|
|
- when resetting/disabling the controller between transfers it writes
|
|
CLEAR to the control register instead of just zero.
|
|
Using just zero gave many errors. This might be the reason why
|
|
downstream had to disable this feature and make it available with a
|
|
module parameter.
|
|
|
|
I have run thousands of transfers to a DS1307 (rtc), MMA8451 (accel)
|
|
and AT24C32 (eeprom) in parallel without problems.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Acked-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 101 ++++++++++++++++++++++++---------------
|
|
1 file changed, 63 insertions(+), 38 deletions(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index 565ef69..241e08a 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -63,6 +63,7 @@ struct bcm2835_i2c_dev {
|
|
struct i2c_adapter adapter;
|
|
struct completion completion;
|
|
struct i2c_msg *curr_msg;
|
|
+ int num_msgs;
|
|
u32 msg_err;
|
|
u8 *msg_buf;
|
|
size_t msg_buf_remaining;
|
|
@@ -110,6 +111,45 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev)
|
|
}
|
|
|
|
/*
|
|
+ * Repeated Start Condition (Sr)
|
|
+ * The BCM2835 ARM Peripherals datasheet mentions a way to trigger a Sr when it
|
|
+ * talks about reading from a slave with 10 bit address. This is achieved by
|
|
+ * issuing a write, poll the I2CS.TA flag and wait for it to be set, and then
|
|
+ * issue a read.
|
|
+ * A comment in https://github.com/raspberrypi/linux/issues/254 shows how the
|
|
+ * firmware actually does it using polling and says that it's a workaround for
|
|
+ * a problem in the state machine.
|
|
+ * It turns out that it is possible to use the TXW interrupt to know when the
|
|
+ * transfer is active, provided the FIFO has not been prefilled.
|
|
+ */
|
|
+
|
|
+static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev)
|
|
+{
|
|
+ u32 c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN;
|
|
+ struct i2c_msg *msg = i2c_dev->curr_msg;
|
|
+ bool last_msg = (i2c_dev->num_msgs == 1);
|
|
+
|
|
+ if (!i2c_dev->num_msgs)
|
|
+ return;
|
|
+
|
|
+ i2c_dev->num_msgs--;
|
|
+ i2c_dev->msg_buf = msg->buf;
|
|
+ i2c_dev->msg_buf_remaining = msg->len;
|
|
+
|
|
+ if (msg->flags & I2C_M_RD)
|
|
+ c |= BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
|
|
+ else
|
|
+ c |= BCM2835_I2C_C_INTT;
|
|
+
|
|
+ if (last_msg)
|
|
+ c |= BCM2835_I2C_C_INTD;
|
|
+
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
|
|
+}
|
|
+
|
|
+/*
|
|
* Note about I2C_C_CLEAR on error:
|
|
* The I2C_C_CLEAR on errors will take some time to resolve -- if you were in
|
|
* non-idle state and I2C_C_READ, it sets an abort_rx flag and runs through
|
|
@@ -151,6 +191,12 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
|
}
|
|
|
|
bcm2835_fill_txfifo(i2c_dev);
|
|
+
|
|
+ if (i2c_dev->num_msgs && !i2c_dev->msg_buf_remaining) {
|
|
+ i2c_dev->curr_msg++;
|
|
+ bcm2835_i2c_start_transfer(i2c_dev);
|
|
+ }
|
|
+
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -175,30 +221,25 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
-static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
- struct i2c_msg *msg)
|
|
+static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|
+ int num)
|
|
{
|
|
- u32 c;
|
|
+ struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
|
unsigned long time_left;
|
|
+ int i;
|
|
|
|
- i2c_dev->curr_msg = msg;
|
|
- i2c_dev->msg_buf = msg->buf;
|
|
- i2c_dev->msg_buf_remaining = msg->len;
|
|
- reinit_completion(&i2c_dev->completion);
|
|
-
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
|
|
+ for (i = 0; i < (num - 1); i++)
|
|
+ if (msgs[i].flags & I2C_M_RD) {
|
|
+ dev_warn_once(i2c_dev->dev,
|
|
+ "only one read message supported, has to be last\n");
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
|
|
- if (msg->flags & I2C_M_RD) {
|
|
- c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
|
|
- } else {
|
|
- c = BCM2835_I2C_C_INTT;
|
|
- bcm2835_fill_txfifo(i2c_dev);
|
|
- }
|
|
- c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD | BCM2835_I2C_C_I2CEN;
|
|
+ i2c_dev->curr_msg = msgs;
|
|
+ i2c_dev->num_msgs = num;
|
|
+ reinit_completion(&i2c_dev->completion);
|
|
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
|
|
+ bcm2835_i2c_start_transfer(i2c_dev);
|
|
|
|
time_left = wait_for_completion_timeout(&i2c_dev->completion,
|
|
BCM2835_I2C_TIMEOUT);
|
|
@@ -209,31 +250,15 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
- if (likely(!i2c_dev->msg_err))
|
|
- return 0;
|
|
+ if (!i2c_dev->msg_err)
|
|
+ return num;
|
|
|
|
dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
|
|
|
|
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
|
|
return -EREMOTEIO;
|
|
- else
|
|
- return -EIO;
|
|
-}
|
|
-
|
|
-static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|
- int num)
|
|
-{
|
|
- struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
|
- int i;
|
|
- int ret = 0;
|
|
-
|
|
- for (i = 0; i < num; i++) {
|
|
- ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i]);
|
|
- if (ret)
|
|
- break;
|
|
- }
|
|
|
|
- return ret ?: i;
|
|
+ return -EIO;
|
|
}
|
|
|
|
static u32 bcm2835_i2c_func(struct i2c_adapter *adap)
|
|
--
|
|
2.9.3
|
|
|
|
From e13e19e12f66401ce1e21ab491715835852babe7 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:13 +0200
|
|
Subject: [PATCH 31160/39886] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Use i2c_adapter->timeout for the completion timeout value. The core
|
|
default is 1 second.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 4 +---
|
|
1 file changed, 1 insertion(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index 241e08a..d2085dd 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -53,8 +53,6 @@
|
|
#define BCM2835_I2C_CDIV_MIN 0x0002
|
|
#define BCM2835_I2C_CDIV_MAX 0xFFFE
|
|
|
|
-#define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
|
-
|
|
struct bcm2835_i2c_dev {
|
|
struct device *dev;
|
|
void __iomem *regs;
|
|
@@ -242,7 +240,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|
bcm2835_i2c_start_transfer(i2c_dev);
|
|
|
|
time_left = wait_for_completion_timeout(&i2c_dev->completion,
|
|
- BCM2835_I2C_TIMEOUT);
|
|
+ adap->timeout);
|
|
if (!time_left) {
|
|
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
|
|
BCM2835_I2C_C_CLEAR);
|
|
--
|
|
2.9.3
|
|
|
|
From 9446f62e8e18057fceb179d947508df2f7253b26 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
|
Date: Mon, 3 Oct 2016 22:06:14 +0200
|
|
Subject: [PATCH 31161/39886] i2c: bcm2835: Add support for dynamic clock
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Support a dynamic clock by reading the frequency and setting the
|
|
divisor in the transfer function instead of during probe.
|
|
|
|
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
|
Reviewed-by: Martin Sperl <kernel@martin.sperl.org>
|
|
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
|
---
|
|
drivers/i2c/busses/i2c-bcm2835.c | 51 +++++++++++++++++++++++++---------------
|
|
1 file changed, 32 insertions(+), 19 deletions(-)
|
|
|
|
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
|
index d2085dd..c3436f6 100644
|
|
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
|
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
|
@@ -58,6 +58,7 @@ struct bcm2835_i2c_dev {
|
|
void __iomem *regs;
|
|
struct clk *clk;
|
|
int irq;
|
|
+ u32 bus_clk_rate;
|
|
struct i2c_adapter adapter;
|
|
struct completion completion;
|
|
struct i2c_msg *curr_msg;
|
|
@@ -78,6 +79,30 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
|
|
return readl(i2c_dev->regs + reg);
|
|
}
|
|
|
|
+static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
|
|
+{
|
|
+ u32 divider;
|
|
+
|
|
+ divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
|
|
+ i2c_dev->bus_clk_rate);
|
|
+ /*
|
|
+ * Per the datasheet, the register is always interpreted as an even
|
|
+ * number, by rounding down. In other words, the LSB is ignored. So,
|
|
+ * if the LSB is set, increment the divider to avoid any issue.
|
|
+ */
|
|
+ if (divider & 1)
|
|
+ divider++;
|
|
+ if ((divider < BCM2835_I2C_CDIV_MIN) ||
|
|
+ (divider > BCM2835_I2C_CDIV_MAX)) {
|
|
+ dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
|
|
{
|
|
u32 val;
|
|
@@ -224,7 +249,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|
{
|
|
struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
|
unsigned long time_left;
|
|
- int i;
|
|
+ int i, ret;
|
|
|
|
for (i = 0; i < (num - 1); i++)
|
|
if (msgs[i].flags & I2C_M_RD) {
|
|
@@ -233,6 +258,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
+ ret = bcm2835_i2c_set_divider(i2c_dev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
i2c_dev->curr_msg = msgs;
|
|
i2c_dev->num_msgs = num;
|
|
reinit_completion(&i2c_dev->completion);
|
|
@@ -282,7 +311,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
|
{
|
|
struct bcm2835_i2c_dev *i2c_dev;
|
|
struct resource *mem, *irq;
|
|
- u32 bus_clk_rate, divider;
|
|
int ret;
|
|
struct i2c_adapter *adap;
|
|
|
|
@@ -306,27 +334,12 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
|
}
|
|
|
|
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
|
- &bus_clk_rate);
|
|
+ &i2c_dev->bus_clk_rate);
|
|
if (ret < 0) {
|
|
dev_warn(&pdev->dev,
|
|
"Could not read clock-frequency property\n");
|
|
- bus_clk_rate = 100000;
|
|
- }
|
|
-
|
|
- divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), bus_clk_rate);
|
|
- /*
|
|
- * Per the datasheet, the register is always interpreted as an even
|
|
- * number, by rounding down. In other words, the LSB is ignored. So,
|
|
- * if the LSB is set, increment the divider to avoid any issue.
|
|
- */
|
|
- if (divider & 1)
|
|
- divider++;
|
|
- if ((divider < BCM2835_I2C_CDIV_MIN) ||
|
|
- (divider > BCM2835_I2C_CDIV_MAX)) {
|
|
- dev_err(&pdev->dev, "Invalid clock-frequency\n");
|
|
- return -ENODEV;
|
|
+ i2c_dev->bus_clk_rate = 100000;
|
|
}
|
|
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
|
|
|
|
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
if (!irq) {
|
|
--
|
|
2.9.3
|
|
|
|
From f2a46926aba1f0c33944901d2420a6a887455ddc Mon Sep 17 00:00:00 2001
|
|
From: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Date: Tue, 22 Nov 2016 12:45:28 -0800
|
|
Subject: [PATCH 08819/13183] clk: bcm2835: Fix ->fixed_divider of pllh_aux
|
|
|
|
There is no fixed divider on pllh_aux.
|
|
|
|
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index 8c7763f..836d075 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -1596,7 +1596,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
|
.a2w_reg = A2W_PLLH_AUX,
|
|
.load_mask = CM_PLLH_LOADAUX,
|
|
.hold_mask = 0,
|
|
- .fixed_divider = 10),
|
|
+ .fixed_divider = 1),
|
|
[BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(
|
|
.name = "pllh_pix",
|
|
.source_pll = "pllh",
|
|
--
|
|
2.9.3
|
|
|
|
commit 84c39b8b7d46883f7a7514c7d55909831aa846fd
|
|
Author: Arvind Yadav <arvind.yadav.cs@gmail.com>
|
|
Date: Wed Sep 21 23:03:57 2016 +0530
|
|
|
|
clocksource/drivers/bcm2835_timer: Unmap region obtained by of_iomap
|
|
|
|
Free memory mapping, if bcm2835_timer_init is not successful.
|
|
|
|
Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
|
|
|
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c
|
|
index e71acf2..f2f29d2 100644
|
|
--- a/drivers/clocksource/bcm2835_timer.c
|
|
+++ b/drivers/clocksource/bcm2835_timer.c
|
|
@@ -96,7 +96,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|
ret = of_property_read_u32(node, "clock-frequency", &freq);
|
|
if (ret) {
|
|
pr_err("Can't read clock-frequency");
|
|
- return ret;
|
|
+ goto err_iounmap;
|
|
}
|
|
|
|
system_clock = base + REG_COUNTER_LO;
|
|
@@ -108,13 +108,15 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|
irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
|
|
if (irq <= 0) {
|
|
pr_err("Can't parse IRQ");
|
|
- return -EINVAL;
|
|
+ ret = -EINVAL;
|
|
+ goto err_iounmap;
|
|
}
|
|
|
|
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
|
|
if (!timer) {
|
|
pr_err("Can't allocate timer struct\n");
|
|
- return -ENOMEM;
|
|
+ ret = -ENOMEM;
|
|
+ goto err_iounmap;
|
|
}
|
|
|
|
timer->control = base + REG_CONTROL;
|
|
@@ -133,7 +135,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|
ret = setup_irq(irq, &timer->act);
|
|
if (ret) {
|
|
pr_err("Can't set up timer IRQ\n");
|
|
- return ret;
|
|
+ goto err_iounmap;
|
|
}
|
|
|
|
clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
|
|
@@ -141,6 +143,10 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|
pr_info("bcm2835: system timer (irq = %d)\n", irq);
|
|
|
|
return 0;
|
|
+
|
|
+err_iounmap:
|
|
+ iounmap(base);
|
|
+ return ret;
|
|
}
|
|
CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer",
|
|
bcm2835_timer_init);
|
|
From 155e8b3b0ee320ae866b97dd31eba8a1f080a772 Mon Sep 17 00:00:00 2001
|
|
From: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Date: Thu, 1 Dec 2016 22:00:19 +0100
|
|
Subject: [PATCH 11733/13183] clk: bcm: Support rate change propagation on
|
|
bcm2835 clocks
|
|
|
|
Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set
|
|
to a precise rate (in our case 108MHz). With the current implementation,
|
|
where peripheral clocks are not allowed to forward rate change requests
|
|
to their parents, it is impossible to match this requirement unless the
|
|
bootloader has configured things correctly, or a specific rate has been
|
|
assigned through the DT (with the assigned-clk-rates property).
|
|
|
|
Add a new field to struct bcm2835_clock_data to specify which parent
|
|
clocks accept rate change propagation, and support set rate propagation
|
|
in bcm2835_clock_determine_rate().
|
|
|
|
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 67 ++++++++++++++++++++++++++++++++++++++++---
|
|
1 file changed, 63 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index 2acaa77..df96fe6 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -436,6 +436,9 @@ struct bcm2835_clock_data {
|
|
const char *const *parents;
|
|
int num_mux_parents;
|
|
|
|
+ /* Bitmap encoding which parents accept rate change propagation. */
|
|
+ unsigned int set_rate_parent;
|
|
+
|
|
u32 ctl_reg;
|
|
u32 div_reg;
|
|
|
|
@@ -1017,10 +1020,60 @@ bcm2835_clk_is_pllc(struct clk_hw *hw)
|
|
return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
|
|
}
|
|
|
|
+static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
|
|
+ int parent_idx,
|
|
+ unsigned long rate,
|
|
+ u32 *div,
|
|
+ unsigned long *prate)
|
|
+{
|
|
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
|
+ struct bcm2835_cprman *cprman = clock->cprman;
|
|
+ const struct bcm2835_clock_data *data = clock->data;
|
|
+ unsigned long best_rate;
|
|
+ u32 curdiv, mindiv, maxdiv;
|
|
+ struct clk_hw *parent;
|
|
+
|
|
+ parent = clk_hw_get_parent_by_index(hw, parent_idx);
|
|
+
|
|
+ if (!(BIT(parent_idx) & data->set_rate_parent)) {
|
|
+ *prate = clk_hw_get_rate(parent);
|
|
+ *div = bcm2835_clock_choose_div(hw, rate, *prate, true);
|
|
+
|
|
+ return bcm2835_clock_rate_from_divisor(clock, *prate,
|
|
+ *div);
|
|
+ }
|
|
+
|
|
+ if (data->frac_bits)
|
|
+ dev_warn(cprman->dev,
|
|
+ "frac bits are not used when propagating rate change");
|
|
+
|
|
+ /* clamp to min divider of 2 if we're dealing with a mash clock */
|
|
+ mindiv = data->is_mash_clock ? 2 : 1;
|
|
+ maxdiv = BIT(data->int_bits) - 1;
|
|
+
|
|
+ /* TODO: Be smart, and only test a subset of the available divisors. */
|
|
+ for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) {
|
|
+ unsigned long tmp_rate;
|
|
+
|
|
+ tmp_rate = clk_hw_round_rate(parent, rate * curdiv);
|
|
+ tmp_rate /= curdiv;
|
|
+ if (curdiv == mindiv ||
|
|
+ (tmp_rate > best_rate && tmp_rate <= rate))
|
|
+ best_rate = tmp_rate;
|
|
+
|
|
+ if (best_rate == rate)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ *div = curdiv << CM_DIV_FRAC_BITS;
|
|
+ *prate = curdiv * best_rate;
|
|
+
|
|
+ return best_rate;
|
|
+}
|
|
+
|
|
static int bcm2835_clock_determine_rate(struct clk_hw *hw,
|
|
struct clk_rate_request *req)
|
|
{
|
|
- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
|
struct clk_hw *parent, *best_parent = NULL;
|
|
bool current_parent_is_pllc;
|
|
unsigned long rate, best_rate = 0;
|
|
@@ -1048,9 +1101,8 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
|
|
if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
|
|
continue;
|
|
|
|
- prate = clk_hw_get_rate(parent);
|
|
- div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
|
|
- rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
|
|
+ rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate,
|
|
+ &div, &prate);
|
|
if (rate > best_rate && rate <= req->rate) {
|
|
best_parent = parent;
|
|
best_prate = prate;
|
|
@@ -1262,6 +1314,13 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
|
init.name = data->name;
|
|
init.flags = data->flags | CLK_IGNORE_UNUSED;
|
|
|
|
+ /*
|
|
+ * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
|
|
+ * rate changes on at least of the parents.
|
|
+ */
|
|
+ if (data->set_rate_parent)
|
|
+ init.flags |= CLK_SET_RATE_PARENT;
|
|
+
|
|
if (data->is_vpu_clock) {
|
|
init.ops = &bcm2835_vpu_clock_clk_ops;
|
|
} else {
|
|
--
|
|
2.9.3
|
|
|
|
From d86d46af84855403c00018be1c3e7bc190f2a6cd Mon Sep 17 00:00:00 2001
|
|
From: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Date: Thu, 1 Dec 2016 22:00:20 +0100
|
|
Subject: [PATCH 11734/13183] clk: bcm: Allow rate change propagation to
|
|
PLLH_AUX on VEC clock
|
|
|
|
The VEC clock requires needs to be set at exactly 108MHz. Allow rate
|
|
change propagation on PLLH_AUX to match this requirement wihtout
|
|
impacting other IPs (PLLH is currently only used by the HDMI encoder,
|
|
which cannot be enabled when the VEC encoder is enabled).
|
|
|
|
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 7 ++++++-
|
|
1 file changed, 6 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index df96fe6..eaf82f4 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -1861,7 +1861,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
|
.ctl_reg = CM_VECCTL,
|
|
.div_reg = CM_VECDIV,
|
|
.int_bits = 4,
|
|
- .frac_bits = 0),
|
|
+ .frac_bits = 0,
|
|
+ /*
|
|
+ * Allow rate change propagation only on PLLH_AUX which is
|
|
+ * assigned index 7 in the parent array.
|
|
+ */
|
|
+ .set_rate_parent = BIT(7)),
|
|
|
|
/* dsi clocks */
|
|
[BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
|
|
--
|
|
2.9.3
|
|
|
|
From 2aab7a2055a1705c9e30920d95a596226999eb21 Mon Sep 17 00:00:00 2001
|
|
From: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Date: Mon, 12 Dec 2016 09:00:53 +0100
|
|
Subject: [PATCH 12092/13183] clk: bcm: Fix 'maybe-uninitialized' warning in
|
|
bcm2835_clock_choose_div_and_prate()
|
|
|
|
best_rate is reported as potentially uninitialized by gcc.
|
|
|
|
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
|
Fixes: 155e8b3b0ee3 ("clk: bcm: Support rate change propagation on bcm2835 clocks")
|
|
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
|
|
Reviewed-by: Eric Anholt <eric@anholt.net>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
---
|
|
drivers/clk/bcm/clk-bcm2835.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
|
index eaf82f4..0d14409 100644
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
|
@@ -1029,7 +1029,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
|
|
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
|
struct bcm2835_cprman *cprman = clock->cprman;
|
|
const struct bcm2835_clock_data *data = clock->data;
|
|
- unsigned long best_rate;
|
|
+ unsigned long best_rate = 0;
|
|
u32 curdiv, mindiv, maxdiv;
|
|
struct clk_hw *parent;
|
|
|
|
--
|
|
2.9.3
|
|
|