1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 /*
4 * I2C bus driver for Kontron COM modules
5 *
6 * Based on the similar driver in Linux.
7 */
8
9 #include <stdint.h>
10 #include <console/console.h>
11 #include <device/device.h>
12 #include <device/i2c_bus.h>
13 #include <timer.h>
14 #include <delay.h>
15
16 #include "chip.h"
17 #include "kempld.h"
18 #include "kempld_internal.h"
19
20 #define KEMPLD_I2C_PRELOW 0x0b
21 #define KEMPLD_I2C_PREHIGH 0x0c
22 #define KEMPLD_I2C_DATA 0x0e
23
24 #define KEMPLD_I2C_CTRL 0x0d
25 #define I2C_CTRL_IEN 0x40
26 #define I2C_CTRL_EN 0x80
27
28 #define KEMPLD_I2C_STAT 0x0f
29 #define I2C_STAT_IF 0x01
30 #define I2C_STAT_TIP 0x02
31 #define I2C_STAT_ARBLOST 0x20
32 #define I2C_STAT_BUSY 0x40
33 #define I2C_STAT_NACK 0x80
34
35 #define KEMPLD_I2C_CMD 0x0f
36 #define I2C_CMD_START 0x91
37 #define I2C_CMD_STOP 0x41
38 #define I2C_CMD_READ 0x21
39 #define I2C_CMD_WRITE 0x11
40 #define I2C_CMD_READ_ACK 0x21
41 #define I2C_CMD_READ_NACK 0x29
42 #define I2C_CMD_IACK 0x01
43
44 #define EIO 5
45 #define ENXIO 6
46 #define EAGAIN 11
47 #define EBUSY 16
48 #define ETIMEDOUT 110
49
50 enum kempld_i2c_state {
51 STATE_DONE = 0,
52 STATE_INIT,
53 STATE_ADDR,
54 STATE_ADDR10,
55 STATE_START,
56 STATE_WRITE,
57 STATE_READ,
58 STATE_ERROR,
59 };
60
61 struct kempld_i2c_data {
62 const struct i2c_msg *msg;
63 size_t pos;
64 size_t nmsgs;
65 enum kempld_i2c_state state;
66 };
67
68 /*
69 * kempld_get_mutex must be called prior to calling this function.
70 */
kempld_i2c_process(struct kempld_i2c_data * const i2c)71 static int kempld_i2c_process(struct kempld_i2c_data *const i2c)
72 {
73 u8 stat = kempld_read8(KEMPLD_I2C_STAT);
74 const struct i2c_msg *msg = i2c->msg;
75 u8 addr;
76
77 /* Ready? */
78 if (stat & I2C_STAT_TIP)
79 return -EBUSY;
80
81 if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
82 /* Stop has been sent */
83 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_IACK);
84 if (i2c->state == STATE_ERROR)
85 return -EIO;
86 return 0;
87 }
88
89 /* Error? */
90 if (stat & I2C_STAT_ARBLOST) {
91 i2c->state = STATE_ERROR;
92 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
93 return -EAGAIN;
94 }
95
96 if (i2c->state == STATE_INIT) {
97 if (stat & I2C_STAT_BUSY)
98 return -EBUSY;
99
100 i2c->state = STATE_ADDR;
101 }
102
103 if (i2c->state == STATE_ADDR) {
104 /* 10 bit address? */
105 if (i2c->msg->flags & I2C_M_TEN) {
106 addr = 0xf0 | ((i2c->msg->slave >> 7) & 0x6);
107 i2c->state = STATE_ADDR10;
108 } else {
109 addr = (i2c->msg->slave << 1);
110 i2c->state = STATE_START;
111 }
112
113 /* Set read bit if necessary */
114 addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
115
116 kempld_write8(KEMPLD_I2C_DATA, addr);
117 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_START);
118
119 return 0;
120 }
121
122 /* Second part of 10 bit addressing */
123 if (i2c->state == STATE_ADDR10) {
124 kempld_write8(KEMPLD_I2C_DATA, i2c->msg->slave & 0xff);
125 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_WRITE);
126
127 i2c->state = STATE_START;
128 return 0;
129 }
130
131 if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
132 i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
133
134 if (stat & I2C_STAT_NACK) {
135 i2c->state = STATE_ERROR;
136 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
137 return -ENXIO;
138 }
139 } else {
140 msg->buf[i2c->pos++] = kempld_read8(KEMPLD_I2C_DATA);
141 }
142
143 if (i2c->pos >= msg->len) {
144 i2c->nmsgs--;
145 i2c->msg++;
146 i2c->pos = 0;
147 msg = i2c->msg;
148
149 if (i2c->nmsgs) {
150 if (!(msg->flags & I2C_M_NOSTART)) {
151 i2c->state = STATE_ADDR;
152 return 0;
153 }
154 i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
155 } else {
156 i2c->state = STATE_DONE;
157 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
158 return 0;
159 }
160 }
161
162 if (i2c->state == STATE_READ) {
163 kempld_write8(KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
164 I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
165 } else {
166 kempld_write8(KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
167 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_WRITE);
168 }
169
170 return 0;
171 }
172
kempld_i2c_xfer(struct device * const dev,const struct i2c_msg * const msgs,const size_t num)173 static int kempld_i2c_xfer(struct device *const dev,
174 const struct i2c_msg *const msgs,
175 const size_t num)
176 {
177 struct kempld_i2c_data i2c;
178 struct stopwatch sw;
179 int ret;
180
181 if (kempld_get_mutex(100) < 0)
182 return -ENXIO;
183
184 i2c.msg = msgs;
185 i2c.pos = 0;
186 i2c.nmsgs = num;
187 i2c.state = STATE_INIT;
188
189 /* Handle the transfer */
190 stopwatch_init_msecs_expire(&sw, 1000);
191 while (!stopwatch_expired(&sw)) {
192 ret = kempld_i2c_process(&i2c);
193
194 if (i2c.state == STATE_DONE || i2c.state == STATE_ERROR) {
195 if (i2c.state == STATE_DONE) {
196 printk(BIOS_SPEW, "kempld_i2c: Processed %zu segments.\n", num);
197 ret = 0;
198 } else {
199 printk(BIOS_INFO, "kempld_i2c: Transfer failed.\n");
200 }
201 goto _release;
202 }
203
204 if (ret == 0)
205 stopwatch_init_msecs_expire(&sw, 1000);
206
207 udelay(10);
208 }
209
210 i2c.state = STATE_ERROR;
211 ret = -ETIMEDOUT;
212 printk(BIOS_INFO, "kempld_i2c: Transfer failed.\n");
213
214 _release:
215 kempld_release_mutex();
216 return ret;
217 }
218
219 static const struct i2c_bus_operations kempld_i2c_bus_ops = {
220 .transfer = kempld_i2c_xfer,
221 };
222
223 static struct device_operations kempld_i2c_dev_ops = {
224 .scan_bus = &scan_smbus,
225 .ops_i2c_bus = &kempld_i2c_bus_ops,
226 };
227
kempld_i2c_device_init(struct device * const dev)228 void kempld_i2c_device_init(struct device *const dev)
229 {
230 const struct ec_kontron_kempld_config *const config = dev->chip_info;
231 u16 prescale_corr, frequency;
232 long prescale;
233 u8 ctrl;
234 u8 stat;
235 u8 cfg;
236
237 if (kempld_get_mutex(100) < 0)
238 return;
239
240 /* Make sure the device is disabled */
241 ctrl = kempld_read8(KEMPLD_I2C_CTRL);
242 ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
243 kempld_write8(KEMPLD_I2C_CTRL, ctrl);
244
245 frequency = KEMPLD_I2C_FREQ_STANDARD_MODE_100KHZ;
246 if (config && config->i2c_frequency) {
247 if (config->i2c_frequency <= KEMPLD_I2C_FREQ_MAX) {
248 frequency = config->i2c_frequency;
249 } else {
250 printk(BIOS_NOTICE,
251 "kempld_i2c: %d kHz is too high!\n",
252 config->i2c_frequency);
253 }
254 }
255 printk(BIOS_INFO, "kempld_i2c: Use frequency %d\n", frequency);
256
257 const u8 spec_major = KEMPLD_SPEC_GET_MAJOR(kempld_read8(KEMPLD_SPEC));
258 if (spec_major == 1)
259 prescale = KEMPLD_CLK / (frequency * 5) - 1000;
260 else
261 prescale = KEMPLD_CLK / (frequency * 4) - 3000;
262
263 if (prescale < 0)
264 prescale = 0;
265
266 /* Round to the best matching value */
267 prescale_corr = prescale / 1000;
268 if (prescale % 1000 >= 500)
269 prescale_corr++;
270
271 kempld_write8(KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
272 kempld_write8(KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
273
274 /* Disable I2C bus output on GPIO pins */
275 cfg = kempld_read8(KEMPLD_CFG);
276 cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
277 kempld_write8(KEMPLD_CFG, cfg);
278
279 /* Enable the device */
280 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_IACK);
281 ctrl |= I2C_CTRL_EN;
282 kempld_write8(KEMPLD_I2C_CTRL, ctrl);
283
284 stat = kempld_read8(KEMPLD_I2C_STAT);
285 if (stat & I2C_STAT_BUSY)
286 kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
287
288 dev->ops = &kempld_i2c_dev_ops;
289
290 kempld_release_mutex();
291 }
292