Home | History | Annotate | Download | only in i2c
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2017 - Beniamino Galvani <b.galvani (at) gmail.com>
      4  */
      5 #include <common.h>
      6 #include <asm/io.h>
      7 #include <clk.h>
      8 #include <dm.h>
      9 #include <i2c.h>
     10 
     11 #define I2C_TIMEOUT_MS		100
     12 
     13 /* Control register fields */
     14 #define REG_CTRL_START		BIT(0)
     15 #define REG_CTRL_ACK_IGNORE	BIT(1)
     16 #define REG_CTRL_STATUS		BIT(2)
     17 #define REG_CTRL_ERROR		BIT(3)
     18 #define REG_CTRL_CLKDIV_SHIFT	12
     19 #define REG_CTRL_CLKDIV_MASK	GENMASK(21, 12)
     20 #define REG_CTRL_CLKDIVEXT_SHIFT 28
     21 #define REG_CTRL_CLKDIVEXT_MASK	GENMASK(29, 28)
     22 
     23 enum {
     24 	TOKEN_END = 0,
     25 	TOKEN_START,
     26 	TOKEN_SLAVE_ADDR_WRITE,
     27 	TOKEN_SLAVE_ADDR_READ,
     28 	TOKEN_DATA,
     29 	TOKEN_DATA_LAST,
     30 	TOKEN_STOP,
     31 };
     32 
     33 struct i2c_regs {
     34 	u32 ctrl;
     35 	u32 slave_addr;
     36 	u32 tok_list0;
     37 	u32 tok_list1;
     38 	u32 tok_wdata0;
     39 	u32 tok_wdata1;
     40 	u32 tok_rdata0;
     41 	u32 tok_rdata1;
     42 };
     43 
     44 struct meson_i2c {
     45 	struct clk clk;
     46 	struct i2c_regs *regs;
     47 	struct i2c_msg *msg;	/* Current I2C message */
     48 	bool last;		/* Whether the message is the last */
     49 	uint count;		/* Number of bytes in the current transfer */
     50 	uint pos;		/* Position of current transfer in message */
     51 	u32 tokens[2];		/* Sequence of tokens to be written */
     52 	uint num_tokens;	/* Number of tokens to be written */
     53 };
     54 
     55 static void meson_i2c_reset_tokens(struct meson_i2c *i2c)
     56 {
     57 	i2c->tokens[0] = 0;
     58 	i2c->tokens[1] = 0;
     59 	i2c->num_tokens = 0;
     60 }
     61 
     62 static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
     63 {
     64 	if (i2c->num_tokens < 8)
     65 		i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4);
     66 	else
     67 		i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4);
     68 
     69 	i2c->num_tokens++;
     70 }
     71 
     72 /*
     73  * Retrieve data for the current transfer (which can be at most 8
     74  * bytes) from the device internal buffer.
     75  */
     76 static void meson_i2c_get_data(struct meson_i2c *i2c, u8 *buf, int len)
     77 {
     78 	u32 rdata0, rdata1;
     79 	int i;
     80 
     81 	rdata0 = readl(&i2c->regs->tok_rdata0);
     82 	rdata1 = readl(&i2c->regs->tok_rdata1);
     83 
     84 	debug("meson i2c: read data %08x %08x len %d\n", rdata0, rdata1, len);
     85 
     86 	for (i = 0; i < min(4, len); i++)
     87 		*buf++ = (rdata0 >> i * 8) & 0xff;
     88 
     89 	for (i = 4; i < min(8, len); i++)
     90 		*buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
     91 }
     92 
     93 /*
     94  * Write data for the current transfer (which can be at most 8 bytes)
     95  * to the device internal buffer.
     96  */
     97 static void meson_i2c_put_data(struct meson_i2c *i2c, u8 *buf, int len)
     98 {
     99 	u32 wdata0 = 0, wdata1 = 0;
    100 	int i;
    101 
    102 	for (i = 0; i < min(4, len); i++)
    103 		wdata0 |= *buf++ << (i * 8);
    104 
    105 	for (i = 4; i < min(8, len); i++)
    106 		wdata1 |= *buf++ << ((i - 4) * 8);
    107 
    108 	writel(wdata0, &i2c->regs->tok_wdata0);
    109 	writel(wdata1, &i2c->regs->tok_wdata1);
    110 
    111 	debug("meson i2c: write data %08x %08x len %d\n", wdata0, wdata1, len);
    112 }
    113 
    114 /*
    115  * Prepare the next transfer: pick the next 8 bytes in the remaining
    116  * part of message and write tokens and data (if needed) to the
    117  * device.
    118  */
    119 static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
    120 {
    121 	bool write = !(i2c->msg->flags & I2C_M_RD);
    122 	int i;
    123 
    124 	i2c->count = min(i2c->msg->len - i2c->pos, 8u);
    125 
    126 	for (i = 0; i + 1 < i2c->count; i++)
    127 		meson_i2c_add_token(i2c, TOKEN_DATA);
    128 
    129 	if (i2c->count) {
    130 		if (write || i2c->pos + i2c->count < i2c->msg->len)
    131 			meson_i2c_add_token(i2c, TOKEN_DATA);
    132 		else
    133 			meson_i2c_add_token(i2c, TOKEN_DATA_LAST);
    134 	}
    135 
    136 	if (write)
    137 		meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
    138 
    139 	if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len)
    140 		meson_i2c_add_token(i2c, TOKEN_STOP);
    141 
    142 	writel(i2c->tokens[0], &i2c->regs->tok_list0);
    143 	writel(i2c->tokens[1], &i2c->regs->tok_list1);
    144 }
    145 
    146 static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
    147 {
    148 	int token;
    149 
    150 	token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
    151 		TOKEN_SLAVE_ADDR_WRITE;
    152 
    153 	writel(msg->addr << 1, &i2c->regs->slave_addr);
    154 	meson_i2c_add_token(i2c, TOKEN_START);
    155 	meson_i2c_add_token(i2c, token);
    156 }
    157 
    158 static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
    159 			      int last)
    160 {
    161 	ulong start;
    162 
    163 	debug("meson i2c: %s addr %u len %u\n",
    164 	      (msg->flags & I2C_M_RD) ? "read" : "write",
    165 	      msg->addr, msg->len);
    166 
    167 	i2c->msg = msg;
    168 	i2c->last = last;
    169 	i2c->pos = 0;
    170 	i2c->count = 0;
    171 
    172 	meson_i2c_reset_tokens(i2c);
    173 	meson_i2c_do_start(i2c, msg);
    174 
    175 	do {
    176 		meson_i2c_prepare_xfer(i2c);
    177 
    178 		/* start the transfer */
    179 		setbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
    180 		start = get_timer(0);
    181 		while (readl(&i2c->regs->ctrl) & REG_CTRL_STATUS) {
    182 			if (get_timer(start) > I2C_TIMEOUT_MS) {
    183 				clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
    184 				debug("meson i2c: timeout\n");
    185 				return -ETIMEDOUT;
    186 			}
    187 			udelay(1);
    188 		}
    189 		meson_i2c_reset_tokens(i2c);
    190 		clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
    191 
    192 		if (readl(&i2c->regs->ctrl) & REG_CTRL_ERROR) {
    193 			debug("meson i2c: error\n");
    194 			return -EREMOTEIO;
    195 		}
    196 
    197 		if ((msg->flags & I2C_M_RD) && i2c->count) {
    198 			meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
    199 					   i2c->count);
    200 		}
    201 		i2c->pos += i2c->count;
    202 	} while (i2c->pos < msg->len);
    203 
    204 	return 0;
    205 }
    206 
    207 static int meson_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
    208 			  int nmsgs)
    209 {
    210 	struct meson_i2c *i2c = dev_get_priv(bus);
    211 	int i, ret = 0;
    212 
    213 	for (i = 0; i < nmsgs; i++) {
    214 		ret = meson_i2c_xfer_msg(i2c, msg + i, i == nmsgs - 1);
    215 		if (ret)
    216 			return ret;
    217 	}
    218 
    219 	return 0;
    220 }
    221 
    222 static int meson_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
    223 {
    224 	struct meson_i2c *i2c = dev_get_priv(bus);
    225 	ulong clk_rate;
    226 	unsigned int div;
    227 
    228 	clk_rate = clk_get_rate(&i2c->clk);
    229 	if (IS_ERR_VALUE(clk_rate))
    230 		return -EINVAL;
    231 
    232 	div = DIV_ROUND_UP(clk_rate, speed * 4);
    233 
    234 	/* clock divider has 12 bits */
    235 	if (div >= (1 << 12)) {
    236 		debug("meson i2c: requested bus frequency too low\n");
    237 		div = (1 << 12) - 1;
    238 	}
    239 
    240 	clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIV_MASK,
    241 			(div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
    242 
    243 	clrsetbits_le32(&i2c->regs->ctrl, REG_CTRL_CLKDIVEXT_MASK,
    244 			(div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
    245 
    246 	debug("meson i2c: set clk %u, src %lu, div %u\n", speed, clk_rate, div);
    247 
    248 	return 0;
    249 }
    250 
    251 static int meson_i2c_probe(struct udevice *bus)
    252 {
    253 	struct meson_i2c *i2c = dev_get_priv(bus);
    254 	int ret;
    255 
    256 	ret = clk_get_by_index(bus, 0, &i2c->clk);
    257 	if (ret < 0)
    258 		return ret;
    259 
    260 	ret = clk_enable(&i2c->clk);
    261 	if (ret)
    262 		return ret;
    263 
    264 	i2c->regs = dev_read_addr_ptr(bus);
    265 	clrbits_le32(&i2c->regs->ctrl, REG_CTRL_START);
    266 
    267 	return 0;
    268 }
    269 
    270 static const struct dm_i2c_ops meson_i2c_ops = {
    271 	.xfer          = meson_i2c_xfer,
    272 	.set_bus_speed = meson_i2c_set_bus_speed,
    273 };
    274 
    275 static const struct udevice_id meson_i2c_ids[] = {
    276 	{ .compatible = "amlogic,meson6-i2c" },
    277 	{ .compatible = "amlogic,meson-gx-i2c" },
    278 	{ .compatible = "amlogic,meson-gxbb-i2c" },
    279 	{ }
    280 };
    281 
    282 U_BOOT_DRIVER(i2c_meson) = {
    283 	.name = "i2c_meson",
    284 	.id   = UCLASS_I2C,
    285 	.of_match = meson_i2c_ids,
    286 	.probe = meson_i2c_probe,
    287 	.priv_auto_alloc_size = sizeof(struct meson_i2c),
    288 	.ops = &meson_i2c_ops,
    289 };
    290