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