f523844204a7fa9a65d70257aa73385a9a77f1b3
[oweals/u-boot.git] / drivers / i2c / i2c-versatile.c
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
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
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
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
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 */
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 */
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) */
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 */
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 */
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 */
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
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
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
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
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
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
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
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 };