1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2018 Arm Ltd.
4 * Author: Liviu Dudau <liviu.dudau@foss.arm.com>
14 #include <linux/delay.h>
17 #define I2C_CONTROL_REG 0x00
18 #define I2C_SET_REG 0x00
19 #define I2C_CLEAR_REG 0x04
24 struct versatile_i2c_priv {
29 static inline void versatile_sda_set(struct versatile_i2c_priv *priv, u8 state)
31 writel(SDA, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
35 static inline int versatile_sda_get(struct versatile_i2c_priv *priv)
37 int v = !!(readl(priv->base + I2C_CONTROL_REG) & SDA);
43 static inline void versatile_scl_set(struct versatile_i2c_priv *priv, u8 state)
45 writel(SCL, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
49 static inline int versatile_scl_get(struct versatile_i2c_priv *priv)
51 int v = !!(readl(priv->base + I2C_CONTROL_REG) & SCL);
57 /* start: SDA goes from high to low while SCL is high */
58 static void versatile_i2c_start(struct versatile_i2c_priv *priv)
61 versatile_sda_set(priv, 1);
62 versatile_scl_set(priv, 1);
63 versatile_sda_set(priv, 0);
66 /* stop: SDA goes from low to high while SCL is high */
67 static void versatile_i2c_stop(struct versatile_i2c_priv *priv)
69 versatile_scl_set(priv, 0);
70 versatile_sda_set(priv, 0);
71 versatile_scl_set(priv, 1);
72 versatile_sda_set(priv, 1);
75 /* read a bit from the SDA line (data or ACK/NACK) */
76 static u8 versatile_i2c_read_bit(struct versatile_i2c_priv *priv)
78 versatile_scl_set(priv, 0);
79 versatile_sda_set(priv, 1);
80 versatile_scl_set(priv, 1);
82 return (u8)versatile_sda_get(priv);
85 /* write a bit on the SDA line */
86 static void versatile_i2c_write_bit(struct versatile_i2c_priv *priv, u8 bit)
88 versatile_scl_set(priv, 0);
89 versatile_sda_set(priv, bit);
90 versatile_scl_set(priv, 1);
94 /* send a reset sequence of 9 clocks with SDA high */
95 static void versatile_i2c_reset_bus(struct versatile_i2c_priv *priv)
99 for (i = 0; i < 9; i++)
100 versatile_i2c_write_bit(priv, 1);
102 versatile_i2c_stop(priv);
105 /* write byte without start/stop sequence */
106 static int versatile_i2c_write_byte(struct versatile_i2c_priv *priv, u8 byte)
110 for (i = 0; i < 8; i++) {
111 versatile_i2c_write_bit(priv, byte & 0x80);
116 nak = versatile_i2c_read_bit(priv);
117 versatile_scl_set(priv, 0);
119 return nak; /* not a nack is an ack */
122 static int versatile_i2c_read_byte(struct versatile_i2c_priv *priv,
128 for (i = 0; i < 8; i++) {
130 *byte |= versatile_i2c_read_bit(priv);
133 versatile_i2c_write_bit(priv, ack);
138 static int versatile_i2c_send_slave_addr(struct versatile_i2c_priv *priv,
144 if (msg->flags & I2C_M_TEN) {
145 /* 10-bit address, send extended address code first */
146 addr = 0xf0 | ((msg->addr >> 7) & 0x06);
147 ret = versatile_i2c_write_byte(priv, addr);
149 versatile_i2c_stop(priv);
154 ret = versatile_i2c_write_byte(priv, msg->addr & 0xff);
156 versatile_i2c_stop(priv);
159 /* reads need to resend the addr */
160 if (msg->flags & I2C_M_RD) {
161 versatile_i2c_start(priv);
163 ret = versatile_i2c_write_byte(priv, addr);
165 versatile_i2c_stop(priv);
170 /* normal 7-bit address */
171 addr = msg->addr << 1;
172 if (msg->flags & I2C_M_RD)
174 ret = versatile_i2c_write_byte(priv, addr);
176 versatile_i2c_stop(priv);
184 static int versatile_i2c_message_xfer(struct versatile_i2c_priv *priv,
190 versatile_i2c_start(priv);
191 if (versatile_i2c_send_slave_addr(priv, msg))
194 for (i = 0; i < msg->len; i++) {
195 if (msg->flags & I2C_M_RD) {
196 ack = (msg->len - i - 1) == 0 ? 1 : 0;
197 ret = versatile_i2c_read_byte(priv, &msg->buf[i], ack);
199 ret = versatile_i2c_write_byte(priv, msg->buf[i]);
206 versatile_i2c_stop(priv);
211 static int versatile_i2c_xfer(struct udevice *bus,
212 struct i2c_msg *msg, int nmsgs)
214 struct versatile_i2c_priv *priv = dev_get_priv(bus);
217 for ( ; nmsgs > 0; nmsgs--, msg++) {
218 ret = versatile_i2c_message_xfer(priv, msg);
226 static int versatile_i2c_chip_probe(struct udevice *bus,
227 uint chip, uint chip_flags)
229 /* probe the presence of a slave by writing a 0-size message */
230 struct i2c_msg msg = { .addr = chip, .flags = chip_flags,
231 .len = 0, .buf = NULL };
232 struct versatile_i2c_priv *priv = dev_get_priv(bus);
234 return versatile_i2c_message_xfer(priv, &msg);
237 static int versatile_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
239 struct versatile_i2c_priv *priv = dev_get_priv(bus);
241 priv->delay = 1000000 / (speed << 2);
243 versatile_i2c_reset_bus(priv);
248 static int versatile_i2c_probe(struct udevice *dev)
250 struct versatile_i2c_priv *priv = dev_get_priv(dev);
252 priv->base = (phys_addr_t)dev_read_addr(dev);
253 priv->delay = 25; /* 25us * 4 = 100kHz */
255 * U-Boot still doesn't assign automatically
256 * sequence numbers to devices
263 static const struct dm_i2c_ops versatile_i2c_ops = {
264 .xfer = versatile_i2c_xfer,
265 .probe_chip = versatile_i2c_chip_probe,
266 .set_bus_speed = versatile_i2c_set_bus_speed,
269 static const struct udevice_id versatile_i2c_of_match[] = {
270 { .compatible = "arm,versatile-i2c" },
274 U_BOOT_DRIVER(versatile_i2c) = {
275 .name = "i2c-bus-versatile",
277 .of_match = versatile_i2c_of_match,
278 .probe = versatile_i2c_probe,
279 .priv_auto_alloc_size = sizeof(struct versatile_i2c_priv),
280 .ops = &versatile_i2c_ops,