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