]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/i2c/meson_i2c.c
2 * (C) Copyright 2017 - Beniamino Galvani <b.galvani@gmail.com>
4 * SPDX-License-Identifier: GPL-2.0+
7 #include <asm/arch/i2c.h>
12 #define I2C_TIMEOUT_MS 100
14 /* Control register fields */
15 #define REG_CTRL_START BIT(0)
16 #define REG_CTRL_ACK_IGNORE BIT(1)
17 #define REG_CTRL_STATUS BIT(2)
18 #define REG_CTRL_ERROR BIT(3)
19 #define REG_CTRL_CLKDIV_SHIFT 12
20 #define REG_CTRL_CLKDIV_MASK GENMASK(21, 12)
21 #define REG_CTRL_CLKDIVEXT_SHIFT 28
22 #define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28)
27 TOKEN_SLAVE_ADDR_WRITE
,
28 TOKEN_SLAVE_ADDR_READ
,
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 */
55 static void meson_i2c_reset_tokens(struct meson_i2c
*i2c
)
62 static void meson_i2c_add_token(struct meson_i2c
*i2c
, int token
)
64 if (i2c
->num_tokens
< 8)
65 i2c
->tokens
[0] |= (token
& 0xf) << (i2c
->num_tokens
* 4);
67 i2c
->tokens
[1] |= (token
& 0xf) << ((i2c
->num_tokens
% 8) * 4);
73 * Retrieve data for the current transfer (which can be at most 8
74 * bytes) from the device internal buffer.
76 static void meson_i2c_get_data(struct meson_i2c
*i2c
, u8
*buf
, int len
)
81 rdata0
= readl(&i2c
->regs
->tok_rdata0
);
82 rdata1
= readl(&i2c
->regs
->tok_rdata1
);
84 debug("meson i2c: read data %08x %08x len %d\n", rdata0
, rdata1
, len
);
86 for (i
= 0; i
< min(4, len
); i
++)
87 *buf
++ = (rdata0
>> i
* 8) & 0xff;
89 for (i
= 4; i
< min(8, len
); i
++)
90 *buf
++ = (rdata1
>> (i
- 4) * 8) & 0xff;
94 * Write data for the current transfer (which can be at most 8 bytes)
95 * to the device internal buffer.
97 static void meson_i2c_put_data(struct meson_i2c
*i2c
, u8
*buf
, int len
)
99 u32 wdata0
= 0, wdata1
= 0;
102 for (i
= 0; i
< min(4, len
); i
++)
103 wdata0
|= *buf
++ << (i
* 8);
105 for (i
= 4; i
< min(8, len
); i
++)
106 wdata1
|= *buf
++ << ((i
- 4) * 8);
108 writel(wdata0
, &i2c
->regs
->tok_wdata0
);
109 writel(wdata1
, &i2c
->regs
->tok_wdata1
);
111 debug("meson i2c: write data %08x %08x len %d\n", wdata0
, wdata1
, len
);
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
119 static void meson_i2c_prepare_xfer(struct meson_i2c
*i2c
)
121 bool write
= !(i2c
->msg
->flags
& I2C_M_RD
);
124 i2c
->count
= min(i2c
->msg
->len
- i2c
->pos
, 8u);
126 for (i
= 0; i
+ 1 < i2c
->count
; i
++)
127 meson_i2c_add_token(i2c
, TOKEN_DATA
);
130 if (write
|| i2c
->pos
+ i2c
->count
< i2c
->msg
->len
)
131 meson_i2c_add_token(i2c
, TOKEN_DATA
);
133 meson_i2c_add_token(i2c
, TOKEN_DATA_LAST
);
137 meson_i2c_put_data(i2c
, i2c
->msg
->buf
+ i2c
->pos
, i2c
->count
);
139 if (i2c
->last
&& i2c
->pos
+ i2c
->count
>= i2c
->msg
->len
)
140 meson_i2c_add_token(i2c
, TOKEN_STOP
);
142 writel(i2c
->tokens
[0], &i2c
->regs
->tok_list0
);
143 writel(i2c
->tokens
[1], &i2c
->regs
->tok_list1
);
146 static void meson_i2c_do_start(struct meson_i2c
*i2c
, struct i2c_msg
*msg
)
150 token
= (msg
->flags
& I2C_M_RD
) ? TOKEN_SLAVE_ADDR_READ
:
151 TOKEN_SLAVE_ADDR_WRITE
;
153 writel(msg
->addr
<< 1, &i2c
->regs
->slave_addr
);
154 meson_i2c_add_token(i2c
, TOKEN_START
);
155 meson_i2c_add_token(i2c
, token
);
158 static int meson_i2c_xfer_msg(struct meson_i2c
*i2c
, struct i2c_msg
*msg
,
163 debug("meson i2c: %s addr %u len %u\n",
164 (msg
->flags
& I2C_M_RD
) ? "read" : "write",
165 msg
->addr
, msg
->len
);
172 meson_i2c_reset_tokens(i2c
);
173 meson_i2c_do_start(i2c
, msg
);
176 meson_i2c_prepare_xfer(i2c
);
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");
189 meson_i2c_reset_tokens(i2c
);
190 clrbits_le32(&i2c
->regs
->ctrl
, REG_CTRL_START
);
192 if (readl(&i2c
->regs
->ctrl
) & REG_CTRL_ERROR
) {
193 debug("meson i2c: error\n");
197 if ((msg
->flags
& I2C_M_RD
) && i2c
->count
) {
198 meson_i2c_get_data(i2c
, i2c
->msg
->buf
+ i2c
->pos
,
201 i2c
->pos
+= i2c
->count
;
202 } while (i2c
->pos
< msg
->len
);
207 static int meson_i2c_xfer(struct udevice
*bus
, struct i2c_msg
*msg
,
210 struct meson_i2c
*i2c
= dev_get_priv(bus
);
213 for (i
= 0; i
< nmsgs
; i
++) {
214 ret
= meson_i2c_xfer_msg(i2c
, msg
+ i
, i
== nmsgs
- 1);
222 static int meson_i2c_set_bus_speed(struct udevice
*bus
, unsigned int speed
)
224 struct meson_i2c
*i2c
= dev_get_priv(bus
);
225 unsigned int clk_rate
= MESON_I2C_CLK_RATE
;
228 div
= DIV_ROUND_UP(clk_rate
, speed
* 4);
230 /* clock divider has 12 bits */
231 if (div
>= (1 << 12)) {
232 debug("meson i2c: requested bus frequency too low\n");
236 clrsetbits_le32(&i2c
->regs
->ctrl
, REG_CTRL_CLKDIV_MASK
,
237 (div
& GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT
);
239 clrsetbits_le32(&i2c
->regs
->ctrl
, REG_CTRL_CLKDIVEXT_MASK
,
240 (div
>> 10) << REG_CTRL_CLKDIVEXT_SHIFT
);
242 debug("meson i2c: set clk %u, src %u, div %u\n", speed
, clk_rate
, div
);
247 static int meson_i2c_probe(struct udevice
*bus
)
249 struct meson_i2c
*i2c
= dev_get_priv(bus
);
251 i2c
->regs
= dev_read_addr_ptr(bus
);
252 clrbits_le32(&i2c
->regs
->ctrl
, REG_CTRL_START
);
257 static const struct dm_i2c_ops meson_i2c_ops
= {
258 .xfer
= meson_i2c_xfer
,
259 .set_bus_speed
= meson_i2c_set_bus_speed
,
262 static const struct udevice_id meson_i2c_ids
[] = {
263 { .compatible
= "amlogic,meson6-i2c" },
264 { .compatible
= "amlogic,meson-gx-i2c" },
265 { .compatible
= "amlogic,meson-gxbb-i2c" },
269 U_BOOT_DRIVER(i2c_meson
) = {
272 .of_match
= meson_i2c_ids
,
273 .probe
= meson_i2c_probe
,
274 .priv_auto_alloc_size
= sizeof(struct meson_i2c
),
275 .ops
= &meson_i2c_ops
,