From b49dd6b1b4c6e5cfbad0df6464c0f0da67159177 Mon Sep 17 00:00:00 2001 From: Yuriy Vynnychek Date: Fri, 11 Feb 2022 14:09:30 +0200 Subject: [PATCH] drivers: pinctrl: introduce new Telink B91 Pinctrl driver Pinctrl driver basic support for Telink B91 platform. Signed-off-by: Yuriy Vynnychek --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.b91 | 11 +++ drivers/pinctrl/pinctrl_b91.c | 172 +++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.b91 create mode 100644 drivers/pinctrl/pinctrl_b91.c diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 79d0eaa6b37..8e3bf4df6d8 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_sources(common.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_TELINK_B91 pinctrl_b91.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AFIO pinctrl_gd32_afio.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NRF pinctrl_nrf.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8680acc3234..96adf043b05 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -29,6 +29,7 @@ config PINCTRL_DYNAMIC runtime. This can be useful, for example, to change the pins assigned to a peripheral at early boot stages depending on a certain input. +source "drivers/pinctrl/Kconfig.b91" source "drivers/pinctrl/Kconfig.gd32" source "drivers/pinctrl/Kconfig.nrf" source "drivers/pinctrl/Kconfig.rcar" diff --git a/drivers/pinctrl/Kconfig.b91 b/drivers/pinctrl/Kconfig.b91 new file mode 100644 index 00000000000..1e8e43e07dd --- /dev/null +++ b/drivers/pinctrl/Kconfig.b91 @@ -0,0 +1,11 @@ +# Copyright (c) 2022 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +DT_COMPAT_TELINK_B91_PINCTRL := telink,b91-pinctrl + +config PINCTRL_TELINK_B91 + bool "Telink B91 pin controller driver" + depends on SOC_RISCV_TELINK_B91 + default $(dt_compat_enabled,$(DT_COMPAT_TELINK_B91_PINCTRL)) + help + Enables Telink B91 pin controller driver diff --git a/drivers/pinctrl/pinctrl_b91.c b/drivers/pinctrl/pinctrl_b91.c new file mode 100644 index 00000000000..27a22eb36e2 --- /dev/null +++ b/drivers/pinctrl/pinctrl_b91.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2022 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "analog.h" +#include +#include + +#define DT_DRV_COMPAT telink_b91_pinctrl + +/** + * GPIO Function Enable Register + * ADDR PINS + * gpio_en: PORT_A[0-7] + * gpio_en + 1*8: PORT_B[0-7] + * gpio_en + 2*8: PORT_C[0-7] + * gpio_en + 3*8: PORT_D[0-7] + * gpio_en + 4*8: PORT_E[0-7] + * gpio_en + 5*8: PORT_F[0-7] + */ +#define reg_gpio_en(pin) (*(volatile uint8_t *)((uint32_t)DT_INST_REG_ADDR_BY_NAME(0, gpio_en) + \ + ((pin >> 8) * 8))) + +/** + * Function Multiplexer Register + * ADDR PINS + * pin_mux: PORT_A[0-3] + * pin_mux + 1: PORT_A[4-7] + * pin_mux + 2: PORT_B[0-3] + * pin_mux + 3: PORT_B[4-7] + * pin_mux + 4: PORT_C[0-3] + * pin_mux + 5: PORT_C[4-7] + * pin_mux + 6: PORT_D[0-3] + * pin_mux + 7: PORT_D[4-7] + * pin_mux + 0x20: PORT_E[0-3] + * pin_mux + 0x21: PORT_E[4-7] + * pin_mux + 0x26: PORT_F[0-3] + * pin_mux + 0x27: PORT_F[4-7] + */ +#define reg_pin_mux(pin) (*(volatile uint8_t *)((uint32_t)DT_INST_REG_ADDR_BY_NAME(0, pin_mux) + \ + (((pin >> 8) < 4) ? ((pin >> 8) * 2) : 0) + \ + (((pin >> 8) == 4) ? 0x20 : 0) + \ + (((pin >> 8) == 5) ? 0x26 : 0) + \ + ((pin & 0x0f0) ? 1 : 0))) + +/** + * Pull Up resistors enable + * ADDR PINS + * pull_up_en: PORT_A[0-3] + * pull_up_en + 1: PORT_A[4-7] + * pull_up_en + 2: PORT_B[0-3] + * pull_up_en + 3: PORT_B[4-7] + * pull_up_en + 4: PORT_C[0-3] + * pull_up_en + 5: PORT_C[4-7] + * pull_up_en + 6: PORT_D[0-3] + * pull_up_en + 7: PORT_D[4-7] + * pull_up_en + 8: PORT_E[0-3] + * pull_up_en + 9: PORT_E[4-7] + * pull_up_en + 10: PORT_F[0-3] + * pull_up_en + 11: PORT_F[4-7] + */ +#define reg_pull_up_en(pin) ((uint8_t)(DT_INST_REG_ADDR_BY_NAME(0, pull_up_en) + \ + ((pin >> 8) * 2) + \ + ((pin & 0xf0) ? 1 : 0))) + +/* Pinctrl driver initialization */ +static int pinctrl_b91_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* set pad_mul_sel register value from dts */ + reg_gpio_pad_mul_sel |= DT_INST_PROP(0, pad_mul_sel); + + return 0; +} + +SYS_INIT(pinctrl_b91_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +/* Act as GPIO function disable */ +static inline void pinctrl_b91_gpio_function_disable(uint32_t pin) +{ + uint8_t bit = pin & 0xff; + + reg_gpio_en(pin) &= ~bit; +} + +/* Get function value bits start position (offset) */ +static inline int pinctrl_b91_get_offset(uint32_t pin, uint8_t *offset) +{ + switch (B91_PINMUX_GET_PIN_ID(pin)) { + case B91_PIN_0: + *offset = B91_PIN_0_FUNC_POS; + break; + case B91_PIN_1: + *offset = B91_PIN_1_FUNC_POS; + break; + case B91_PIN_2: + *offset = B91_PIN_2_FUNC_POS; + break; + case B91_PIN_3: + *offset = B91_PIN_3_FUNC_POS; + break; + case B91_PIN_4: + *offset = B91_PIN_4_FUNC_POS; + break; + case B91_PIN_5: + *offset = B91_PIN_5_FUNC_POS; + break; + case B91_PIN_6: + *offset = B91_PIN_6_FUNC_POS; + break; + case B91_PIN_7: + *offset = B91_PIN_7_FUNC_POS; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* Set pin's function */ +static int pinctrl_configure_pin(const pinctrl_soc_pin_t *pinctrl) +{ + int status; + uint8_t mask; + uint8_t offset = 0; + uint8_t pull = B91_PINMUX_GET_PULL(*pinctrl); + uint8_t func = B91_PINMUX_GET_FUNC(*pinctrl); + uint32_t pin = B91_PINMUX_GET_PIN(*pinctrl); + uint8_t pull_up_en_addr = reg_pull_up_en(pin); + + /* calculate offset and mask for the func and pull values */ + status = pinctrl_b91_get_offset(pin, &offset); + if (status != 0) { + return status; + } + mask = (uint8_t) ~(BIT(offset) | BIT(offset + 1)); + + /* disable GPIO function (can be enabled back by GPIO init using GPIO driver) */ + pinctrl_b91_gpio_function_disable(pin); + + /* set func value */ + func = func << offset; + reg_pin_mux(pin) = (reg_pin_mux(pin) & mask) | func; + + /* set pull value */ + pull = pull << offset; + analog_write_reg8(pull_up_en_addr, (analog_read_reg8(pull_up_en_addr) & mask) | pull); + + return status; +} + +/* API implementation: configure_pins */ +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + int status = 0; + + for (uint8_t i = 0; i < pin_cnt; i++) { + status = pinctrl_configure_pin(pins++); + if (status < 0) { + break; + } + } + + return status; +}