• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 Arm Ltd.
4  * Author: Liviu Dudau <liviu.dudau@foss.arm.com>
5  *
6  */
7 
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <i2c.h>
12 #include <asm/io.h>
13 #include <clk.h>
14 #include <linux/io.h>
15 
16 #define I2C_CONTROL_REG		0x00
17 #define I2C_SET_REG		0x00
18 #define I2C_CLEAR_REG		0x04
19 
20 #define SCL	BIT(0)
21 #define SDA	BIT(1)
22 
23 struct versatile_i2c_priv {
24 	phys_addr_t base;
25 	u32 delay;
26 };
27 
versatile_sda_set(struct versatile_i2c_priv * priv,u8 state)28 static inline void versatile_sda_set(struct versatile_i2c_priv *priv, u8 state)
29 {
30 	writel(SDA, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
31 	udelay(priv->delay);
32 }
33 
versatile_sda_get(struct versatile_i2c_priv * priv)34 static inline int versatile_sda_get(struct versatile_i2c_priv *priv)
35 {
36 	int v = !!(readl(priv->base + I2C_CONTROL_REG) & SDA);
37 
38 	udelay(priv->delay);
39 	return v;
40 }
41 
versatile_scl_set(struct versatile_i2c_priv * priv,u8 state)42 static inline void versatile_scl_set(struct versatile_i2c_priv *priv, u8 state)
43 {
44 	writel(SCL, priv->base + (state ? I2C_SET_REG : I2C_CLEAR_REG));
45 	udelay(priv->delay);
46 }
47 
versatile_scl_get(struct versatile_i2c_priv * priv)48 static inline int versatile_scl_get(struct versatile_i2c_priv *priv)
49 {
50 	int v = !!(readl(priv->base + I2C_CONTROL_REG) & SCL);
51 
52 	udelay(priv->delay);
53 	return v;
54 }
55 
56 /* start: SDA goes from high to low while SCL is high */
versatile_i2c_start(struct versatile_i2c_priv * priv)57 static void versatile_i2c_start(struct versatile_i2c_priv *priv)
58 {
59 	udelay(priv->delay);
60 	versatile_sda_set(priv, 1);
61 	versatile_scl_set(priv, 1);
62 	versatile_sda_set(priv, 0);
63 }
64 
65 /* stop: SDA goes from low to high while SCL is high */
versatile_i2c_stop(struct versatile_i2c_priv * priv)66 static void versatile_i2c_stop(struct versatile_i2c_priv *priv)
67 {
68 	versatile_scl_set(priv, 0);
69 	versatile_sda_set(priv, 0);
70 	versatile_scl_set(priv, 1);
71 	versatile_sda_set(priv, 1);
72 }
73 
74 /* read a bit from the SDA line (data or ACK/NACK) */
versatile_i2c_read_bit(struct versatile_i2c_priv * priv)75 static u8 versatile_i2c_read_bit(struct versatile_i2c_priv *priv)
76 {
77 	versatile_scl_set(priv, 0);
78 	versatile_sda_set(priv, 1);
79 	versatile_scl_set(priv, 1);
80 	udelay(priv->delay);
81 	return (u8)versatile_sda_get(priv);
82 }
83 
84 /* write a bit on the SDA line */
versatile_i2c_write_bit(struct versatile_i2c_priv * priv,u8 bit)85 static void versatile_i2c_write_bit(struct versatile_i2c_priv *priv, u8 bit)
86 {
87 	versatile_scl_set(priv, 0);
88 	versatile_sda_set(priv, bit);
89 	versatile_scl_set(priv, 1);
90 	udelay(priv->delay);
91 }
92 
93 /* send a reset sequence of 9 clocks with SDA high */
versatile_i2c_reset_bus(struct versatile_i2c_priv * priv)94 static void versatile_i2c_reset_bus(struct versatile_i2c_priv *priv)
95 {
96 	int i;
97 
98 	for (i = 0; i < 9; i++)
99 		versatile_i2c_write_bit(priv, 1);
100 
101 	versatile_i2c_stop(priv);
102 }
103 
104 /* write byte without start/stop sequence */
versatile_i2c_write_byte(struct versatile_i2c_priv * priv,u8 byte)105 static int versatile_i2c_write_byte(struct versatile_i2c_priv *priv, u8 byte)
106 {
107 	u8 nak, i;
108 
109 	for (i = 0; i < 8; i++) {
110 		versatile_i2c_write_bit(priv, byte & 0x80);
111 		byte <<= 1;
112 	}
113 
114 	/* read ACK */
115 	nak = versatile_i2c_read_bit(priv);
116 	versatile_scl_set(priv, 0);
117 
118 	return nak;	/* not a nack is an ack */
119 }
120 
versatile_i2c_read_byte(struct versatile_i2c_priv * priv,u8 * byte,u8 ack)121 static int versatile_i2c_read_byte(struct versatile_i2c_priv *priv,
122 				   u8 *byte, u8 ack)
123 {
124 	u8 i;
125 
126 	*byte = 0;
127 	for (i = 0; i < 8; i++) {
128 		*byte <<= 1;
129 		*byte |= versatile_i2c_read_bit(priv);
130 	}
131 	/* write the nack */
132 	versatile_i2c_write_bit(priv, ack);
133 
134 	return 0;
135 }
136 
versatile_i2c_send_slave_addr(struct versatile_i2c_priv * priv,struct i2c_msg * msg)137 static int versatile_i2c_send_slave_addr(struct versatile_i2c_priv *priv,
138 					 struct i2c_msg *msg)
139 {
140 	u8 addr;
141 	int ret;
142 
143 	if (msg->flags & I2C_M_TEN) {
144 		/* 10-bit address, send extended address code first */
145 		addr = 0xf0 | ((msg->addr >> 7) & 0x06);
146 		ret = versatile_i2c_write_byte(priv, addr);
147 		if (ret) {
148 			versatile_i2c_stop(priv);
149 			return -EIO;
150 		}
151 
152 		/* remaining bits */
153 		ret = versatile_i2c_write_byte(priv, msg->addr & 0xff);
154 		if (ret) {
155 			versatile_i2c_stop(priv);
156 			return -EIO;
157 		}
158 		/* reads need to resend the addr */
159 		if (msg->flags & I2C_M_RD) {
160 			versatile_i2c_start(priv);
161 			addr |= 1;
162 			ret = versatile_i2c_write_byte(priv, addr);
163 			if (ret) {
164 				versatile_i2c_stop(priv);
165 				return -EIO;
166 			}
167 		}
168 	} else {
169 		/* normal 7-bit address */
170 		addr = msg->addr << 1;
171 		if (msg->flags & I2C_M_RD)
172 			addr |= 1;
173 		ret = versatile_i2c_write_byte(priv, addr);
174 		if (ret) {
175 			versatile_i2c_stop(priv);
176 			return -EIO;
177 		}
178 	}
179 
180 	return 0;
181 }
182 
versatile_i2c_message_xfer(struct versatile_i2c_priv * priv,struct i2c_msg * msg)183 static int versatile_i2c_message_xfer(struct versatile_i2c_priv *priv,
184 				      struct i2c_msg *msg)
185 {
186 	int i, ret;
187 	u8 ack;
188 
189 	versatile_i2c_start(priv);
190 	if (versatile_i2c_send_slave_addr(priv, msg))
191 		return -EIO;
192 
193 	for (i = 0; i < msg->len; i++) {
194 		if (msg->flags & I2C_M_RD) {
195 			ack = (msg->len - i - 1) == 0 ? 1 : 0;
196 			ret = versatile_i2c_read_byte(priv, &msg->buf[i], ack);
197 		} else {
198 			ret = versatile_i2c_write_byte(priv, msg->buf[i]);
199 		}
200 
201 		if (ret)
202 			break;
203 	}
204 
205 	versatile_i2c_stop(priv);
206 
207 	return ret;
208 }
209 
versatile_i2c_xfer(struct udevice * bus,struct i2c_msg * msg,int nmsgs)210 static int versatile_i2c_xfer(struct udevice *bus,
211 			      struct i2c_msg *msg, int nmsgs)
212 {
213 	struct versatile_i2c_priv *priv = dev_get_priv(bus);
214 	int ret;
215 
216 	for ( ; nmsgs > 0; nmsgs--, msg++) {
217 		ret = versatile_i2c_message_xfer(priv, msg);
218 		if (ret)
219 			return -EREMOTEIO;
220 	}
221 
222 	return 0;
223 }
224 
versatile_i2c_chip_probe(struct udevice * bus,uint chip,uint chip_flags)225 static int versatile_i2c_chip_probe(struct udevice *bus,
226 				    uint chip, uint chip_flags)
227 {
228 	/* probe the presence of a slave by writing a 0-size message */
229 	struct i2c_msg msg = { .addr = chip, .flags = chip_flags,
230 			       .len = 0, .buf = NULL };
231 	struct versatile_i2c_priv *priv = dev_get_priv(bus);
232 
233 	return versatile_i2c_message_xfer(priv, &msg);
234 }
235 
versatile_i2c_set_bus_speed(struct udevice * bus,unsigned int speed)236 static int versatile_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
237 {
238 	struct versatile_i2c_priv *priv = dev_get_priv(bus);
239 
240 	priv->delay = 1000000 / (speed << 2);
241 
242 	versatile_i2c_reset_bus(priv);
243 
244 	return 0;
245 }
246 
versatile_i2c_probe(struct udevice * dev)247 static int versatile_i2c_probe(struct udevice *dev)
248 {
249 	struct versatile_i2c_priv *priv = dev_get_priv(dev);
250 
251 	priv->base = (phys_addr_t)dev_read_addr(dev);
252 	priv->delay = 25;	/* 25us * 4 = 100kHz */
253 	/*
254 	 * U-Boot still doesn't assign automatically
255 	 * sequence numbers to devices
256 	 */
257 	dev->req_seq = 1;
258 
259 	return 0;
260 }
261 
262 static const struct dm_i2c_ops versatile_i2c_ops = {
263 	.xfer = versatile_i2c_xfer,
264 	.probe_chip = versatile_i2c_chip_probe,
265 	.set_bus_speed = versatile_i2c_set_bus_speed,
266 };
267 
268 static const struct udevice_id versatile_i2c_of_match[] = {
269 	{ .compatible = "arm,versatile-i2c" },
270 	{ }
271 };
272 
273 U_BOOT_DRIVER(versatile_i2c) = {
274 	.name = "i2c-bus-versatile",
275 	.id = UCLASS_I2C,
276 	.of_match = versatile_i2c_of_match,
277 	.probe = versatile_i2c_probe,
278 	.priv_auto_alloc_size = sizeof(struct versatile_i2c_priv),
279 	.ops = &versatile_i2c_ops,
280 };
281