|
| 1 | +/* |
| 2 | + * Copyright (c) 2024 Renesas Electronics Corporation |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + */ |
| 5 | + |
| 6 | +#define DT_DRV_COMPAT renesas_rz_scif_uart |
| 7 | + |
| 8 | +#include <zephyr/drivers/pinctrl.h> |
| 9 | +#include <zephyr/drivers/uart.h> |
| 10 | +#include <zephyr/logging/log.h> |
| 11 | +#include "r_scif_uart.h" |
| 12 | + |
| 13 | +LOG_MODULE_REGISTER(rz_scif_uart); |
| 14 | + |
| 15 | +struct uart_rz_scif_config { |
| 16 | + const struct pinctrl_dev_config *pin_config; |
| 17 | + const uart_api_t *fsp_api; |
| 18 | +}; |
| 19 | + |
| 20 | +struct uart_rz_scif_data { |
| 21 | + struct uart_config uart_config; |
| 22 | + uart_cfg_t *fsp_cfg; |
| 23 | + scif_uart_instance_ctrl_t *fsp_ctrl; |
| 24 | +}; |
| 25 | + |
| 26 | +static int uart_rz_scif_poll_in(const struct device *dev, unsigned char *c) |
| 27 | +{ |
| 28 | + struct uart_rz_scif_data *data = dev->data; |
| 29 | + R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; |
| 30 | + |
| 31 | + if (reg->FDR_b.R == 0U) { |
| 32 | + /* There are no characters available to read. */ |
| 33 | + return -1; |
| 34 | + } |
| 35 | + *c = reg->FRDR; |
| 36 | + |
| 37 | + return 0; |
| 38 | +} |
| 39 | + |
| 40 | +static void uart_rz_scif_poll_out(const struct device *dev, unsigned char c) |
| 41 | +{ |
| 42 | + struct uart_rz_scif_data *data = dev->data; |
| 43 | + R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; |
| 44 | + |
| 45 | + while (!reg->FSR_b.TDFE) { |
| 46 | + } |
| 47 | + |
| 48 | + reg->FTDR = c; |
| 49 | + |
| 50 | + while (!reg->FSR_b.TEND) { |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +static int uart_rz_scif_err_check(const struct device *dev) |
| 55 | +{ |
| 56 | + struct uart_rz_scif_data *data = dev->data; |
| 57 | + R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; |
| 58 | + |
| 59 | + const uint32_t fsr = reg->FSR; |
| 60 | + const uint32_t lsr = reg->LSR; |
| 61 | + int errors = 0; |
| 62 | + |
| 63 | + if ((lsr & R_SCIFA0_LSR_ORER_Msk) != 0) { |
| 64 | + errors |= UART_ERROR_OVERRUN; |
| 65 | + } |
| 66 | + if ((fsr & R_SCIFA0_FSR_PER_Msk) != 0) { |
| 67 | + errors |= UART_ERROR_PARITY; |
| 68 | + } |
| 69 | + if ((fsr & R_SCIFA0_FSR_FER_Pos) != 0) { |
| 70 | + errors |= UART_ERROR_FRAMING; |
| 71 | + } |
| 72 | + |
| 73 | + return errors; |
| 74 | +} |
| 75 | + |
| 76 | +static int uart_rz_scif_apply_config(const struct device *dev) |
| 77 | +{ |
| 78 | + struct uart_rz_scif_data *data = dev->data; |
| 79 | + |
| 80 | + struct uart_config *uart_config = &data->uart_config; |
| 81 | + uart_cfg_t *fsp_cfg = data->fsp_cfg; |
| 82 | + |
| 83 | + scif_baud_setting_t baud_setting; |
| 84 | + scif_uart_extended_cfg_t config_extend; |
| 85 | + const scif_uart_extended_cfg_t *fsp_config_extend = fsp_cfg->p_extend; |
| 86 | + |
| 87 | + fsp_err_t fsp_err; |
| 88 | + |
| 89 | + fsp_err = R_SCIF_UART_BaudCalculate(data->fsp_ctrl, uart_config->baudrate, false, 5000, |
| 90 | + &baud_setting); |
| 91 | + if (fsp_err) { |
| 92 | + return -EIO; |
| 93 | + } |
| 94 | + |
| 95 | + memcpy(fsp_config_extend->p_baud_setting, &baud_setting, sizeof(scif_baud_setting_t)); |
| 96 | + |
| 97 | + switch (uart_config->data_bits) { |
| 98 | + case UART_CFG_DATA_BITS_7: |
| 99 | + fsp_cfg->data_bits = UART_DATA_BITS_7; |
| 100 | + break; |
| 101 | + case UART_CFG_DATA_BITS_8: |
| 102 | + fsp_cfg->data_bits = UART_DATA_BITS_8; |
| 103 | + break; |
| 104 | + default: |
| 105 | + return -ENOTSUP; |
| 106 | + } |
| 107 | + |
| 108 | + switch (uart_config->parity) { |
| 109 | + case UART_CFG_PARITY_NONE: |
| 110 | + fsp_cfg->parity = UART_PARITY_OFF; |
| 111 | + break; |
| 112 | + case UART_CFG_PARITY_ODD: |
| 113 | + fsp_cfg->parity = UART_PARITY_ODD; |
| 114 | + break; |
| 115 | + case UART_CFG_PARITY_EVEN: |
| 116 | + fsp_cfg->parity = UART_PARITY_EVEN; |
| 117 | + break; |
| 118 | + default: |
| 119 | + return -ENOTSUP; |
| 120 | + } |
| 121 | + |
| 122 | + switch (uart_config->stop_bits) { |
| 123 | + case UART_CFG_STOP_BITS_1: |
| 124 | + fsp_cfg->stop_bits = UART_STOP_BITS_1; |
| 125 | + break; |
| 126 | + case UART_CFG_STOP_BITS_2: |
| 127 | + fsp_cfg->stop_bits = UART_STOP_BITS_2; |
| 128 | + break; |
| 129 | + default: |
| 130 | + return -ENOTSUP; |
| 131 | + } |
| 132 | + |
| 133 | + memcpy(&config_extend, fsp_config_extend->p_baud_setting, sizeof(scif_baud_setting_t)); |
| 134 | + |
| 135 | + switch (uart_config->flow_ctrl) { |
| 136 | + case UART_CFG_FLOW_CTRL_NONE: |
| 137 | + config_extend.flow_control = SCIF_UART_FLOW_CONTROL_NONE; |
| 138 | + config_extend.uart_mode = SCIF_UART_MODE_RS232; |
| 139 | + config_extend.rs485_setting.enable = SCI_UART_RS485_DISABLE; |
| 140 | + break; |
| 141 | + case UART_CFG_FLOW_CTRL_RTS_CTS: |
| 142 | + config_extend.flow_control = SCIF_UART_FLOW_CONTROL_AUTO; |
| 143 | + config_extend.uart_mode = SCIF_UART_MODE_RS232; |
| 144 | + config_extend.rs485_setting.enable = SCI_UART_RS485_DISABLE; |
| 145 | + break; |
| 146 | + default: |
| 147 | + return -ENOTSUP; |
| 148 | + } |
| 149 | + |
| 150 | + memcpy(fsp_config_extend->p_baud_setting, &config_extend, sizeof(scif_baud_setting_t)); |
| 151 | + |
| 152 | + return 0; |
| 153 | +} |
| 154 | + |
| 155 | +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE |
| 156 | + |
| 157 | +static int uart_rz_scif_configure(const struct device *dev, const struct uart_config *cfg) |
| 158 | +{ |
| 159 | + int err; |
| 160 | + fsp_err_t fsp_err; |
| 161 | + const struct uart_rz_scif_config *config = dev->config; |
| 162 | + struct uart_rz_scif_data *data = dev->data; |
| 163 | + |
| 164 | + memcpy(&data->uart_config, cfg, sizeof(struct uart_config)); |
| 165 | + |
| 166 | + err = uart_rz_scif_apply_config(dev); |
| 167 | + |
| 168 | + if (err) { |
| 169 | + return err; |
| 170 | + } |
| 171 | + |
| 172 | + fsp_err = config->fsp_api->close(data->fsp_ctrl); |
| 173 | + if (fsp_err) { |
| 174 | + return -EIO; |
| 175 | + } |
| 176 | + |
| 177 | + fsp_err = config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg); |
| 178 | + if (fsp_err) { |
| 179 | + return -EIO; |
| 180 | + } |
| 181 | + |
| 182 | + R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; |
| 183 | + /* Temporarily disable the DRI interrupt caused by receive data ready */ |
| 184 | + /* TODO: support interrupt-driven api */ |
| 185 | + reg->SCR_b.RIE = 0; |
| 186 | + |
| 187 | + return err; |
| 188 | +} |
| 189 | + |
| 190 | +static int uart_rz_scif_config_get(const struct device *dev, struct uart_config *cfg) |
| 191 | +{ |
| 192 | + struct uart_rz_scif_data *data = dev->data; |
| 193 | + |
| 194 | + memcpy(cfg, &data->uart_config, sizeof(struct uart_config)); |
| 195 | + return 0; |
| 196 | +} |
| 197 | + |
| 198 | +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ |
| 199 | + |
| 200 | +static const struct uart_driver_api uart_rz_scif_driver_api = { |
| 201 | + .poll_in = uart_rz_scif_poll_in, |
| 202 | + .poll_out = uart_rz_scif_poll_out, |
| 203 | + .err_check = uart_rz_scif_err_check, |
| 204 | +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE |
| 205 | + .configure = uart_rz_scif_configure, |
| 206 | + .config_get = uart_rz_scif_config_get, |
| 207 | +#endif |
| 208 | +}; |
| 209 | + |
| 210 | +static int uart_rz_scif_init(const struct device *dev) |
| 211 | +{ |
| 212 | + const struct uart_rz_scif_config *config = dev->config; |
| 213 | + struct uart_rz_scif_data *data = dev->data; |
| 214 | + int ret; |
| 215 | + |
| 216 | + /* Configure dt provided device signals when available */ |
| 217 | + ret = pinctrl_apply_state(config->pin_config, PINCTRL_STATE_DEFAULT); |
| 218 | + if (ret < 0) { |
| 219 | + return ret; |
| 220 | + } |
| 221 | + |
| 222 | + /* uart_rz_scif_apply_config must be called first before open api */ |
| 223 | + ret = uart_rz_scif_apply_config(dev); |
| 224 | + if (ret < 0) { |
| 225 | + return ret; |
| 226 | + } |
| 227 | + |
| 228 | + config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg); |
| 229 | + |
| 230 | + R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; |
| 231 | + /* Temporarily disable the DRI interrupt caused by receive data ready */ |
| 232 | + /* TODO: support interrupt-driven api */ |
| 233 | + reg->SCR_b.RIE = 0; |
| 234 | + |
| 235 | + return 0; |
| 236 | +} |
| 237 | + |
| 238 | +#define UART_RZG_INIT(n) \ |
| 239 | + static scif_uart_instance_ctrl_t g_uart##n##_ctrl; \ |
| 240 | + static scif_baud_setting_t g_uart##n##_baud_setting; \ |
| 241 | + static scif_uart_extended_cfg_t g_uart##n##_cfg_extend = { \ |
| 242 | + .bri_ipl = DT_INST_IRQ_BY_NAME(n, bri, priority), \ |
| 243 | + .bri_irq = DT_INST_IRQ_BY_NAME(n, bri, irq), \ |
| 244 | + .clock = SCIF_UART_CLOCK_INT, \ |
| 245 | + .noise_cancel = SCIF_UART_NOISE_CANCELLATION_ENABLE, \ |
| 246 | + .p_baud_setting = &g_uart##n##_baud_setting, \ |
| 247 | + .rx_fifo_trigger = SCIF_UART_RECEIVE_TRIGGER_MAX, \ |
| 248 | + .rts_fifo_trigger = SCIF_UART_RTS_TRIGGER_14, \ |
| 249 | + .uart_mode = SCIF_UART_MODE_RS232, \ |
| 250 | + .flow_control = SCIF_UART_FLOW_CONTROL_NONE, \ |
| 251 | + .rs485_setting = \ |
| 252 | + { \ |
| 253 | + .enable = (sci_uart_rs485_enable_t)NULL, \ |
| 254 | + .polarity = SCI_UART_RS485_DE_POLARITY_HIGH, \ |
| 255 | + .de_control_pin = \ |
| 256 | + (bsp_io_port_pin_t)SCIF_UART_INVALID_16BIT_PARAM, \ |
| 257 | + }, \ |
| 258 | + }; \ |
| 259 | + static uart_cfg_t g_uart##n##_cfg = { \ |
| 260 | + .channel = DT_INST_PROP(n, channel), \ |
| 261 | + .p_callback = NULL, \ |
| 262 | + .p_context = NULL, \ |
| 263 | + .p_extend = &g_uart##n##_cfg_extend, \ |
| 264 | + .p_transfer_tx = NULL, \ |
| 265 | + .p_transfer_rx = NULL, \ |
| 266 | + .rxi_ipl = DT_INST_IRQ_BY_NAME(n, rxi, priority), \ |
| 267 | + .txi_ipl = DT_INST_IRQ_BY_NAME(n, txi, priority), \ |
| 268 | + .tei_ipl = DT_INST_IRQ_BY_NAME(n, tei, priority), \ |
| 269 | + .eri_ipl = DT_INST_IRQ_BY_NAME(n, eri, priority), \ |
| 270 | + .rxi_irq = DT_INST_IRQ_BY_NAME(n, rxi, irq), \ |
| 271 | + .txi_irq = DT_INST_IRQ_BY_NAME(n, txi, irq), \ |
| 272 | + .tei_irq = DT_INST_IRQ_BY_NAME(n, tei, irq), \ |
| 273 | + .eri_irq = DT_INST_IRQ_BY_NAME(n, eri, irq), \ |
| 274 | + }; \ |
| 275 | + PINCTRL_DT_INST_DEFINE(n); \ |
| 276 | + static const struct uart_rz_scif_config uart_rz_scif_config_##n = { \ |
| 277 | + .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n), .fsp_api = &g_uart_on_scif}; \ |
| 278 | + static struct uart_rz_scif_data uart_rz_scif_data_##n = { \ |
| 279 | + .uart_config = \ |
| 280 | + { \ |
| 281 | + .baudrate = DT_INST_PROP_OR(n, current_speed, 115200), \ |
| 282 | + .parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \ |
| 283 | + .stop_bits = \ |
| 284 | + DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \ |
| 285 | + .data_bits = \ |
| 286 | + DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \ |
| 287 | + .flow_ctrl = DT_INST_PROP_OR(n, hw_flow_control, \ |
| 288 | + UART_CFG_FLOW_CTRL_NONE), \ |
| 289 | + }, \ |
| 290 | + .fsp_cfg = &g_uart##n##_cfg, \ |
| 291 | + .fsp_ctrl = &g_uart##n##_ctrl, \ |
| 292 | + }; \ |
| 293 | + static int uart_rz_scif_init_##n(const struct device *dev) \ |
| 294 | + { \ |
| 295 | + return uart_rz_scif_init(dev); \ |
| 296 | + } \ |
| 297 | + DEVICE_DT_INST_DEFINE(n, &uart_rz_scif_init_##n, NULL, &uart_rz_scif_data_##n, \ |
| 298 | + &uart_rz_scif_config_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ |
| 299 | + &uart_rz_scif_driver_api); |
| 300 | + |
| 301 | +DT_INST_FOREACH_STATUS_OKAY(UART_RZG_INIT) |
0 commit comments