Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017 Piotr Mienkowski |
| 3 | * |
| 4 | * SPDX-License-Identifier: Apache-2.0 |
| 5 | */ |
| 6 | |
| 7 | /** |
| 8 | * @file |
| 9 | * @brief Public APIs for the I2S (Inter-IC Sound) bus drivers. |
| 10 | */ |
| 11 | |
Flavio Ceolin | 67ca176 | 2018-09-14 10:43:44 -0700 | [diff] [blame] | 12 | #ifndef ZEPHYR_INCLUDE_I2S_H_ |
| 13 | #define ZEPHYR_INCLUDE_I2S_H_ |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 14 | |
| 15 | /** |
| 16 | * @defgroup i2s_interface I2S Interface |
| 17 | * @ingroup io_interfaces |
| 18 | * @brief I2S (Inter-IC Sound) Interface |
| 19 | * |
| 20 | * The I2S API provides support for the standard I2S interface standard as well |
| 21 | * as common non-standard extensions such as PCM Short/Long Frame Sync, |
| 22 | * Left/Right Justified Data Format. |
| 23 | * @{ |
| 24 | */ |
| 25 | |
| 26 | #include <zephyr/types.h> |
| 27 | #include <device.h> |
| 28 | |
| 29 | #ifdef __cplusplus |
| 30 | extern "C" { |
| 31 | #endif |
| 32 | |
| 33 | /* |
| 34 | * The following #defines are used to configure the I2S controller. |
| 35 | */ |
| 36 | |
| 37 | |
| 38 | typedef u8_t i2s_fmt_t; |
| 39 | |
| 40 | /** Data Format bit field position. */ |
| 41 | #define I2S_FMT_DATA_FORMAT_SHIFT 0 |
| 42 | /** Data Format bit field mask. */ |
| 43 | #define I2S_FMT_DATA_FORMAT_MASK (0x7 << I2S_FMT_DATA_FORMAT_SHIFT) |
| 44 | |
| 45 | /** @brief Standard I2S Data Format. |
| 46 | * |
David B. Kinder | f00f585 | 2017-10-01 10:00:48 -0700 | [diff] [blame] | 47 | * Serial data is transmitted in two's complement with the MSB first. Both |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 48 | * Word Select (WS) and Serial Data (SD) signals are sampled on the rising edge |
| 49 | * of the clock signal (SCK). The MSB is always sent one clock period after the |
| 50 | * WS changes. Left channel data are sent first indicated by WS = 0, followed |
| 51 | * by right channel data indicated by WS = 1. |
| 52 | * |
| 53 | * -. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. |
| 54 | * SCK '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' ' |
| 55 | * -. .-------------------------------. |
| 56 | * WS '-------------------------------' '---- |
| 57 | * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. |
| 58 | * SD | |MSB| |...| |LSB| x |...| x |MSB| |...| |LSB| x |...| x | |
| 59 | * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' |
| 60 | * | Left channel | Right channel | |
| 61 | */ |
| 62 | #define I2S_FMT_DATA_FORMAT_I2S (0 << I2S_FMT_DATA_FORMAT_SHIFT) |
| 63 | |
| 64 | /** @brief PCM Short Frame Sync Data Format. |
| 65 | * |
David B. Kinder | f00f585 | 2017-10-01 10:00:48 -0700 | [diff] [blame] | 66 | * Serial data is transmitted in two's complement with the MSB first. Both |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 67 | * Word Select (WS) and Serial Data (SD) signals are sampled on the falling edge |
| 68 | * of the clock signal (SCK). The falling edge of the frame sync signal (WS) |
| 69 | * indicates the start of the PCM word. The frame sync is one clock cycle long. |
| 70 | * An arbitrary number of data words can be sent in one frame. |
| 71 | * |
| 72 | * .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. |
| 73 | * SCK -' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- |
| 74 | * .---. .---. |
| 75 | * WS -' '- -' '- |
| 76 | * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.--- |
| 77 | * SD | |MSB| |...| |LSB|MSB| |...| |LSB|MSB| |...| |LSB| |
| 78 | * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'--- |
| 79 | * | Word 1 | Word 2 | Word 3 | Word n | |
| 80 | */ |
| 81 | #define I2S_FMT_DATA_FORMAT_PCM_SHORT (1 << I2S_FMT_DATA_FORMAT_SHIFT) |
| 82 | |
| 83 | /** @brief PCM Long Frame Sync Data Format. |
| 84 | * |
David B. Kinder | f00f585 | 2017-10-01 10:00:48 -0700 | [diff] [blame] | 85 | * Serial data is transmitted in two's complement with the MSB first. Both |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 86 | * Word Select (WS) and Serial Data (SD) signals are sampled on the falling edge |
| 87 | * of the clock signal (SCK). The rising edge of the frame sync signal (WS) |
| 88 | * indicates the start of the PCM word. The frame sync has an arbitrary length, |
| 89 | * however it has to fall before the start of the next frame. An arbitrary |
| 90 | * number of data words can be sent in one frame. |
| 91 | * |
| 92 | * .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. |
| 93 | * SCK -' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- |
| 94 | * .--- ---. ---. ---. .--- |
| 95 | * WS -' '- '- '- -' |
| 96 | * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.--- |
| 97 | * SD | |MSB| |...| |LSB|MSB| |...| |LSB|MSB| |...| |LSB| |
| 98 | * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'--- |
| 99 | * | Word 1 | Word 2 | Word 3 | Word n | |
| 100 | */ |
| 101 | #define I2S_FMT_DATA_FORMAT_PCM_LONG (2 << I2S_FMT_DATA_FORMAT_SHIFT) |
| 102 | |
| 103 | /** |
| 104 | * @brief Left Justified Data Format. |
| 105 | * |
David B. Kinder | f00f585 | 2017-10-01 10:00:48 -0700 | [diff] [blame] | 106 | * Serial data is transmitted in two's complement with the MSB first. Both |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 107 | * Word Select (WS) and Serial Data (SD) signals are sampled on the rising edge |
| 108 | * of the clock signal (SCK). The bits within the data word are left justified |
| 109 | * such that the MSB is always sent in the clock period following the WS |
| 110 | * transition. Left channel data are sent first indicated by WS = 1, followed |
| 111 | * by right channel data indicated by WS = 0. |
| 112 | * |
| 113 | * .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. |
| 114 | * SCK -' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- |
| 115 | * .-------------------------------. .- |
| 116 | * WS ---' '-------------------------------' |
| 117 | * ---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.- |
| 118 | * SD |MSB| |...| |LSB| x |...| x |MSB| |...| |LSB| x |...| x | |
| 119 | * ---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'- |
| 120 | * | Left channel | Right channel | |
| 121 | */ |
| 122 | #define I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED (3 << I2S_FMT_DATA_FORMAT_SHIFT) |
| 123 | |
| 124 | /** |
| 125 | * @brief Right Justified Data Format. |
| 126 | * |
David B. Kinder | f00f585 | 2017-10-01 10:00:48 -0700 | [diff] [blame] | 127 | * Serial data is transmitted in two's complement with the MSB first. Both |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 128 | * Word Select (WS) and Serial Data (SD) signals are sampled on the rising edge |
| 129 | * of the clock signal (SCK). The bits within the data word are right justified |
| 130 | * such that the LSB is always sent in the clock period preceding the WS |
| 131 | * transition. Left channel data are sent first indicated by WS = 1, followed |
| 132 | * by right channel data indicated by WS = 0. |
| 133 | * |
| 134 | * .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. |
| 135 | * SCK -' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- |
| 136 | * .-------------------------------. .- |
| 137 | * WS ---' '-------------------------------' |
| 138 | * ---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.- |
| 139 | * SD | x |...| x |MSB| |...| |LSB| x |...| x |MSB| |...| |LSB| |
| 140 | * ---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'- |
| 141 | * | Left channel | Right channel | |
| 142 | */ |
| 143 | #define I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED (4 << I2S_FMT_DATA_FORMAT_SHIFT) |
| 144 | |
| 145 | /** Send MSB first */ |
| 146 | #define I2S_FMT_DATA_ORDER_MSB (0 << 3) |
| 147 | /** Send LSB first */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 148 | #define I2S_FMT_DATA_ORDER_LSB BIT(3) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 149 | /** Invert bit ordering, send LSB first */ |
| 150 | #define I2S_FMT_DATA_ORDER_INV I2S_FMT_DATA_ORDER_LSB |
Rajavardhan Gundi | 5b6f024 | 2018-02-28 15:50:20 +0530 | [diff] [blame] | 151 | |
| 152 | /** Data Format bit field position. */ |
| 153 | #define I2S_FMT_CLK_FORMAT_SHIFT 4 |
| 154 | /** Data Format bit field mask. */ |
| 155 | #define I2S_FMT_CLK_FORMAT_MASK (0x3 << I2S_FMT_CLK_FORMAT_SHIFT) |
| 156 | |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 157 | /** Invert bit clock */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 158 | #define I2S_FMT_BIT_CLK_INV BIT(4) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 159 | /** Invert frame clock */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 160 | #define I2S_FMT_FRAME_CLK_INV BIT(5) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 161 | |
Rajavardhan Gundi | 5b6f024 | 2018-02-28 15:50:20 +0530 | [diff] [blame] | 162 | /** NF represents "Normal Frame" whereas IF represents "Inverted Frame" |
| 163 | * NB represents "Normal Bit Clk" whereas IB represents "Inverted Bit clk" |
| 164 | */ |
| 165 | #define I2S_FMT_CLK_NF_NB (0 << I2S_FMT_CLK_FORMAT_SHIFT) |
| 166 | #define I2S_FMT_CLK_NF_IB (1 << I2S_FMT_CLK_FORMAT_SHIFT) |
| 167 | #define I2S_FMT_CLK_IF_NB (2 << I2S_FMT_CLK_FORMAT_SHIFT) |
| 168 | #define I2S_FMT_CLK_IF_IB (3 << I2S_FMT_CLK_FORMAT_SHIFT) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 169 | |
| 170 | typedef u8_t i2s_opt_t; |
| 171 | |
| 172 | /** Run bit clock continuously */ |
| 173 | #define I2S_OPT_BIT_CLK_CONT (0 << 0) |
| 174 | /** Run bit clock when sending data only */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 175 | #define I2S_OPT_BIT_CLK_GATED BIT(0) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 176 | /** I2S driver is bit clock master */ |
| 177 | #define I2S_OPT_BIT_CLK_MASTER (0 << 1) |
| 178 | /** I2S driver is bit clock slave */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 179 | #define I2S_OPT_BIT_CLK_SLAVE BIT(1) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 180 | /** I2S driver is frame clock master */ |
| 181 | #define I2S_OPT_FRAME_CLK_MASTER (0 << 2) |
| 182 | /** I2S driver is frame clock slave */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 183 | #define I2S_OPT_FRAME_CLK_SLAVE BIT(2) |
Rajavardhan Gundi | 5b6f024 | 2018-02-28 15:50:20 +0530 | [diff] [blame] | 184 | |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 185 | /** @brief Loop back mode. |
| 186 | * |
| 187 | * In loop back mode RX input will be connected internally to TX output. |
| 188 | * This is used primarily for testing. |
| 189 | */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 190 | #define I2S_OPT_LOOPBACK BIT(7) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 191 | |
Rajavardhan Gundi | 5b6f024 | 2018-02-28 15:50:20 +0530 | [diff] [blame] | 192 | /** @brief Ping pong mode |
| 193 | * |
| 194 | * In ping pong mode TX output will keep alternating between a ping buffer |
| 195 | * and a pong buffer. This is normally used in audio streams when one buffer |
| 196 | * is being populated while the other is being played (DMAed) and vice versa. |
| 197 | * So, in this mode, 2 sets of buffers fixed in size are used. Static Arrays |
| 198 | * are used to achieve this and hence they are never freed. |
| 199 | */ |
Flavio Ceolin | 95eb2b4 | 2019-03-08 12:35:46 -0800 | [diff] [blame] | 200 | #define I2S_OPT_PINGPONG BIT(6) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 201 | |
Anas Nashif | 11828bf | 2018-02-25 08:31:17 -0600 | [diff] [blame] | 202 | /** |
| 203 | * @brief I2C Direction |
| 204 | */ |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 205 | enum i2s_dir { |
| 206 | /** Receive data */ |
| 207 | I2S_DIR_RX, |
| 208 | /** Transmit data */ |
| 209 | I2S_DIR_TX, |
| 210 | }; |
| 211 | |
| 212 | /** Interface state */ |
| 213 | enum i2s_state { |
| 214 | /** @brief The interface is not ready. |
| 215 | * |
| 216 | * The interface was initialized but is not yet ready to receive / |
| 217 | * transmit data. Call i2s_configure() to configure interface and change |
| 218 | * its state to READY. |
| 219 | */ |
| 220 | I2S_STATE_NOT_READY, |
| 221 | /** The interface is ready to receive / transmit data. */ |
| 222 | I2S_STATE_READY, |
| 223 | /** The interface is receiving / transmitting data. */ |
| 224 | I2S_STATE_RUNNING, |
| 225 | /** The interface is draining its transmit queue. */ |
| 226 | I2S_STATE_STOPPING, |
| 227 | /** TX buffer underrun or RX buffer overrun has occurred. */ |
| 228 | I2S_STATE_ERROR, |
| 229 | }; |
| 230 | |
| 231 | /** Trigger command */ |
| 232 | enum i2s_trigger_cmd { |
| 233 | /** @brief Start the transmission / reception of data. |
| 234 | * |
| 235 | * If I2S_DIR_TX is set some data has to be queued for transmission by |
| 236 | * the i2s_write() function. This trigger can be used in READY state |
| 237 | * only and changes the interface state to RUNNING. |
| 238 | */ |
| 239 | I2S_TRIGGER_START, |
| 240 | /** @brief Stop the transmission / reception of data. |
| 241 | * |
| 242 | * Stop the transmission / reception of data at the end of the current |
| 243 | * memory block. This trigger can be used in RUNNING state only and at |
| 244 | * first changes the interface state to STOPPING. When the current TX / |
| 245 | * RX block is transmitted / received the state is changed to READY. |
| 246 | * Subsequent START trigger will resume transmission / reception where |
| 247 | * it stopped. |
| 248 | */ |
| 249 | I2S_TRIGGER_STOP, |
| 250 | /** @brief Empty the transmit queue. |
| 251 | * |
| 252 | * Send all data in the transmit queue and stop the transmission. |
| 253 | * If the trigger is applied to the RX queue it has the same effect as |
| 254 | * I2S_TRIGGER_STOP. This trigger can be used in RUNNING state only and |
| 255 | * at first changes the interface state to STOPPING. When all TX blocks |
| 256 | * are transmitted the state is changed to READY. |
| 257 | */ |
| 258 | I2S_TRIGGER_DRAIN, |
| 259 | /** @brief Discard the transmit / receive queue. |
| 260 | * |
| 261 | * Stop the transmission / reception immediately and discard the |
| 262 | * contents of the respective queue. This trigger can be used in any |
| 263 | * state other than NOT_READY and changes the interface state to READY. |
| 264 | */ |
| 265 | I2S_TRIGGER_DROP, |
| 266 | /** @brief Prepare the queues after underrun/overrun error has occurred. |
| 267 | * |
| 268 | * This trigger can be used in ERROR state only and changes the |
| 269 | * interface state to READY. |
| 270 | */ |
| 271 | I2S_TRIGGER_PREPARE, |
| 272 | }; |
| 273 | |
| 274 | /** @struct i2s_config |
| 275 | * @brief Interface configuration options. |
| 276 | * |
| 277 | * Memory slab pointed to by the mem_slab field has to be defined and |
| 278 | * initialized by the user. For I2S driver to function correctly number of |
| 279 | * memory blocks in a slab has to be at least 2 per queue. Size of the memory |
| 280 | * block should be multiple of frame_size where frame_size = (channels * |
| 281 | * word_size_bytes). As an example 16 bit word will occupy 2 bytes, 24 or 32 |
| 282 | * bit word will occupy 4 bytes. |
| 283 | * |
| 284 | * Please check Zephyr Kernel Primer for more information on memory slabs. |
| 285 | * |
| 286 | * @remark When I2S data format is selected parameter channels is ignored, |
| 287 | * number of words in a frame is always 2. |
| 288 | * |
| 289 | * @param word_size Number of bits representing one data word. |
| 290 | * @param channels Number of words per frame. |
| 291 | * @param format Data stream format as defined by I2S_FMT_* constants. |
| 292 | * @param options Configuration options as defined by I2S_OPT_* constants. |
| 293 | * @param frame_clk_freq Frame clock (WS) frequency, this is sampling rate. |
| 294 | * @param mem_slab memory slab to store RX/TX data. |
| 295 | * @param block_size Size of one RX/TX memory block (buffer) in bytes. |
| 296 | * @param timeout Read/Write timeout. Number of milliseconds to wait in case TX |
| 297 | * queue is full, RX queue is empty or one of the special values |
| 298 | * K_NO_WAIT, K_FOREVER. |
| 299 | */ |
| 300 | struct i2s_config { |
| 301 | u8_t word_size; |
| 302 | u8_t channels; |
| 303 | i2s_fmt_t format; |
| 304 | i2s_opt_t options; |
| 305 | u32_t frame_clk_freq; |
| 306 | struct k_mem_slab *mem_slab; |
| 307 | size_t block_size; |
| 308 | s32_t timeout; |
| 309 | }; |
| 310 | |
| 311 | /** |
| 312 | * @cond INTERNAL_HIDDEN |
| 313 | * |
| 314 | * For internal use only, skip these in public documentation. |
| 315 | */ |
| 316 | struct i2s_driver_api { |
| 317 | int (*configure)(struct device *dev, enum i2s_dir dir, |
| 318 | struct i2s_config *cfg); |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 319 | struct i2s_config *(*config_get)(struct device *dev, |
| 320 | enum i2s_dir dir); |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 321 | int (*read)(struct device *dev, void **mem_block, size_t *size); |
| 322 | int (*write)(struct device *dev, void *mem_block, size_t size); |
| 323 | int (*trigger)(struct device *dev, enum i2s_dir dir, |
| 324 | enum i2s_trigger_cmd cmd); |
| 325 | }; |
| 326 | /** |
| 327 | * @endcond |
| 328 | */ |
| 329 | |
| 330 | /** |
| 331 | * @brief Configure operation of a host I2S controller. |
| 332 | * |
| 333 | * The dir parameter specifies if Transmit (TX) or Receive (RX) direction |
| 334 | * will be configured by data provided via cfg parameter. |
| 335 | * |
| 336 | * The function can be called in NOT_READY or READY state only. If executed |
| 337 | * successfully the function will change the interface state to READY. |
| 338 | * |
| 339 | * If the function is called with the parameter cfg->frame_clk_freq set to 0 |
| 340 | * the interface state will be changed to NOT_READY. |
| 341 | * |
| 342 | * @param dev Pointer to the device structure for the driver instance. |
| 343 | * @param dir Stream direction: RX or TX as defined by I2S_DIR_* |
| 344 | * @param cfg Pointer to the structure containing configuration parameters. |
| 345 | * |
| 346 | * @retval 0 If successful. |
| 347 | * @retval -EINVAL Invalid argument. |
| 348 | */ |
Andrew Boie | ad4df68 | 2018-11-14 15:00:27 -0800 | [diff] [blame] | 349 | __syscall int i2s_configure(struct device *dev, enum i2s_dir dir, |
| 350 | struct i2s_config *cfg); |
| 351 | |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 352 | static inline int z_impl_i2s_configure(struct device *dev, enum i2s_dir dir, |
Andrew Boie | ad4df68 | 2018-11-14 15:00:27 -0800 | [diff] [blame] | 353 | struct i2s_config *cfg) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 354 | { |
| 355 | const struct i2s_driver_api *api = dev->driver_api; |
| 356 | |
| 357 | return api->configure(dev, dir, cfg); |
| 358 | } |
| 359 | |
| 360 | /** |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 361 | * @brief Fetch configuration information of a host I2S controller |
| 362 | * |
| 363 | * @param dev Pointer to the device structure for the driver instance |
| 364 | * @param dir Stream direction: RX or TX as defined by I2S_DIR_* |
| 365 | * @retval Pointer to the structure containing configuration parameters, |
| 366 | * or NULL if un-configured |
| 367 | */ |
| 368 | static inline struct i2s_config *i2s_config_get(struct device *dev, |
| 369 | enum i2s_dir dir) |
| 370 | { |
| 371 | const struct i2s_driver_api *api = dev->driver_api; |
| 372 | |
| 373 | return api->config_get(dev, dir); |
| 374 | } |
| 375 | |
| 376 | /** |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 377 | * @brief Read data from the RX queue. |
| 378 | * |
| 379 | * Data received by the I2S interface is stored in the RX queue consisting of |
| 380 | * memory blocks preallocated by this function from rx_mem_slab (as defined by |
| 381 | * i2s_configure). Ownership of the RX memory block is passed on to the user |
| 382 | * application which has to release it. |
| 383 | * |
| 384 | * The data is read in chunks equal to the size of the memory block. If the |
| 385 | * interface is in READY state the number of bytes read can be smaller. |
| 386 | * |
| 387 | * If there is no data in the RX queue the function will block waiting for |
| 388 | * the next RX memory block to fill in. This operation can timeout as defined |
| 389 | * by i2s_configure. If the timeout value is set to K_NO_WAIT the function |
| 390 | * is non-blocking. |
| 391 | * |
| 392 | * Reading from the RX queue is possible in any state other than NOT_READY. |
| 393 | * If the interface is in the ERROR state it is still possible to read all the |
| 394 | * valid data stored in RX queue. Afterwards the function will return -EIO |
| 395 | * error. |
| 396 | * |
| 397 | * @param dev Pointer to the device structure for the driver instance. |
| 398 | * @param mem_block Pointer to the RX memory block containing received data. |
| 399 | * @param size Pointer to the variable storing the number of bytes read. |
| 400 | * |
| 401 | * @retval 0 If successful. |
| 402 | * @retval -EIO The interface is in NOT_READY or ERROR state and there are no |
| 403 | * more data blocks in the RX queue. |
| 404 | * @retval -EBUSY Returned without waiting. |
| 405 | * @retval -EAGAIN Waiting period timed out. |
| 406 | */ |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 407 | static inline int i2s_read(struct device *dev, void **mem_block, |
| 408 | size_t *size) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 409 | { |
| 410 | const struct i2s_driver_api *api = dev->driver_api; |
| 411 | |
| 412 | return api->read(dev, mem_block, size); |
| 413 | } |
| 414 | |
| 415 | /** |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 416 | * @brief Read data from the RX queue into a provided buffer |
| 417 | * |
| 418 | * Data received by the I2S interface is stored in the RX queue consisting of |
| 419 | * memory blocks preallocated by this function from rx_mem_slab (as defined by |
| 420 | * i2s_configure). Calling this function removes one block from the queue |
| 421 | * which is copied into the provided buffer and then freed. |
| 422 | * |
| 423 | * The provided buffer must be large enough to contain a full memory block |
| 424 | * of data, which is parameterized for the channel via i2s_configure(). |
| 425 | * |
| 426 | * This function is otherwise equivalent to i2s_read(). |
| 427 | * |
| 428 | * @param dev Pointer to the device structure for the driver instance. |
| 429 | * @param buf Destination buffer for read data, which must be at least the |
| 430 | * as large as the configured memory block size for the RX channel. |
| 431 | * @param size Pointer to the variable storing the number of bytes read. |
| 432 | * |
| 433 | * @retval 0 If successful. |
| 434 | * @retval -EIO The interface is in NOT_READY or ERROR state and there are no |
| 435 | * more data blocks in the RX queue. |
| 436 | * @retval -EBUSY Returned without waiting. |
| 437 | * @retval -EAGAIN Waiting period timed out. |
| 438 | */ |
| 439 | __syscall int i2s_buf_read(struct device *dev, void *buf, size_t *size); |
| 440 | |
| 441 | /** |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 442 | * @brief Write data to the TX queue. |
| 443 | * |
| 444 | * Data to be sent by the I2S interface is stored first in the TX queue. TX |
| 445 | * queue consists of memory blocks preallocated by the user from tx_mem_slab |
| 446 | * (as defined by i2s_configure). This function takes ownership of the memory |
| 447 | * block and will release it when all data are transmitted. |
| 448 | * |
| 449 | * If there are no free slots in the TX queue the function will block waiting |
| 450 | * for the next TX memory block to be send and removed from the queue. This |
| 451 | * operation can timeout as defined by i2s_configure. If the timeout value is |
| 452 | * set to K_NO_WAIT the function is non-blocking. |
| 453 | * |
| 454 | * Writing to the TX queue is only possible if the interface is in READY or |
| 455 | * RUNNING state. |
| 456 | * |
| 457 | * @param dev Pointer to the device structure for the driver instance. |
| 458 | * @param mem_block Pointer to the TX memory block containing data to be sent. |
| 459 | * @param size Number of bytes to write. This value has to be equal or smaller |
| 460 | * than the size of the memory block. |
| 461 | * |
| 462 | * @retval 0 If successful. |
| 463 | * @retval -EIO The interface is not in READY or RUNNING state. |
| 464 | * @retval -EBUSY Returned without waiting. |
| 465 | * @retval -EAGAIN Waiting period timed out. |
| 466 | */ |
| 467 | static inline int i2s_write(struct device *dev, void *mem_block, size_t size) |
| 468 | { |
| 469 | const struct i2s_driver_api *api = dev->driver_api; |
| 470 | |
| 471 | return api->write(dev, mem_block, size); |
| 472 | } |
| 473 | |
| 474 | /** |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 475 | * @brief Write data to the TX queue from a provided buffer |
| 476 | * |
| 477 | * This function acquires a memory block from the I2S channel TX queue |
| 478 | * and copies the provided data buffer into it. It is otherwise equivalent |
| 479 | * to i2s_write(). |
| 480 | * |
| 481 | * @param dev Pointer to the device structure for the driver instance. |
| 482 | * @param buf Pointer to a buffer containing the data to transmit. |
| 483 | * @param size Number of bytes to write. This value has to be equal or smaller |
| 484 | * than the size of the channel's TX memory block configuration. |
| 485 | * |
| 486 | * @retval 0 If successful. |
| 487 | * @retval -EIO The interface is not in READY or RUNNING state. |
| 488 | * @retval -EBUSY Returned without waiting. |
| 489 | * @retval -EAGAIN Waiting period timed out. |
| 490 | * @retval -ENOMEM No memory in TX slab queue. |
| 491 | * @retval -EINVAL Size parameter larger than TX queue memory block. |
| 492 | */ |
| 493 | __syscall int i2s_buf_write(struct device *dev, void *buf, size_t size); |
| 494 | |
| 495 | /** |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 496 | * @brief Send a trigger command. |
| 497 | * |
| 498 | * @param dev Pointer to the device structure for the driver instance. |
| 499 | * @param dir Stream direction: RX or TX. |
| 500 | * @param cmd Trigger command. |
| 501 | * |
| 502 | * @retval 0 If successful. |
| 503 | * @retval -EINVAL Invalid argument. |
| 504 | * @retval -EIO The trigger cannot be executed in the current state or a DMA |
| 505 | * channel cannot be allocated. |
| 506 | * @retval -ENOMEM RX/TX memory block not available. |
| 507 | */ |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 508 | __syscall int i2s_trigger(struct device *dev, enum i2s_dir dir, |
| 509 | enum i2s_trigger_cmd cmd); |
| 510 | |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 511 | static inline int z_impl_i2s_trigger(struct device *dev, enum i2s_dir dir, |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 512 | enum i2s_trigger_cmd cmd) |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 513 | { |
| 514 | const struct i2s_driver_api *api = dev->driver_api; |
| 515 | |
| 516 | return api->trigger(dev, dir, cmd); |
| 517 | } |
| 518 | |
Andrew Boie | 06c23f1 | 2018-08-09 12:38:18 -0700 | [diff] [blame] | 519 | #include <syscalls/i2s.h> |
| 520 | |
Piotr Mienkowski | cbff174 | 2017-07-10 23:27:10 +0200 | [diff] [blame] | 521 | #ifdef __cplusplus |
| 522 | } |
| 523 | #endif |
| 524 | |
| 525 | /** |
| 526 | * @} |
| 527 | */ |
| 528 | |
Flavio Ceolin | 67ca176 | 2018-09-14 10:43:44 -0700 | [diff] [blame] | 529 | #endif /* ZEPHYR_INCLUDE_I2S_H_ */ |