1 /*
2  * Copyright (c) 2020 Eric Holland
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include <nrfx.h>
10 /*
11   To use the twim driver, NRFX_TWIM_ENABLED must be set to 1 in the GLOBAL_DEFINES
12   additionally, NRFX_TWIM0_ENABLED and/or NRFX_TWIM1_ENABLED must also be 1 to specify
13   which modules are active.  These would ideally be set in either a project rule.mk
14   or in a targets rules.mk.
15 
16   The pins to be used for each of the active TWIM modules should be defined as:
17   TWIM0_SCL_PIN, TWIM0_SDA_PIN  (if twim0 is used)
18   TWIM1_SCL_PIN, TWIM1_SDA_PIN  (if twim1 is used)
19   and ideally be defined in the targets include/gpioconfig.h since it is included here.
20 */
21 
22 #if (NRFX_TWIM_ENABLED)
23 #include <nrfx_log.h>
24 #include <nrfx_twim.h>
25 #include <dev/i2c.h>
26 #include <kernel/event.h>
27 #include <kernel/mutex.h>
28 #include <lk/debug.h>
29 #include <lk/err.h>
30 #include <target/gpioconfig.h>
31 
32 
33 #define TWIM_MASTER_TIMEOUT_MS 1000
34 
35 typedef struct twim_dev {
36     nrfx_twim_t twim;
37     event_t evt;
38     mutex_t lock;
39     nrfx_twim_evt_type_t result;
40 } twim_dev_t;
41 
42 #if (NRFX_TWIM0_ENABLED)
43 static twim_dev_t twim0 = { NRFX_TWIM_INSTANCE(0),
44                             EVENT_INITIAL_VALUE(twim0.evt, false, 0),
45                             MUTEX_INITIAL_VALUE(twim0.lock),
46                             0
47                           };
48 
nrf52_SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQ(void)49 void nrf52_SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQ(void) {
50     arm_cm_irq_entry();
51     nrfx_twim_0_irq_handler();
52     arm_cm_irq_exit(true);
53 }
54 #endif
55 
56 #if (NRFX_TWIM1_ENABLED)
57 static twim_dev_t twim1 = { NRFX_TWIM_INSTANCE(1),
58                             EVENT_INITIAL_VALUE(twim1.evt, false, 0),
59                             MUTEX_INITIAL_VALUE(twim1.lock),
60                             0
61                           };
62 
nrf52_SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQ(void)63 void nrf52_SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQ(void) {
64     arm_cm_irq_entry();
65     nrfx_twim_1_irq_handler();
66     arm_cm_irq_exit(true);
67 }
68 #endif
69 
get_nrfx_twim(int bus)70 static inline twim_dev_t *get_nrfx_twim(int bus) {
71     switch (bus) {
72 #if (NRFX_TWIM0_ENABLED)
73         case 0:
74             return &twim0;
75 #endif
76 #if (NRFX_TWIM1_ENABLED)
77         case 1:
78             return &twim1;
79 #endif
80         default:
81             return NULL;
82     }
83 }
84 
i2c_twim_evt_handler(nrfx_twim_evt_t const * p_event,void * p_context)85 void i2c_twim_evt_handler(nrfx_twim_evt_t const *p_event,void *p_context) {
86     twim_dev_t *twim = (twim_dev_t *)p_context;
87     twim->result = p_event->type;
88     event_signal(&twim->evt, false);
89 }
90 
i2c_init_early(void)91 void i2c_init_early(void) {}
92 
i2c_init()93 void i2c_init() {
94     nrfx_err_t status;
95 
96 #if (NRFX_TWIM0_ENABLED)
97     //Pins should be defined in target/gpioconfig.h
98     const nrfx_twim_config_t twim0_config = NRFX_TWIM_DEFAULT_CONFIG(TWIM0_SCL_PIN, TWIM0_SDA_PIN);
99 
100     status = nrfx_twim_init(&twim0.twim, &twim0_config, i2c_twim_evt_handler, &twim0);
101     if (status == NRFX_SUCCESS) {
102         nrfx_twim_enable(&twim0.twim);
103     } else {
104         NRFX_LOG_ERROR("ERROR in twim0 init:%s \n",NRFX_LOG_ERROR_STRING_GET(status));
105     }
106 #endif
107 
108 #if (NRFX_TWIM1_ENABLED)
109     //Pins should be defined in target/gpioconfig.h
110     const nrfx_twim_config_t twim1_config = NRFX_TWIM_DEFAULT_CONFIG(TWIM1_SCL_PIN, TWIM1_SDA_PIN);
111 
112     status = nrfx_twim_init(&twim1, &twim1_config, i2c_twim_evt_handler, &twim1);
113     if (status == NRFX_SUCCESS) {
114         nrfx_twim_enable(&twim1);
115     } else {
116         NRFX_LOG_ERROR("ERROR in twim1 init:%s \n",NRFX_LOG_ERROR_STRING_GET(status));
117     }
118 #endif
119 }
120 
i2c_xfer(int bus,nrfx_twim_xfer_desc_t * desc)121 static status_t i2c_xfer(int bus, nrfx_twim_xfer_desc_t *desc) {
122     twim_dev_t *twim = get_nrfx_twim(bus);
123     if (twim == NULL) return ERR_INVALID_ARGS;
124 
125     mutex_acquire(&twim->lock);
126 
127     nrfx_err_t nrfx_status = nrfx_twim_xfer(&twim->twim, desc, 0);
128 
129     event_wait_timeout(&twim->evt, TWIM_MASTER_TIMEOUT_MS);
130     event_unsignal(&twim->evt);
131     mutex_release(&twim->lock);
132 
133     if (nrfx_status != NRFX_SUCCESS) {
134         NRFX_LOG_ERROR("%s:%s \n", __func__, NRFX_LOG_ERROR_STRING_GET(nrfx_status));
135         return (status_t)nrfx_status;
136     }
137     return NO_ERROR;
138 }
139 
i2c_transmit(int bus,uint8_t address,const void * buf,size_t count)140 status_t i2c_transmit(int bus, uint8_t address, const void *buf, size_t count) {
141 
142     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TX(address, (uint8_t *)buf, count);
143 
144     return i2c_xfer(bus, &xfer);
145 }
146 
i2c_receive(int bus,uint8_t address,void * buf,size_t count)147 status_t i2c_receive(int bus, uint8_t address, void *buf, size_t count) {
148 
149     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_RX(address, (uint8_t *)buf, count);
150 
151     return i2c_xfer(bus, &xfer);
152 }
153 
i2c_write_reg_bytes(int bus,uint8_t address,uint8_t reg,const uint8_t * val,size_t cnt)154 status_t i2c_write_reg_bytes(int bus, uint8_t address, uint8_t reg, const uint8_t *val,
155                              size_t cnt) {
156 
157     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TXTX(address, &reg, 1, (uint8_t *)val, cnt);
158 
159     return i2c_xfer(bus, &xfer);
160 }
161 
i2c_read_reg_bytes(int bus,uint8_t address,uint8_t reg,uint8_t * val,size_t cnt)162 status_t i2c_read_reg_bytes(int bus, uint8_t address, uint8_t reg, uint8_t *val, size_t cnt) {
163     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TXRX(address, &reg, 1, (uint8_t *)val, cnt);
164 
165     return i2c_xfer(bus, &xfer);
166 }
167 
168 #endif // NRFX_TWIM_ENABLED
169