]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
26f820f3 | 2 | /* |
4e3d8406 MY |
3 | * Copyright (C) 2014 Panasonic Corporation |
4 | * Copyright (C) 2015-2016 Socionext Inc. | |
5 | * Author: Masahiro Yamada <[email protected]> | |
26f820f3 MY |
6 | */ |
7 | ||
336d4615 | 8 | #include <dm/device_compat.h> |
804cf1c4 MY |
9 | #include <linux/delay.h> |
10 | #include <linux/errno.h> | |
f6e7f07c | 11 | #include <linux/io.h> |
336399fb | 12 | #include <linux/sizes.h> |
804cf1c4 MY |
13 | #include <linux/types.h> |
14 | #include <dm.h> | |
26f820f3 | 15 | #include <fdtdec.h> |
804cf1c4 | 16 | #include <i2c.h> |
26f820f3 | 17 | |
26f820f3 MY |
18 | struct uniphier_i2c_regs { |
19 | u32 dtrm; /* data transmission */ | |
20 | #define I2C_DTRM_STA (1 << 10) | |
21 | #define I2C_DTRM_STO (1 << 9) | |
22 | #define I2C_DTRM_NACK (1 << 8) | |
23 | #define I2C_DTRM_RD (1 << 0) | |
24 | u32 drec; /* data reception */ | |
25 | #define I2C_DREC_STS (1 << 12) | |
26 | #define I2C_DREC_LRB (1 << 11) | |
27 | #define I2C_DREC_LAB (1 << 9) | |
28 | u32 myad; /* slave address */ | |
29 | u32 clk; /* clock frequency control */ | |
30 | u32 brst; /* bus reset */ | |
31 | #define I2C_BRST_FOEN (1 << 1) | |
32 | #define I2C_BRST_BRST (1 << 0) | |
33 | u32 hold; /* hold time control */ | |
34 | u32 bsts; /* bus status monitor */ | |
35 | u32 noise; /* noise filter control */ | |
36 | u32 setup; /* setup time control */ | |
37 | }; | |
38 | ||
39 | #define IOBUS_FREQ 100000000 | |
40 | ||
804cf1c4 MY |
41 | struct uniphier_i2c_priv { |
42 | struct udevice *dev; | |
26f820f3 MY |
43 | struct uniphier_i2c_regs __iomem *regs; /* register base */ |
44 | unsigned long input_clk; /* master clock (Hz) */ | |
45 | unsigned long wait_us; /* wait for every byte transfer (us) */ | |
46 | }; | |
47 | ||
48 | static int uniphier_i2c_probe(struct udevice *dev) | |
49 | { | |
50 | fdt_addr_t addr; | |
804cf1c4 | 51 | struct uniphier_i2c_priv *priv = dev_get_priv(dev); |
26f820f3 | 52 | |
2548493a | 53 | addr = dev_read_addr(dev); |
336399fb MY |
54 | if (addr == FDT_ADDR_T_NONE) |
55 | return -EINVAL; | |
26f820f3 | 56 | |
4e3d8406 | 57 | priv->regs = devm_ioremap(dev, addr, SZ_64); |
26f820f3 MY |
58 | if (!priv->regs) |
59 | return -ENOMEM; | |
60 | ||
61 | priv->input_clk = IOBUS_FREQ; | |
62 | ||
804cf1c4 MY |
63 | priv->dev = dev; |
64 | ||
26f820f3 MY |
65 | /* deassert reset */ |
66 | writel(0x3, &priv->regs->brst); | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
804cf1c4 | 71 | static int send_and_recv_byte(struct uniphier_i2c_priv *priv, u32 dtrm) |
26f820f3 | 72 | { |
804cf1c4 | 73 | writel(dtrm, &priv->regs->dtrm); |
26f820f3 MY |
74 | |
75 | /* | |
76 | * This controller only provides interruption to inform the completion | |
77 | * of each byte transfer. (No status register to poll it.) | |
78 | * Unfortunately, U-Boot does not have a good support of interrupt. | |
79 | * Wait for a while. | |
80 | */ | |
804cf1c4 | 81 | udelay(priv->wait_us); |
26f820f3 | 82 | |
804cf1c4 | 83 | return readl(&priv->regs->drec); |
26f820f3 MY |
84 | } |
85 | ||
804cf1c4 | 86 | static int send_byte(struct uniphier_i2c_priv *priv, u32 dtrm, bool *stop) |
26f820f3 MY |
87 | { |
88 | int ret = 0; | |
89 | u32 drec; | |
90 | ||
804cf1c4 | 91 | drec = send_and_recv_byte(priv, dtrm); |
26f820f3 MY |
92 | |
93 | if (drec & I2C_DREC_LAB) { | |
804cf1c4 | 94 | dev_dbg(priv->dev, "uniphier_i2c: bus arbitration failed\n"); |
26f820f3 MY |
95 | *stop = false; |
96 | ret = -EREMOTEIO; | |
97 | } | |
98 | if (drec & I2C_DREC_LRB) { | |
804cf1c4 | 99 | dev_dbg(priv->dev, "uniphier_i2c: slave did not return ACK\n"); |
26f820f3 MY |
100 | ret = -EREMOTEIO; |
101 | } | |
102 | return ret; | |
103 | } | |
104 | ||
804cf1c4 | 105 | static int uniphier_i2c_transmit(struct uniphier_i2c_priv *priv, uint addr, |
26f820f3 MY |
106 | uint len, const u8 *buf, bool *stop) |
107 | { | |
108 | int ret; | |
109 | ||
804cf1c4 | 110 | dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len); |
26f820f3 | 111 | |
804cf1c4 | 112 | ret = send_byte(priv, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop); |
26f820f3 MY |
113 | if (ret < 0) |
114 | goto fail; | |
115 | ||
116 | while (len--) { | |
804cf1c4 | 117 | ret = send_byte(priv, I2C_DTRM_NACK | *buf++, stop); |
26f820f3 MY |
118 | if (ret < 0) |
119 | goto fail; | |
120 | } | |
121 | ||
122 | fail: | |
123 | if (*stop) | |
804cf1c4 | 124 | writel(I2C_DTRM_STO | I2C_DTRM_NACK, &priv->regs->dtrm); |
26f820f3 MY |
125 | |
126 | return ret; | |
127 | } | |
128 | ||
804cf1c4 | 129 | static int uniphier_i2c_receive(struct uniphier_i2c_priv *priv, uint addr, |
26f820f3 MY |
130 | uint len, u8 *buf, bool *stop) |
131 | { | |
132 | int ret; | |
133 | ||
804cf1c4 | 134 | dev_dbg(priv->dev, "%s: addr = %x, len = %d\n", __func__, addr, len); |
26f820f3 | 135 | |
804cf1c4 | 136 | ret = send_byte(priv, I2C_DTRM_STA | I2C_DTRM_NACK | |
26f820f3 MY |
137 | I2C_DTRM_RD | addr << 1, stop); |
138 | if (ret < 0) | |
139 | goto fail; | |
140 | ||
141 | while (len--) | |
804cf1c4 | 142 | *buf++ = send_and_recv_byte(priv, len ? 0 : I2C_DTRM_NACK); |
26f820f3 MY |
143 | |
144 | fail: | |
145 | if (*stop) | |
804cf1c4 | 146 | writel(I2C_DTRM_STO | I2C_DTRM_NACK, &priv->regs->dtrm); |
26f820f3 MY |
147 | |
148 | return ret; | |
149 | } | |
150 | ||
151 | static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, | |
152 | int nmsgs) | |
153 | { | |
154 | int ret = 0; | |
804cf1c4 | 155 | struct uniphier_i2c_priv *priv = dev_get_priv(bus); |
26f820f3 MY |
156 | bool stop; |
157 | ||
158 | for (; nmsgs > 0; nmsgs--, msg++) { | |
159 | /* If next message is read, skip the stop condition */ | |
160 | stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true; | |
161 | ||
162 | if (msg->flags & I2C_M_RD) | |
804cf1c4 | 163 | ret = uniphier_i2c_receive(priv, msg->addr, msg->len, |
26f820f3 MY |
164 | msg->buf, &stop); |
165 | else | |
804cf1c4 | 166 | ret = uniphier_i2c_transmit(priv, msg->addr, msg->len, |
26f820f3 MY |
167 | msg->buf, &stop); |
168 | ||
169 | if (ret < 0) | |
170 | break; | |
171 | } | |
172 | ||
173 | return ret; | |
174 | } | |
175 | ||
176 | static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) | |
177 | { | |
804cf1c4 | 178 | struct uniphier_i2c_priv *priv = dev_get_priv(bus); |
26f820f3 MY |
179 | |
180 | /* max supported frequency is 400 kHz */ | |
f3d46152 | 181 | if (speed > I2C_SPEED_FAST_RATE) |
26f820f3 MY |
182 | return -EINVAL; |
183 | ||
184 | /* bus reset: make sure the bus is idle when change the frequency */ | |
185 | writel(0x1, &priv->regs->brst); | |
186 | ||
187 | writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed), | |
188 | &priv->regs->clk); | |
189 | ||
190 | writel(0x3, &priv->regs->brst); | |
191 | ||
192 | /* | |
193 | * Theoretically, each byte can be transferred in | |
194 | * 1000000 * 9 / speed usec. For safety, wait more than double. | |
195 | */ | |
196 | priv->wait_us = 20000000 / speed; | |
197 | ||
198 | return 0; | |
199 | } | |
200 | ||
201 | ||
202 | static const struct dm_i2c_ops uniphier_i2c_ops = { | |
203 | .xfer = uniphier_i2c_xfer, | |
204 | .set_bus_speed = uniphier_i2c_set_bus_speed, | |
205 | }; | |
206 | ||
207 | static const struct udevice_id uniphier_i2c_of_match[] = { | |
6462cded MY |
208 | { .compatible = "socionext,uniphier-i2c" }, |
209 | { /* sentinel */ } | |
26f820f3 MY |
210 | }; |
211 | ||
212 | U_BOOT_DRIVER(uniphier_i2c) = { | |
213 | .name = "uniphier-i2c", | |
214 | .id = UCLASS_I2C, | |
215 | .of_match = uniphier_i2c_of_match, | |
216 | .probe = uniphier_i2c_probe, | |
41575d8e | 217 | .priv_auto = sizeof(struct uniphier_i2c_priv), |
26f820f3 MY |
218 | .ops = &uniphier_i2c_ops, |
219 | }; |