Skip to content

Instantly share code, notes, and snippets.

@P33M
Last active December 12, 2015 06:38
Show Gist options
  • Save P33M/137a47974eca9a6ee990 to your computer and use it in GitHub Desktop.
Save P33M/137a47974eca9a6ee990 to your computer and use it in GitHub Desktop.
Suggested i2c_bcm2708 clock handling
diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c
index 63414a3..6bfb77f 100644
--- a/drivers/i2c/busses/i2c-bcm2708.c
+++ b/drivers/i2c/busses/i2c-bcm2708.c
@@ -67,6 +67,8 @@
#define BSC_S_TA 0x00000001
#define I2C_TIMEOUT_MS 150
+#define SCL_TIMEOUT_MS 35
+#define BSC_CLKT_MIN 64
#define DRV_NAME "bcm2708_i2c"
@@ -149,17 +151,23 @@ static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi)
{
unsigned long bus_hz;
u32 cdiv;
+ u32 clkt;
u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
bus_hz = clk_get_rate(bi->clk);
cdiv = bus_hz / baudrate;
-
+
+ clkt = (baudrate/1000) * SCL_TIMEOUT_MS;
+ if(clkt > 65535) clkt = 65535;
+ if(clkt < BSC_CLKT_MIN) clkt = BSC_CLKT_MIN;
+
if (bi->msg->flags & I2C_M_RD)
c |= BSC_C_INTR | BSC_C_READ;
else
c |= BSC_C_INTT;
bcm2708_wr(bi, BSC_DIV, cdiv);
+ bcm2708_wr(bi, BSC_CLKT, clkt);
bcm2708_wr(bi, BSC_A, bi->msg->addr);
bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
bcm2708_wr(bi, BSC_C, c);
@@ -260,6 +268,8 @@ static int __devinit bcm2708_i2c_probe(struct platform_device *pdev)
struct clk *clk;
struct bcm2708_i2c *bi;
struct i2c_adapter *adap;
+ u32 div;
+ unsigned long bus_hz;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -328,13 +338,32 @@ static int __devinit bcm2708_i2c_probe(struct platform_device *pdev)
}
bcm2708_bsc_reset(bi);
-
+ /* Check resulting BSC_DIV value.
+ * Values less than 2 or greater than 65535 will cause undesired operation;
+ * additionally the BSC controller will only use even divisors.
+ */
+ bus_hz = clk_get_rate(clk);
+ div = (bus_hz/baudrate) & ~0x1;
+ if(div < 2) {
+ div = 2;
+ dev_warn(&pdev->dev, "BSC%d requested baudrate %dkHz is too high, setting to %dkHz\n",
+ pdev->id, baudrate/1000, ((unsigned int)bus_hz/div)/1000);
+ }
+ if(div > 65535)
+ {
+ div = 65535;
+ dev_warn(&pdev->dev, "BSC%d requested baudrate %dkHz is too low, setting to %dkHz\n",
+ pdev->id, baudrate/1000, ((unsigned int)bus_hz/div)/1000);
+ }
+ baudrate = bus_hz/div;
+
err = i2c_add_numbered_adapter(adap);
if (err < 0) {
dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
goto out_free_irq;
}
-
+
+
dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %dk)\n",
pdev->id, (unsigned long)regs->start, irq, baudrate/1000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment