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