1 /*
2 * Copyright (c) 2019 Brett Witherspoon
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_cc13xx_cc26xx_i2c
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/pinctrl.h>
12 #include <zephyr/pm/device.h>
13 #include <zephyr/pm/policy.h>
14
15 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(i2c_cc13xx_cc26xx);
18
19 #include <driverlib/i2c.h>
20 #include <driverlib/prcm.h>
21
22 #include <ti/drivers/Power.h>
23 #include <ti/drivers/power/PowerCC26X2.h>
24 #include <zephyr/irq.h>
25
26 #include "i2c-priv.h"
27
28 struct i2c_cc13xx_cc26xx_data {
29 struct k_sem lock;
30 struct k_sem complete;
31 volatile uint32_t error;
32 #ifdef CONFIG_PM
33 Power_NotifyObj postNotify;
34 uint32_t dev_config;
35 #endif
36 };
37
38 struct i2c_cc13xx_cc26xx_config {
39 uint32_t base;
40 const struct pinctrl_dev_config *pcfg;
41 };
42
i2c_cc13xx_cc26xx_transmit(const struct device * dev,const uint8_t * buf,uint32_t len,uint16_t addr)43 static int i2c_cc13xx_cc26xx_transmit(const struct device *dev,
44 const uint8_t *buf,
45 uint32_t len, uint16_t addr)
46 {
47 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
48 const uint32_t base = config->base;
49 struct i2c_cc13xx_cc26xx_data *data = dev->data;
50
51 /* Sending address without data is not supported */
52 if (len == 0) {
53 return -EIO;
54 }
55
56 I2CMasterSlaveAddrSet(base, addr, false);
57
58 /* The following assumes a single master. Use I2CMasterBusBusy() if
59 * wanting to implement multiple master support.
60 */
61
62 /* Single transmission */
63 if (len == 1) {
64 I2CMasterDataPut(base, *buf);
65
66 I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_SEND);
67
68 k_sem_take(&data->complete, K_FOREVER);
69
70 return data->error == I2C_MASTER_ERR_NONE ? 0 : -EIO;
71 }
72
73 /* Burst transmission */
74 I2CMasterDataPut(base, buf[0]);
75
76 I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_START);
77
78 k_sem_take(&data->complete, K_FOREVER);
79
80 if (data->error != I2C_MASTER_ERR_NONE) {
81 goto send_error_stop;
82 }
83
84 for (int i = 1; i < len - 1; i++) {
85 I2CMasterDataPut(base, buf[i]);
86
87 I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_CONT);
88
89 k_sem_take(&data->complete, K_FOREVER);
90
91 if (data->error != I2C_MASTER_ERR_NONE) {
92 goto send_error_stop;
93 }
94 }
95
96 I2CMasterDataPut(base, buf[len - 1]);
97
98 I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_FINISH);
99
100 k_sem_take(&data->complete, K_FOREVER);
101
102 if (data->error != I2C_MASTER_ERR_NONE) {
103 return -EIO;
104 }
105
106 return 0;
107
108 send_error_stop:
109 I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
110 return -EIO;
111 }
112
i2c_cc13xx_cc26xx_receive(const struct device * dev,uint8_t * buf,uint32_t len,uint16_t addr)113 static int i2c_cc13xx_cc26xx_receive(const struct device *dev, uint8_t *buf,
114 uint32_t len,
115 uint16_t addr)
116 {
117 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
118 const uint32_t base = config->base;
119 struct i2c_cc13xx_cc26xx_data *data = dev->data;
120
121 /* Sending address without data is not supported */
122 if (len == 0) {
123 return -EIO;
124 }
125
126 I2CMasterSlaveAddrSet(base, addr, true);
127
128 /* The following assumes a single master. Use I2CMasterBusBusy() if
129 * wanting to implement multiple master support.
130 */
131
132 /* Single receive */
133 if (len == 1) {
134 I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_RECEIVE);
135
136 k_sem_take(&data->complete, K_FOREVER);
137
138 if (data->error != I2C_MASTER_ERR_NONE) {
139 return -EIO;
140 }
141
142 *buf = I2CMasterDataGet(base);
143
144 return 0;
145 }
146
147 /* Burst receive */
148 I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_START);
149
150 k_sem_take(&data->complete, K_FOREVER);
151
152 if (data->error != I2C_MASTER_ERR_NONE) {
153 goto recv_error_stop;
154 }
155
156 buf[0] = I2CMasterDataGet(base);
157
158 for (int i = 1; i < len - 1; i++) {
159 I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
160
161 k_sem_take(&data->complete, K_FOREVER);
162
163 if (data->error != I2C_MASTER_ERR_NONE) {
164 goto recv_error_stop;
165 }
166
167 buf[i] = I2CMasterDataGet(base);
168 }
169
170 I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
171
172 k_sem_take(&data->complete, K_FOREVER);
173
174 if (data->error != I2C_MASTER_ERR_NONE) {
175 return -EIO;
176 }
177
178 buf[len - 1] = I2CMasterDataGet(base);
179
180 return 0;
181
182 recv_error_stop:
183 I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
184 return -EIO;
185 }
186
i2c_cc13xx_cc26xx_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)187 static int i2c_cc13xx_cc26xx_transfer(const struct device *dev,
188 struct i2c_msg *msgs,
189 uint8_t num_msgs, uint16_t addr)
190 {
191 struct i2c_cc13xx_cc26xx_data *data = dev->data;
192 int ret = 0;
193
194 if (num_msgs == 0) {
195 return 0;
196 }
197
198 k_sem_take(&data->lock, K_FOREVER);
199
200 pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
201
202 for (int i = 0; i < num_msgs; i++) {
203 /* Not supported by hardware */
204 if (msgs[i].flags & I2C_MSG_ADDR_10_BITS) {
205 ret = -EIO;
206 break;
207 }
208
209 if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
210 ret = i2c_cc13xx_cc26xx_transmit(dev, msgs[i].buf,
211 msgs[i].len, addr);
212 } else {
213 ret = i2c_cc13xx_cc26xx_receive(dev, msgs[i].buf,
214 msgs[i].len, addr);
215 }
216
217 if (ret) {
218 break;
219 }
220 }
221
222 pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
223
224 k_sem_give(&data->lock);
225
226 return ret;
227 }
228
229 #define CPU_FREQ DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
i2c_cc13xx_cc26xx_configure(const struct device * dev,uint32_t dev_config)230 static int i2c_cc13xx_cc26xx_configure(const struct device *dev,
231 uint32_t dev_config)
232 {
233 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
234 bool fast;
235
236 switch (I2C_SPEED_GET(dev_config)) {
237 case I2C_SPEED_STANDARD:
238 fast = false;
239 break;
240 case I2C_SPEED_FAST:
241 fast = true;
242 break;
243 default:
244 LOG_ERR("Unsupported speed");
245 return -EIO;
246 }
247
248 /* Support for slave mode has not been implemented */
249 if (!(dev_config & I2C_MODE_CONTROLLER)) {
250 LOG_ERR("Slave mode is not supported");
251 return -EIO;
252 }
253
254 /* This is deprecated and could be ignored in the future */
255 if (dev_config & I2C_ADDR_10_BITS) {
256 LOG_ERR("10-bit addressing mode is not supported");
257 return -EIO;
258 }
259
260 /* Enables and configures I2C master */
261 I2CMasterInitExpClk(config->base, CPU_FREQ, fast);
262
263 #ifdef CONFIG_PM
264 struct i2c_cc13xx_cc26xx_data *data = dev->data;
265
266 data->dev_config = dev_config;
267 #endif
268
269 return 0;
270 }
271
i2c_cc13xx_cc26xx_isr(const struct device * dev)272 static void i2c_cc13xx_cc26xx_isr(const struct device *dev)
273 {
274 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
275 struct i2c_cc13xx_cc26xx_data *data = dev->data;
276 const uint32_t base = config->base;
277
278 if (I2CMasterIntStatus(base, true)) {
279 I2CMasterIntClear(base);
280
281 data->error = I2CMasterErr(base);
282
283 k_sem_give(&data->complete);
284 }
285 }
286
287 #ifdef CONFIG_PM
288 /*
289 * ======== postNotifyFxn ========
290 * Called by Power module when waking up the CPU from Standby. The i2c needs
291 * to be reconfigured afterwards, unless Zephyr's device PM turned it off, in
292 * which case it'd be responsible for turning it back on and reconfigure it.
293 */
postNotifyFxn(unsigned int eventType,uintptr_t eventArg,uintptr_t clientArg)294 static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
295 uintptr_t clientArg)
296 {
297 const struct device *dev = (const struct device *)clientArg;
298 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
299 struct i2c_cc13xx_cc26xx_data *data = dev->data;
300 int ret = Power_NOTIFYDONE;
301 int16_t res_id;
302
303 /* Reconfigure the hardware if returning from sleep */
304 if (eventType == PowerCC26XX_AWAKE_STANDBY) {
305 res_id = PowerCC26XX_PERIPH_I2C0;
306
307 if (Power_getDependencyCount(res_id) != 0) {
308 /* Reconfigure and enable I2C only if powered */
309 if (i2c_cc13xx_cc26xx_configure(dev,
310 data->dev_config) != 0) {
311 ret = Power_NOTIFYERROR;
312 }
313
314 I2CMasterIntEnable(config->base);
315 }
316 }
317
318 return (ret);
319 }
320 #endif
321
322 #ifdef CONFIG_PM_DEVICE
i2c_cc13xx_cc26xx_pm_action(const struct device * dev,enum pm_device_action action)323 static int i2c_cc13xx_cc26xx_pm_action(const struct device *dev,
324 enum pm_device_action action)
325 {
326 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
327 struct i2c_cc13xx_cc26xx_data *data = dev->data;
328 int ret = 0;
329
330 switch (action) {
331 case PM_DEVICE_ACTION_RESUME:
332 Power_setDependency(PowerCC26XX_PERIPH_I2C0);
333 ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
334 if (ret < 0) {
335 return ret;
336 }
337 ret = i2c_cc13xx_cc26xx_configure(dev, data->dev_config);
338 if (ret == 0) {
339 I2CMasterIntEnable(config->base);
340 }
341 break;
342 case PM_DEVICE_ACTION_SUSPEND:
343 I2CMasterIntDisable(config->base);
344 I2CMasterDisable(config->base);
345 /* Reset pin type to default GPIO configuration */
346 ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
347 if (ret < 0) {
348 return ret;
349 }
350 Power_releaseDependency(PowerCC26XX_PERIPH_I2C0);
351 break;
352 default:
353 return -ENOTSUP;
354 }
355
356 return ret;
357 }
358 #endif /* CONFIG_PM_DEVICE */
359
i2c_cc13xx_cc26xx_init(const struct device * dev)360 static int i2c_cc13xx_cc26xx_init(const struct device *dev)
361 {
362 const struct i2c_cc13xx_cc26xx_config *config = dev->config;
363 uint32_t cfg;
364 int err;
365
366 #ifdef CONFIG_PM
367 struct i2c_cc13xx_cc26xx_data *data = dev->data;
368
369 /* Set Power dependencies & constraints */
370 Power_setDependency(PowerCC26XX_PERIPH_I2C0);
371
372 /* Register notification function */
373 Power_registerNotify(&data->postNotify,
374 PowerCC26XX_AWAKE_STANDBY,
375 postNotifyFxn, (uintptr_t)dev);
376 #else
377 /* Enable I2C power domain */
378 PRCMPowerDomainOn(PRCM_DOMAIN_SERIAL);
379
380 /* Enable I2C peripheral clock */
381 PRCMPeripheralRunEnable(PRCM_PERIPH_I2C0);
382 /* Enable in sleep mode until proper power management is added */
383 PRCMPeripheralSleepEnable(PRCM_PERIPH_I2C0);
384 PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_I2C0);
385
386 /* Load PRCM settings */
387 PRCMLoadSet();
388 while (!PRCMLoadGet()) {
389 continue;
390 }
391
392 /* I2C should not be accessed until power domain is on. */
393 while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_SERIAL) !=
394 PRCM_DOMAIN_POWER_ON) {
395 continue;
396 }
397 #endif
398
399 IRQ_CONNECT(DT_INST_IRQN(0),
400 DT_INST_IRQ(0, priority),
401 i2c_cc13xx_cc26xx_isr, DEVICE_DT_INST_GET(0), 0);
402 irq_enable(DT_INST_IRQN(0));
403
404 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
405 if (err < 0) {
406 LOG_ERR("Failed to configure pinctrl state");
407 return err;
408 }
409
410 cfg = i2c_map_dt_bitrate(DT_INST_PROP(0, clock_frequency));
411 err = i2c_cc13xx_cc26xx_configure(dev, cfg | I2C_MODE_CONTROLLER);
412 if (err) {
413 LOG_ERR("Failed to configure");
414 return err;
415 }
416
417 I2CMasterIntEnable(config->base);
418
419 return 0;
420 }
421
422 static DEVICE_API(i2c, i2c_cc13xx_cc26xx_driver_api) = {
423 .configure = i2c_cc13xx_cc26xx_configure,
424 .transfer = i2c_cc13xx_cc26xx_transfer,
425 #ifdef CONFIG_I2C_RTIO
426 .iodev_submit = i2c_iodev_submit_fallback,
427 #endif
428 };
429
430 PINCTRL_DT_INST_DEFINE(0);
431
432 static const struct i2c_cc13xx_cc26xx_config i2c_cc13xx_cc26xx_config = {
433 .base = DT_INST_REG_ADDR(0),
434 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
435 };
436
437 static struct i2c_cc13xx_cc26xx_data i2c_cc13xx_cc26xx_data = {
438 .lock = Z_SEM_INITIALIZER(i2c_cc13xx_cc26xx_data.lock, 1, 1),
439 .complete = Z_SEM_INITIALIZER(i2c_cc13xx_cc26xx_data.complete, 0, 1),
440 .error = I2C_MASTER_ERR_NONE
441 };
442
443 PM_DEVICE_DT_INST_DEFINE(0, i2c_cc13xx_cc26xx_pm_action);
444
445 I2C_DEVICE_DT_INST_DEFINE(0,
446 i2c_cc13xx_cc26xx_init,
447 PM_DEVICE_DT_INST_GET(0),
448 &i2c_cc13xx_cc26xx_data, &i2c_cc13xx_cc26xx_config,
449 POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,
450 &i2c_cc13xx_cc26xx_driver_api);
451