|
@@ -214,6 +214,69 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* calculate and set clock divisors */
|
|
|
+static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
|
|
|
+{
|
|
|
+ int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
|
|
|
+ int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
|
|
|
+
|
|
|
+ for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
|
|
|
+ /*
|
|
|
+ * An mdiv value of less than 2 seems to not work well
|
|
|
+ * with ds1337 RTCs, so we constrain it to larger values.
|
|
|
+ */
|
|
|
+ for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
|
|
|
+ /*
|
|
|
+ * For given ndiv and mdiv values check the
|
|
|
+ * two closest thp values.
|
|
|
+ */
|
|
|
+ tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
|
|
|
+ tclk *= (1 << ndiv_idx);
|
|
|
+ thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
|
|
|
+
|
|
|
+ for (inc = 0; inc <= 1; inc++) {
|
|
|
+ thp_idx = thp_base + inc;
|
|
|
+ if (thp_idx < 5 || thp_idx > 0xff)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ foscl = i2c->sys_freq / (2 * (thp_idx + 1));
|
|
|
+ foscl = foscl / (1 << ndiv_idx);
|
|
|
+ foscl = foscl / (mdiv_idx + 1) / 10;
|
|
|
+ diff = abs(foscl - i2c->twsi_freq);
|
|
|
+ if (diff < delta_hz) {
|
|
|
+ delta_hz = diff;
|
|
|
+ thp = thp_idx;
|
|
|
+ mdiv = mdiv_idx;
|
|
|
+ ndiv = ndiv_idx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
|
|
|
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
|
|
|
+}
|
|
|
+
|
|
|
+static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
|
|
|
+{
|
|
|
+ u8 status;
|
|
|
+ int tries;
|
|
|
+
|
|
|
+ /* disable high level controller, enable bus access */
|
|
|
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
|
|
|
+
|
|
|
+ /* reset controller */
|
|
|
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
|
|
|
+
|
|
|
+ for (tries = 10; tries; tries--) {
|
|
|
+ udelay(1);
|
|
|
+ status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
|
|
|
+ if (status == STAT_IDLE)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* octeon_i2c_start - send START to the bus
|
|
|
* @i2c: The struct octeon_i2c
|
|
@@ -428,69 +491,6 @@ static struct i2c_adapter octeon_i2c_ops = {
|
|
|
.algo = &octeon_i2c_algo,
|
|
|
};
|
|
|
|
|
|
-/* calculate and set clock divisors */
|
|
|
-static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
|
|
|
-{
|
|
|
- int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
|
|
|
- int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
|
|
|
-
|
|
|
- for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
|
|
|
- /*
|
|
|
- * An mdiv value of less than 2 seems to not work well
|
|
|
- * with ds1337 RTCs, so we constrain it to larger values.
|
|
|
- */
|
|
|
- for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
|
|
|
- /*
|
|
|
- * For given ndiv and mdiv values check the
|
|
|
- * two closest thp values.
|
|
|
- */
|
|
|
- tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
|
|
|
- tclk *= (1 << ndiv_idx);
|
|
|
- thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
|
|
|
-
|
|
|
- for (inc = 0; inc <= 1; inc++) {
|
|
|
- thp_idx = thp_base + inc;
|
|
|
- if (thp_idx < 5 || thp_idx > 0xff)
|
|
|
- continue;
|
|
|
-
|
|
|
- foscl = i2c->sys_freq / (2 * (thp_idx + 1));
|
|
|
- foscl = foscl / (1 << ndiv_idx);
|
|
|
- foscl = foscl / (mdiv_idx + 1) / 10;
|
|
|
- diff = abs(foscl - i2c->twsi_freq);
|
|
|
- if (diff < delta_hz) {
|
|
|
- delta_hz = diff;
|
|
|
- thp = thp_idx;
|
|
|
- mdiv = mdiv_idx;
|
|
|
- ndiv = ndiv_idx;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
|
|
|
- octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
|
|
|
-}
|
|
|
-
|
|
|
-static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
|
|
|
-{
|
|
|
- u8 status;
|
|
|
- int tries;
|
|
|
-
|
|
|
- /* disable high level controller, enable bus access */
|
|
|
- octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
|
|
|
-
|
|
|
- /* reset controller */
|
|
|
- octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
|
|
|
-
|
|
|
- for (tries = 10; tries; tries--) {
|
|
|
- udelay(1);
|
|
|
- status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
|
|
|
- if (status == STAT_IDLE)
|
|
|
- return 0;
|
|
|
- }
|
|
|
- dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
|
|
|
- return -EIO;
|
|
|
-}
|
|
|
-
|
|
|
static int octeon_i2c_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device_node *node = pdev->dev.of_node;
|