1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright 2021 NXP
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <string.h>
30 
31 #include <zephyr.h>
32 #include <drivers/spi.h>
33 
34 #include "py/runtime.h"
35 #include "py/gc.h"
36 #include "py/mphal.h"
37 #include "py/mperrno.h"
38 #include "extmod/machine_spi.h"
39 #include "modmachine.h"
40 
41 #if MICROPY_PY_MACHINE_SPI
42 
43 #define DEFAULT_SPI_BAUDRATE    (50000)
44 #define DEFAULT_SPI_POLARITY    (0)
45 #define DEFAULT_SPI_PHASE       (0)
46 #define DEFAULT_SPI_BITS        (8)
47 #define DEFAULT_SPI_FIRSTBIT    (SPI_TRANSFER_MSB)
48 #define SPI_LOOP                (0)    // For testing, enable loop mode by setting SPI_LOOP (1)
49 
50 typedef struct _machine_hard_spi_obj_t {
51     mp_obj_base_t base;
52     const struct device *dev;
53     struct spi_config config;
54 } machine_hard_spi_obj_t;
55 
machine_hard_spi_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)56 STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
57     machine_hard_spi_obj_t *self = self_in;
58     mp_printf(print, "SPI(%s, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%s)",
59         self->dev->name,
60         self->config.frequency,
61         (self->config.operation & 0x2) >> 1,
62         (self->config.operation & 0x4) >> 2,
63         (self->config.operation & ~0x1F) >> 5,
64         ((self->config.operation & 0x10) >> 4) == SPI_TRANSFER_MSB ? "MSB" : "LSB");
65 }
66 
machine_hard_spi_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * all_args)67 mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
68     enum {ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso};
69 
70     static const mp_arg_t allowed_args[] = {
71         { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
72         { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = DEFAULT_SPI_BAUDRATE} },
73         { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_POLARITY} },
74         { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_PHASE} },
75         { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_BITS} },
76         { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_FIRSTBIT} },
77         { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
78         { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
79         { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
80     };
81 
82     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
83     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
84 
85     const char *dev_name = mp_obj_str_get_str(args[ARG_id].u_obj);
86     const struct device *dev = device_get_binding(dev_name);
87 
88     if (dev == NULL) {
89         mp_raise_ValueError(MP_ERROR_TEXT("device not found"));
90     }
91 
92     if ((args[ARG_sck].u_obj != MP_OBJ_NULL) || (args[ARG_miso].u_obj != MP_OBJ_NULL) || (args[ARG_mosi].u_obj != MP_OBJ_NULL)) {
93         mp_raise_NotImplementedError(MP_ERROR_TEXT("explicit choice of sck/miso/mosi is not implemented"));
94     }
95 
96     struct spi_config cfg = {
97         .frequency = args[ARG_baudrate].u_int,
98         .operation = (SPI_OP_MODE_MASTER |
99             args[ARG_polarity].u_int << 1 |
100                 args[ARG_phase].u_int << 2 |
101                 SPI_LOOP << 3 |
102                 args[ARG_firstbit].u_int << 4 |
103                 args[ARG_bits].u_int << 5 |
104                 SPI_LINES_SINGLE),
105         .slave = 0,
106         .cs = NULL
107     };
108 
109     machine_hard_spi_obj_t *self = m_new_obj(machine_hard_spi_obj_t);
110 
111     self->base.type = &machine_hard_spi_type;
112     self->dev = dev;
113     self->config = cfg;
114 
115     return MP_OBJ_FROM_PTR(self);
116 }
117 
machine_hard_spi_init(mp_obj_base_t * obj,size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)118 STATIC void machine_hard_spi_init(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
119     enum {ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit};
120 
121     static const mp_arg_t allowed_args[] = {
122         { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
123         { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
124         { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
125         { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
126         { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
127     };
128 
129     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
130     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
131 
132     machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)obj;
133 
134     uint32_t baudrate;
135     uint16_t operation = self->config.operation;
136 
137     if (args[ARG_baudrate].u_int != -1) {
138         baudrate = args[ARG_baudrate].u_int;
139     } else {
140         baudrate = self->config.frequency;
141     }
142 
143     if (args[ARG_polarity].u_int != -1) {
144         operation = (operation & ~0x2) | (args[ARG_polarity].u_int << 1);
145     }
146 
147     if (args[ARG_phase].u_int != -1) {
148         operation = (operation & ~0x4) | (args[ARG_phase].u_int << 2);
149     }
150 
151     if (args[ARG_bits].u_int != -1) {
152         operation = (operation & 0x1F) | (args[ARG_bits].u_int << 5);
153     }
154 
155     if (args[ARG_firstbit].u_int != -1) {
156         operation = (operation & ~0x10) | (args[ARG_firstbit].u_int << 4);
157     }
158 
159     struct spi_config cfg = {
160         .frequency = baudrate,
161         .operation = operation,
162         .slave = 0,
163         .cs = NULL
164     };
165 
166     self->config = cfg;
167 }
168 
machine_hard_spi_transfer(mp_obj_base_t * obj,size_t len,const uint8_t * src,uint8_t * dest)169 STATIC void machine_hard_spi_transfer(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest) {
170     machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)obj;
171 
172     int ret;
173 
174     struct spi_buf tx_bufs[1];
175     tx_bufs[0].buf = (uint8_t *)src;
176     tx_bufs[0].len = len;
177     const struct spi_buf_set tx = {
178         .buffers = tx_bufs,
179         .count = ARRAY_SIZE(tx_bufs)
180     };
181 
182     struct spi_buf rx_bufs[1];
183     rx_bufs[0].buf = dest;
184     rx_bufs[0].len = len;
185     const struct spi_buf_set rx = {
186         .buffers = rx_bufs,
187         .count = ARRAY_SIZE(rx_bufs)
188     };
189 
190     ret = spi_transceive(self->dev, &self->config, &tx, &rx);
191 
192     if (ret < 0) {
193         mp_raise_OSError(-ret);
194     }
195 }
196 
197 STATIC const mp_machine_spi_p_t machine_hard_spi_p = {
198     .init = machine_hard_spi_init,
199     .transfer = machine_hard_spi_transfer,
200 };
201 
202 const mp_obj_type_t machine_hard_spi_type = {
203     { &mp_type_type },
204     .name = MP_QSTR_SPI,
205     .print = machine_hard_spi_print,
206     .make_new = machine_hard_spi_make_new,
207     .protocol = &machine_hard_spi_p,
208     .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
209 };
210 
211 #endif // MICROPY_PY_MACHINE_SPI
212