* [PATCH] i2c: busses: i2c-bcm2835: limits cdiv to allowed values
@ 2015-05-22 8:36 s. wicki
[not found] ` <1432283811-22226-1-git-send-email-linux_wi-ADq4ffItWIY@public.gmane.org>
0 siblings, 1 reply; 2+ messages in thread
From: s. wicki @ 2015-05-22 8:36 UTC (permalink / raw)
To: swarren-3lzwWm7+Weoh9ZMKESR00Q; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, s. wicki
fixes: round down divider instead of incrementing
adds: make sure bits 16-31 of cdiv register are always 0
adds: assume minimal divider of 2 if divider resulted in 0
(bcm2835 sets divider to 32768 if cdiv is set to 0)
Signed-off-by: s. wicki <linux_wi-ADq4ffItWIY@public.gmane.org>
---
drivers/i2c/busses/i2c-bcm2835.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index c9336a3..745181c 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -51,6 +51,9 @@
#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */
#define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000))
+#define BCM2835_I2C_CDIV_MIN 0x0002
+#define BCM2835_I2C_CDIV_MAX 0xFFFE
+#define BCM2835_I2C_CDIV_BITMSK 0xFFFE
struct bcm2835_i2c_dev {
struct device *dev;
@@ -251,13 +254,34 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
}
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 == 0) {
+ /*
+ * divider results in 0 by extremely high bus_clk_rate values
+ * such as bus_clk_rate >= 4044967297 and core_clock = 250MHz.
+ * In such a case assume the minimal possible divider since
+ * bcm2835 chip sets divisor internally to 32768 if cdiv is 0.
+ */
+ divider = BCM2835_I2C_CDIV_MIN;
+ } else {
+ /* check if divider meets certain bcm2835 specific criterias */
+ if ((divider & BCM2835_I2C_CDIV_BITMSK) != divider) {
+ if (divider > BCM2835_I2C_CDIV_MAX)
+ /*
+ * Per the datasheet it must be made sure
+ * that bits 16-31 are set to 0. If that is
+ * not the case, then set to the maximum
+ * allowed value.
+ */
+ divider = BCM2835_I2C_CDIV_MAX;
+ else
+ /*
+ * Per datasheet the cdiv is always rounded
+ * down to an even number. Bitmask takes care
+ * of this and clears the LSB
+ */
+ divider &= BCM2835_I2C_CDIV_BITMSK;
+ }
+ }
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
--
2.1.4
^ permalink raw reply related [flat|nested] 2+ messages in thread[parent not found: <1432283811-22226-1-git-send-email-linux_wi-ADq4ffItWIY@public.gmane.org>]
* Re: [PATCH] i2c: busses: i2c-bcm2835: limits cdiv to allowed values [not found] ` <1432283811-22226-1-git-send-email-linux_wi-ADq4ffItWIY@public.gmane.org> @ 2015-05-28 20:17 ` Stephen Warren 0 siblings, 0 replies; 2+ messages in thread From: Stephen Warren @ 2015-05-28 20:17 UTC (permalink / raw) To: s. wicki; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA On 05/22/2015 02:36 AM, s. wicki wrote: > fixes: round down divider instead of incrementing > adds: make sure bits 16-31 of cdiv register are always 0 > adds: assume minimal divider of 2 if divider resulted in 0 > (bcm2835 sets divider to 32768 if cdiv is set to 0) Do you have a reference to a specific document and section? That'd be good to include in the commit description for future reference. > Signed-off-by: s. wicki <linux_wi-ADq4ffItWIY@public.gmane.org> Using your full name rather than an abbreviation is preferred. You didn't send this pach to the I2C maintainer so I imagine he won't see it and hence it won't be applied. It'd also be a good idea to send this to the Raspberry Pi mailing list, linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XZu6nac5fYnt@public.gmane.org > diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c > +#define BCM2835_I2C_CDIV_MIN 0x0002 > +#define BCM2835_I2C_CDIV_MAX 0xFFFE > +#define BCM2835_I2C_CDIV_BITMSK 0xFFFE > 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++; The old code used to round the divider up in the case where the LSB was set. This ensures that the I2C clock rate is no faster than what was requested. > + if (divider == 0) { > + /* > + * divider results in 0 by extremely high bus_clk_rate values > + * such as bus_clk_rate >= 4044967297 and core_clock = 250MHz. > + * In such a case assume the minimal possible divider since > + * bcm2835 chip sets divisor internally to 32768 if cdiv is 0. > + */ > + divider = BCM2835_I2C_CDIV_MIN; What about when divider == 1? Shouldn't that if condition be: if (divider < BCM2835_I2C_CDIV_MIN) ? > + } else { > + /* check if divider meets certain bcm2835 specific criterias */ > + if ((divider & BCM2835_I2C_CDIV_BITMSK) != divider) { > + if (divider > BCM2835_I2C_CDIV_MAX) > + /* > + * Per the datasheet it must be made sure > + * that bits 16-31 are set to 0. If that is > + * not the case, then set to the maximum > + * allowed value. > + */ > + divider = BCM2835_I2C_CDIV_MAX; > + else > + /* > + * Per datasheet the cdiv is always rounded > + * down to an even number. Bitmask takes care > + * of this and clears the LSB > + */ The datasheet describes how the HW interprets the register value (by ignoring the LSB). It doesn't say how SW must program the register. In other words, SW should round up, to avoid HW rounding down. It's not mandatory for SW to round down. > + divider &= BCM2835_I2C_CDIV_BITMSK; > + } > + } > bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); > > irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); I think this would be better as: if (divider < BCM2835_I2C_CDIV_MIN) divider = BCM2835_I2C_CDIV_MIN; if (divider & 1) divider++; if (divider > BCM2835_I2C_CDIV_MAX) divider = BCM2835_I2C_CDIV_MAX; ^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-05-28 20:17 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-22 8:36 [PATCH] i2c: busses: i2c-bcm2835: limits cdiv to allowed values s. wicki
[not found] ` <1432283811-22226-1-git-send-email-linux_wi-ADq4ffItWIY@public.gmane.org>
2015-05-28 20:17 ` Stephen Warren
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).