1 /*
2 * Copyright (c) 2020, Seagate Technology LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_lpc11u6x_i2c
8
9 #include <kernel.h>
10 #include <drivers/i2c.h>
11 #include <drivers/pinmux.h>
12 #include <drivers/clock_control.h>
13 #include <dt-bindings/pinctrl/lpc11u6x-pinctrl.h>
14 #include "i2c_lpc11u6x.h"
15
16 #define DEV_CFG(dev) ((dev)->config)
17 #define DEV_BASE(dev) (((struct lpc11u6x_i2c_config *) DEV_CFG((dev)))->base)
18 #define DEV_DATA(dev) ((dev)->data)
19
lpc11u6x_i2c_set_bus_speed(const struct lpc11u6x_i2c_config * cfg,const struct device * clk_dev,uint32_t speed)20 static void lpc11u6x_i2c_set_bus_speed(const struct lpc11u6x_i2c_config *cfg,
21 const struct device *clk_dev,
22 uint32_t speed)
23 {
24 uint32_t clk, div;
25
26 clock_control_get_rate(clk_dev, (clock_control_subsys_t) cfg->clkid,
27 &clk);
28 div = clk / speed;
29
30 cfg->base->sclh = div / 2;
31 cfg->base->scll = div - (div / 2);
32 }
33
lpc11u6x_i2c_configure(const struct device * dev,uint32_t dev_config)34 static int lpc11u6x_i2c_configure(const struct device *dev,
35 uint32_t dev_config)
36 {
37 const struct lpc11u6x_i2c_config *cfg = DEV_CFG(dev);
38 struct lpc11u6x_i2c_data *data = DEV_DATA(dev);
39 const struct device *clk_dev, *pinmux_dev;
40 uint32_t speed, flags = 0;
41
42 switch (I2C_SPEED_GET(dev_config)) {
43 case I2C_SPEED_STANDARD:
44 speed = 100000;
45 break;
46 case I2C_SPEED_FAST:
47 speed = 400000;
48 break;
49 case I2C_SPEED_FAST_PLUS:
50 flags |= IOCON_FASTI2C_EN;
51 speed = 1000000;
52 break;
53 case I2C_SPEED_HIGH:
54 case I2C_SPEED_ULTRA:
55 return -ENOTSUP;
56 default:
57 return -EINVAL;
58 }
59
60 if (dev_config & I2C_ADDR_10_BITS) {
61 return -ENOTSUP;
62 }
63
64 clk_dev = device_get_binding(cfg->clock_drv);
65 if (!clk_dev) {
66 return -EINVAL;
67 }
68
69 k_mutex_lock(&data->mutex, K_FOREVER);
70 lpc11u6x_i2c_set_bus_speed(cfg, clk_dev, speed);
71
72 if (!flags) {
73 goto exit;
74 }
75
76 pinmux_dev = device_get_binding(cfg->scl_pinmux_drv);
77 if (!pinmux_dev) {
78 goto err;
79 }
80 pinmux_pin_set(pinmux_dev, cfg->scl_pin, cfg->scl_flags | flags);
81
82 pinmux_dev = device_get_binding(cfg->sda_pinmux_drv);
83 if (!pinmux_dev) {
84 goto err;
85 }
86 pinmux_pin_set(pinmux_dev, cfg->sda_pin, cfg->sda_flags | flags);
87
88 exit:
89 k_mutex_unlock(&data->mutex);
90 return 0;
91 err:
92 k_mutex_unlock(&data->mutex);
93 return -EINVAL;
94 }
95
lpc11u6x_i2c_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)96 static int lpc11u6x_i2c_transfer(const struct device *dev,
97 struct i2c_msg *msgs,
98 uint8_t num_msgs, uint16_t addr)
99 {
100 const struct lpc11u6x_i2c_config *cfg = DEV_CFG(dev);
101 struct lpc11u6x_i2c_data *data = DEV_DATA(dev);
102 int ret = 0;
103
104 if (!num_msgs) {
105 return 0;
106 }
107
108 k_mutex_lock(&data->mutex, K_FOREVER);
109
110 data->transfer.msgs = msgs;
111 data->transfer.curr_buf = msgs->buf;
112 data->transfer.curr_len = msgs->len;
113 data->transfer.nr_msgs = num_msgs;
114 data->transfer.addr = addr;
115
116 /* Reset all control bits */
117 cfg->base->con_clr = LPC11U6X_I2C_CONTROL_SI |
118 LPC11U6X_I2C_CONTROL_STOP | LPC11U6X_I2C_CONTROL_START;
119
120 /* Send start and wait for completion */
121 data->transfer.status = LPC11U6X_I2C_STATUS_BUSY;
122 cfg->base->con_set = LPC11U6X_I2C_CONTROL_START;
123
124 k_sem_take(&data->completion, K_FOREVER);
125
126 if (data->transfer.status != LPC11U6X_I2C_STATUS_OK) {
127 ret = -EIO;
128 }
129 data->transfer.status = LPC11U6X_I2C_STATUS_INACTIVE;
130
131 /* If a slave is registered, put the controller in slave mode */
132 if (data->slave) {
133 cfg->base->con_set = LPC11U6X_I2C_CONTROL_AA;
134 }
135
136 k_mutex_unlock(&data->mutex);
137 return ret;
138 }
139
lpc11u6x_i2c_slave_register(const struct device * dev,struct i2c_slave_config * cfg)140 static int lpc11u6x_i2c_slave_register(const struct device *dev,
141 struct i2c_slave_config *cfg)
142 {
143 const struct lpc11u6x_i2c_config *dev_cfg = DEV_CFG(dev);
144 struct lpc11u6x_i2c_data *data = DEV_DATA(dev);
145 int ret = 0;
146
147 if (!cfg) {
148 return -EINVAL;
149 }
150
151 if (cfg->flags & I2C_SLAVE_FLAGS_ADDR_10_BITS) {
152 return -ENOTSUP;
153 }
154
155 k_mutex_lock(&data->mutex, K_FOREVER);
156 if (data->slave) {
157 ret = -EBUSY;
158 goto exit;
159 }
160
161 data->slave = cfg;
162 /* Configure controller to act as slave */
163 dev_cfg->base->addr0 = (cfg->address << 1);
164 dev_cfg->base->con_clr = LPC11U6X_I2C_CONTROL_START |
165 LPC11U6X_I2C_CONTROL_STOP | LPC11U6X_I2C_CONTROL_SI;
166 dev_cfg->base->con_set = LPC11U6X_I2C_CONTROL_AA;
167
168 exit:
169 k_mutex_unlock(&data->mutex);
170 return ret;
171 }
172
173
lpc11u6x_i2c_slave_unregister(const struct device * dev,struct i2c_slave_config * cfg)174 static int lpc11u6x_i2c_slave_unregister(const struct device *dev,
175 struct i2c_slave_config *cfg)
176 {
177 const struct lpc11u6x_i2c_config *dev_cfg = DEV_CFG(dev);
178 struct lpc11u6x_i2c_data *data = DEV_DATA(dev);
179
180 if (!cfg) {
181 return -EINVAL;
182 }
183 if (data->slave != cfg) {
184 return -EINVAL;
185 }
186
187 k_mutex_lock(&data->mutex, K_FOREVER);
188 data->slave = NULL;
189 dev_cfg->base->con_clr = LPC11U6X_I2C_CONTROL_AA;
190 k_mutex_unlock(&data->mutex);
191
192 return 0;
193 }
194
lpc11u6x_i2c_isr(const void * arg)195 static void lpc11u6x_i2c_isr(const void *arg)
196 {
197 struct lpc11u6x_i2c_data *data = DEV_DATA((const struct device *)arg);
198 struct lpc11u6x_i2c_regs *i2c = DEV_BASE((const struct device *) arg);
199 struct lpc11u6x_i2c_current_transfer *transfer = &data->transfer;
200 uint32_t clear = LPC11U6X_I2C_CONTROL_SI;
201 uint32_t set = 0;
202 uint8_t val;
203
204 switch (i2c->stat) {
205 /* Master TX states */
206 case LPC11U6X_I2C_MASTER_TX_START:
207 case LPC11U6X_I2C_MASTER_TX_RESTART:
208 i2c->dat = (transfer->addr << 1) |
209 (transfer->msgs->flags & I2C_MSG_READ);
210 clear |= LPC11U6X_I2C_CONTROL_START;
211 transfer->curr_buf = transfer->msgs->buf;
212 transfer->curr_len = transfer->msgs->len;
213 break;
214
215 case LPC11U6X_I2C_MASTER_TX_ADR_ACK:
216 case LPC11U6X_I2C_MASTER_TX_DAT_ACK:
217 if (!transfer->curr_len) {
218 transfer->msgs++;
219 transfer->nr_msgs--;
220 if (!transfer->nr_msgs) {
221 transfer->status = LPC11U6X_I2C_STATUS_OK;
222 set |= LPC11U6X_I2C_CONTROL_STOP;
223 } else {
224 set |= LPC11U6X_I2C_CONTROL_START;
225 }
226 } else {
227 i2c->dat = transfer->curr_buf[0];
228 transfer->curr_buf++;
229 transfer->curr_len--;
230 }
231 break;
232
233 /* Master RX states */
234 case LPC11U6X_I2C_MASTER_RX_DAT_NACK:
235 transfer->msgs++;
236 transfer->nr_msgs--;
237 set |= (transfer->nr_msgs ? LPC11U6X_I2C_CONTROL_START :
238 LPC11U6X_I2C_CONTROL_STOP);
239 if (!transfer->nr_msgs) {
240 transfer->status = LPC11U6X_I2C_STATUS_OK;
241 }
242 __fallthrough;
243 case LPC11U6X_I2C_MASTER_RX_DAT_ACK:
244 transfer->curr_buf[0] = i2c->dat;
245 transfer->curr_buf++;
246 transfer->curr_len--;
247 __fallthrough;
248 case LPC11U6X_I2C_MASTER_RX_ADR_ACK:
249 if (transfer->curr_len <= 1) {
250 clear |= LPC11U6X_I2C_CONTROL_AA;
251 } else {
252 set |= LPC11U6X_I2C_CONTROL_AA;
253 }
254 break;
255
256 /* Slave States */
257 case LPC11U6X_I2C_SLAVE_RX_ADR_ACK:
258 case LPC11U6X_I2C_SLAVE_RX_ARB_LOST_ADR_ACK:
259 case LPC11U6X_I2C_SLAVE_RX_GC_ACK:
260 case LPC11U6X_I2C_SLAVE_RX_ARB_LOST_GC_ACK:
261 if (data->slave->callbacks->write_requested(data->slave)) {
262 clear |= LPC11U6X_I2C_CONTROL_AA;
263 }
264 break;
265
266 case LPC11U6X_I2C_SLAVE_RX_DAT_ACK:
267 case LPC11U6X_I2C_SLAVE_RX_GC_DAT_ACK:
268 val = i2c->dat;
269 if (data->slave->callbacks->write_received(data->slave, val)) {
270 clear |= LPC11U6X_I2C_CONTROL_AA;
271 }
272 break;
273
274 case LPC11U6X_I2C_SLAVE_RX_DAT_NACK:
275 case LPC11U6X_I2C_SLAVE_RX_GC_DAT_NACK:
276 val = i2c->dat;
277 data->slave->callbacks->write_received(data->slave, val);
278 data->slave->callbacks->stop(data->slave);
279 set |= LPC11U6X_I2C_CONTROL_AA;
280 break;
281
282 case LPC11U6X_I2C_SLAVE_RX_STOP:
283 data->slave->callbacks->stop(data->slave);
284 set |= LPC11U6X_I2C_CONTROL_AA;
285 break;
286
287 case LPC11U6X_I2C_SLAVE_TX_ADR_ACK:
288 case LPC11U6X_I2C_SLAVE_TX_ARB_LOST_ADR_ACK:
289 if (data->slave->callbacks->read_requested(data->slave, &val)) {
290 clear |= LPC11U6X_I2C_CONTROL_AA;
291 }
292 i2c->dat = val;
293 break;
294 case LPC11U6X_I2C_SLAVE_TX_DAT_ACK:
295 if (data->slave->callbacks->read_processed(data->slave, &val)) {
296 clear |= LPC11U6X_I2C_CONTROL_AA;
297 }
298 i2c->dat = val;
299 break;
300 case LPC11U6X_I2C_SLAVE_TX_DAT_NACK:
301 case LPC11U6X_I2C_SLAVE_TX_LAST_BYTE:
302 data->slave->callbacks->stop(data->slave);
303 set |= LPC11U6X_I2C_CONTROL_AA;
304 break;
305
306 /* Error cases */
307 case LPC11U6X_I2C_MASTER_TX_ADR_NACK:
308 case LPC11U6X_I2C_MASTER_RX_ADR_NACK:
309 case LPC11U6X_I2C_MASTER_TX_DAT_NACK:
310 case LPC11U6X_I2C_MASTER_TX_ARB_LOST:
311 transfer->status = LPC11U6X_I2C_STATUS_FAIL;
312 set = LPC11U6X_I2C_CONTROL_STOP;
313 break;
314
315 default:
316 set = LPC11U6X_I2C_CONTROL_STOP;
317 break;
318 }
319
320 i2c->con_clr = clear;
321 i2c->con_set = set;
322 if ((transfer->status != LPC11U6X_I2C_STATUS_BUSY) &&
323 (transfer->status != LPC11U6X_I2C_STATUS_INACTIVE)) {
324 k_sem_give(&data->completion);
325 }
326 }
327
328
lpc11u6x_i2c_init(const struct device * dev)329 static int lpc11u6x_i2c_init(const struct device *dev)
330 {
331 const struct lpc11u6x_i2c_config *cfg = DEV_CFG(dev);
332 struct lpc11u6x_i2c_data *data = DEV_DATA(dev);
333 const struct device *pinmux_dev, *clk_dev;
334
335 /* Configure SCL and SDA pins */
336 pinmux_dev = device_get_binding(cfg->scl_pinmux_drv);
337 if (!pinmux_dev) {
338 return -EINVAL;
339 }
340 pinmux_pin_set(pinmux_dev, cfg->scl_pin, cfg->scl_flags);
341
342 pinmux_dev = device_get_binding(cfg->sda_pinmux_drv);
343 if (!pinmux_dev) {
344 return -EINVAL;
345 }
346 pinmux_pin_set(pinmux_dev, cfg->sda_pin, cfg->sda_flags);
347
348 /* Configure clock and de-assert reset for I2Cx */
349 clk_dev = device_get_binding(cfg->clock_drv);
350 if (!clk_dev) {
351 return -EINVAL;
352 }
353 clock_control_on(clk_dev, (clock_control_subsys_t) cfg->clkid);
354
355 /* Configure bus speed. Default is 100KHz */
356 lpc11u6x_i2c_set_bus_speed(cfg, clk_dev, 100000);
357
358 /* Clear all control bytes and enable I2C interface */
359 cfg->base->con_clr = LPC11U6X_I2C_CONTROL_AA | LPC11U6X_I2C_CONTROL_SI |
360 LPC11U6X_I2C_CONTROL_START | LPC11U6X_I2C_CONTROL_I2C_EN;
361 cfg->base->con_set = LPC11U6X_I2C_CONTROL_I2C_EN;
362
363 /* Initialize mutex and semaphore */
364 k_mutex_init(&data->mutex);
365 k_sem_init(&data->completion, 0, 1);
366
367 data->transfer.status = LPC11U6X_I2C_STATUS_INACTIVE;
368 /* Configure IRQ */
369 cfg->irq_config_func(dev);
370 return 0;
371 }
372
373 static const struct i2c_driver_api i2c_api = {
374 .configure = lpc11u6x_i2c_configure,
375 .transfer = lpc11u6x_i2c_transfer,
376 .slave_register = lpc11u6x_i2c_slave_register,
377 .slave_unregister = lpc11u6x_i2c_slave_unregister,
378 };
379
380 #define LPC11U6X_I2C_INIT(idx) \
381 \
382 static void lpc11u6x_i2c_isr_config_##idx(const struct device *dev); \
383 \
384 static const struct lpc11u6x_i2c_config i2c_cfg_##idx = { \
385 .base = \
386 (struct lpc11u6x_i2c_regs *) DT_INST_REG_ADDR(idx), \
387 .clock_drv = DT_LABEL(DT_INST_PHANDLE(idx, clocks)), \
388 .scl_pinmux_drv = \
389 DT_LABEL(DT_INST_PHANDLE_BY_NAME(idx, pinmuxs, scl)), \
390 .sda_pinmux_drv = \
391 DT_LABEL(DT_INST_PHANDLE_BY_NAME(idx, pinmuxs, sda)), \
392 .irq_config_func = lpc11u6x_i2c_isr_config_##idx, \
393 .scl_flags = \
394 DT_INST_PHA_BY_NAME(idx, pinmuxs, scl, function), \
395 .sda_flags = \
396 DT_INST_PHA_BY_NAME(idx, pinmuxs, sda, function), \
397 .scl_pin = DT_INST_PHA_BY_NAME(idx, pinmuxs, scl, pin), \
398 .sda_pin = DT_INST_PHA_BY_NAME(idx, pinmuxs, sda, pin), \
399 .clkid = DT_INST_PHA_BY_IDX(idx, clocks, 0, clkid), \
400 }; \
401 \
402 static struct lpc11u6x_i2c_data i2c_data_##idx; \
403 \
404 DEVICE_DT_INST_DEFINE(idx, \
405 &lpc11u6x_i2c_init, \
406 NULL, \
407 &i2c_data_##idx, &i2c_cfg_##idx, \
408 PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, \
409 &i2c_api); \
410 \
411 static void lpc11u6x_i2c_isr_config_##idx(const struct device *dev) \
412 { \
413 IRQ_CONNECT(DT_INST_IRQN(idx), \
414 DT_INST_IRQ(idx, priority), \
415 lpc11u6x_i2c_isr, DEVICE_DT_INST_GET(idx), 0); \
416 \
417 irq_enable(DT_INST_IRQN(idx)); \
418 }
419
420 DT_INST_FOREACH_STATUS_OKAY(LPC11U6X_I2C_INIT);
421