1 /*
2  * Copyright (c) 2024 Michael Hope
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/pinctrl.h>
8 #include <zephyr/dt-bindings/pinctrl/ch32v003-pinctrl.h>
9 
10 #include <ch32fun.h>
11 
12 static GPIO_TypeDef *const wch_afio_pinctrl_regs[] = {
13 	(GPIO_TypeDef *)DT_REG_ADDR(DT_NODELABEL(gpioa)),
14 	(GPIO_TypeDef *)DT_REG_ADDR(DT_NODELABEL(gpioc)),
15 	(GPIO_TypeDef *)DT_REG_ADDR(DT_NODELABEL(gpiod)),
16 };
17 
pinctrl_configure_pins(const pinctrl_soc_pin_t * pins,uint8_t pin_cnt,uintptr_t reg)18 int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg)
19 {
20 	int i;
21 
22 	for (i = 0; i < pin_cnt; i++, pins++) {
23 		uint8_t port = (pins->config >> CH32V003_PINCTRL_PORT_SHIFT) & 0x03;
24 		uint8_t pin = (pins->config >> CH32V003_PINCTRL_PIN_SHIFT) & 0x0F;
25 		uint8_t bit0 = (pins->config >> CH32V003_PINCTRL_RM_BASE_SHIFT) & 0x1F;
26 		uint8_t remap = (pins->config >> CH32V003_PINCTRL_RM_SHIFT) & 0x3;
27 		GPIO_TypeDef *regs = wch_afio_pinctrl_regs[port];
28 		uint32_t pcfr1 = AFIO->PCFR1;
29 		uint8_t cfg = 0;
30 
31 		if (remap != 0) {
32 			RCC->APB2PCENR |= RCC_AFIOEN;
33 		}
34 
35 		if (pins->output_high || pins->output_low) {
36 			cfg |= (pins->slew_rate + 1);
37 			if (pins->drive_open_drain) {
38 				cfg |= BIT(2);
39 			}
40 			/* Select the alternate function */
41 			cfg |= BIT(3);
42 		} else {
43 			if (pins->bias_pull_up || pins->bias_pull_down) {
44 				cfg |= BIT(3);
45 			}
46 		}
47 		regs->CFGLR = (regs->CFGLR & ~(0x0F << (pin * 4))) | (cfg << (pin * 4));
48 
49 		if (pins->output_high) {
50 			regs->OUTDR |= BIT(pin);
51 			regs->BSHR |= BIT(pin);
52 		} else if (pins->output_low) {
53 			regs->OUTDR |= BIT(pin);
54 			/* Reset the pin. */
55 			regs->BSHR |= BIT(pin + 16);
56 		} else {
57 			regs->OUTDR &= ~(1 << pin);
58 			if (pins->bias_pull_up) {
59 				regs->BSHR = BIT(pin);
60 			}
61 			if (pins->bias_pull_down) {
62 				regs->BCR = BIT(pin);
63 			}
64 		}
65 
66 		if (bit0 == CH32V003_PINMUX_I2C1_RM) {
67 			pcfr1 |= ((remap & 1) << CH32V003_PINMUX_I2C1_RM) |
68 				 (((remap >> 1) & 1) << CH32V003_PINMUX_I2C1_RM1);
69 		} else if (bit0 == CH32V003_PINMUX_USART1_RM) {
70 			pcfr1 |= ((remap & 1) << CH32V003_PINMUX_USART1_RM) |
71 				 (((remap >> 1) & 1) << CH32V003_PINMUX_USART1_RM1);
72 		} else {
73 			pcfr1 |= remap << bit0;
74 		}
75 		AFIO->PCFR1 = pcfr1;
76 	}
77 
78 	return 0;
79 }
80