+// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2017 - Beniamino Galvani <b.galvani@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
-#include <asm/arch/i2c.h>
#include <asm/io.h>
+#include <clk.h>
#include <dm.h>
#include <i2c.h>
-#define I2C_TIMEOUT_MS 500
+#define I2C_TIMEOUT_MS 100
/* Control register fields */
#define REG_CTRL_START BIT(0)
};
struct meson_i2c {
+ struct clk clk;
struct i2c_regs *regs;
- struct i2c_msg *msg;
- bool last;
- uint count;
- uint pos;
- u32 tokens[2];
- uint num_tokens;
+ struct i2c_msg *msg; /* Current I2C message */
+ bool last; /* Whether the message is the last */
+ uint count; /* Number of bytes in the current transfer */
+ uint pos; /* Position of current transfer in message */
+ u32 tokens[2]; /* Sequence of tokens to be written */
+ uint num_tokens; /* Number of tokens to be written */
};
static void meson_i2c_reset_tokens(struct meson_i2c *i2c)
i2c->num_tokens++;
}
+/*
+ * Retrieve data for the current transfer (which can be at most 8
+ * bytes) from the device internal buffer.
+ */
static void meson_i2c_get_data(struct meson_i2c *i2c, u8 *buf, int len)
{
u32 rdata0, rdata1;
*buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
}
+/*
+ * Write data for the current transfer (which can be at most 8 bytes)
+ * to the device internal buffer.
+ */
static void meson_i2c_put_data(struct meson_i2c *i2c, u8 *buf, int len)
{
u32 wdata0 = 0, wdata1 = 0;
debug("meson i2c: write data %08x %08x len %d\n", wdata0, wdata1, len);
}
+/*
+ * Prepare the next transfer: pick the next 8 bytes in the remaining
+ * part of message and write tokens and data (if needed) to the
+ * device.
+ */
static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
{
bool write = !(i2c->msg->flags & I2C_M_RD);
if (readl(&i2c->regs->ctrl) & REG_CTRL_ERROR) {
debug("meson i2c: error\n");
- return -ENXIO;
+ return -EREMOTEIO;
}
if ((msg->flags & I2C_M_RD) && i2c->count) {
for (i = 0; i < nmsgs; i++) {
ret = meson_i2c_xfer_msg(i2c, msg + i, i == nmsgs - 1);
if (ret)
- return -EREMOTEIO;
+ return ret;
}
return 0;
static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct meson_i2c *i2c = dev_get_priv(bus);
- unsigned int clk_rate = MESON_I2C_CLK_RATE;
+ ulong clk_rate;
unsigned int div;
+ clk_rate = clk_get_rate(&i2c->clk);
+ if (IS_ERR_VALUE(clk_rate))
+ return -EINVAL;
+
div = DIV_ROUND_UP(clk_rate, speed * 4);
/* clock divider has 12 bits */
clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIVEXT_MASK,
(div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
- debug("meson i2c: set clk %u, src %u, div %u\n", speed, clk_rate, div);
+ debug("meson i2c: set clk %u, src %lu, div %u\n", speed, clk_rate, div);
return 0;
}
static int meson_i2c_probe(struct udevice *bus)
{
struct meson_i2c *i2c = dev_get_priv(bus);
+ int ret;
+
+ ret = clk_get_by_index(bus, 0, &i2c->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(&i2c->clk);
+ if (ret)
+ return ret;
i2c->regs = dev_read_addr_ptr(bus);
clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);