xref: /aosp_15_r20/external/coreboot/src/ec/kontron/kempld/kempld_i2c.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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