|
| 1 | +/* |
| 2 | + * Copyright (c) 2021 Telink Semiconductor |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#define DT_DRV_COMPAT telink_b91_pinmux |
| 8 | + |
| 9 | +#include "analog.h" |
| 10 | +#include <drivers/pinmux.h> |
| 11 | + |
| 12 | + |
| 13 | +/** |
| 14 | + * GPIO Function Enable Register |
| 15 | + * ADDR PINS |
| 16 | + * gpio_en: PORT_A[0-7] |
| 17 | + * gpio_en + 1*8: PORT_B[0-7] |
| 18 | + * gpio_en + 2*8: PORT_C[0-7] |
| 19 | + * gpio_en + 3*8: PORT_D[0-7] |
| 20 | + * gpio_en + 4*8: PORT_E[0-7] |
| 21 | + * gpio_en + 5*8: PORT_F[0-7] |
| 22 | + */ |
| 23 | +#define reg_gpio_en(pin) (*(volatile uint8_t *)((uint32_t)DT_INST_REG_ADDR_BY_NAME(0, gpio_en) + \ |
| 24 | + ((pin >> 8) * 8))) |
| 25 | + |
| 26 | +/** |
| 27 | + * Function Multiplexer Register |
| 28 | + * ADDR PINS |
| 29 | + * pin_mux: PORT_A[0-3] |
| 30 | + * pin_mux + 1: PORT_A[4-7] |
| 31 | + * pin_mux + 2: PORT_B[0-3] |
| 32 | + * pin_mux + 3: PORT_B[4-7] |
| 33 | + * pin_mux + 4: PORT_C[0-3] |
| 34 | + * pin_mux + 5: PORT_C[4-7] |
| 35 | + * pin_mux + 6: PORT_D[0-3] |
| 36 | + * pin_mux + 7: PORT_D[4-7] |
| 37 | + * pin_mux + 0x20: PORT_E[0-3] |
| 38 | + * pin_mux + 0x21: PORT_E[4-7] |
| 39 | + * pin_mux + 0x26: PORT_F[0-3] |
| 40 | + * pin_mux + 0x27: PORT_F[4-7] |
| 41 | + */ |
| 42 | +#define reg_pin_mux(pin) (*(volatile uint8_t *)((uint32_t)DT_INST_REG_ADDR_BY_NAME(0, pin_mux) + \ |
| 43 | + (((pin >> 8) < 4) ? ((pin >> 8) * 2) : 0) + \ |
| 44 | + (((pin >> 8) == 4) ? 0x20 : 0) + \ |
| 45 | + (((pin >> 8) == 5) ? 0x26 : 0) + \ |
| 46 | + ((pin & 0x0f0) ? 1 : 0))) |
| 47 | + |
| 48 | +/** |
| 49 | + * Pull Up resistors enable |
| 50 | + * ADDR PINS |
| 51 | + * pull_up_en: PORT_A[0-3] |
| 52 | + * pull_up_en + 1: PORT_A[4-7] |
| 53 | + * pull_up_en + 2: PORT_B[0-3] |
| 54 | + * pull_up_en + 3: PORT_B[4-7] |
| 55 | + * pull_up_en + 4: PORT_C[0-3] |
| 56 | + * pull_up_en + 5: PORT_C[4-7] |
| 57 | + * pull_up_en + 6: PORT_D[0-3] |
| 58 | + * pull_up_en + 7: PORT_D[4-7] |
| 59 | + * pull_up_en + 8: PORT_E[0-3] |
| 60 | + * pull_up_en + 9: PORT_E[4-7] |
| 61 | + * pull_up_en + 10: PORT_F[0-3] |
| 62 | + * pull_up_en + 11: PORT_F[4-7] |
| 63 | + */ |
| 64 | +#define reg_pull_up_en(pin) ((uint8_t)(DT_INST_REG_ADDR_BY_NAME(0, pull_up_en) + \ |
| 65 | + ((pin >> 8) * 2) + \ |
| 66 | + ((pin & 0xf0) ? 1 : 0))) |
| 67 | + |
| 68 | +/* GPIO Pull-Up options */ |
| 69 | +#define PINMUX_B91_PULLUP_DISABLE ((uint8_t)0u) |
| 70 | +#define PINMUX_B91_PULLUP_10K ((uint8_t)3u) |
| 71 | + |
| 72 | +/* Get PinMux configuration */ |
| 73 | +#define GET_CFG(dev) ((const struct pinmux_b91_config *)dev->config) |
| 74 | + |
| 75 | + |
| 76 | +/* B91 PinMux config structure */ |
| 77 | +struct pinmux_b91_config { |
| 78 | + uint8_t pad_mul_sel; |
| 79 | +}; |
| 80 | + |
| 81 | + |
| 82 | +/* Act as GPIO function disable */ |
| 83 | +static inline void pinmux_b91_gpio_function_disable(uint32_t pin) |
| 84 | +{ |
| 85 | + uint8_t bit = pin & 0xff; |
| 86 | + |
| 87 | + reg_gpio_en(pin) &= ~bit; |
| 88 | +} |
| 89 | + |
| 90 | +/* Get function value bits start position (offset) */ |
| 91 | +static inline int pinmux_b91_get_func_offset(uint32_t pin, uint8_t *offset) |
| 92 | +{ |
| 93 | + switch ((pin & 0x0fu) != 0u ? pin & 0x0fu : (pin & 0xf0u) >> 4u) { |
| 94 | + case BIT(0): |
| 95 | + *offset = 0u; |
| 96 | + break; |
| 97 | + case BIT(1): |
| 98 | + *offset = 2u; |
| 99 | + break; |
| 100 | + case BIT(2): |
| 101 | + *offset = 4u; |
| 102 | + break; |
| 103 | + case BIT(3): |
| 104 | + *offset = 6u; |
| 105 | + break; |
| 106 | + |
| 107 | + default: |
| 108 | + return -EINVAL; |
| 109 | + } |
| 110 | + |
| 111 | + return 0; |
| 112 | +} |
| 113 | + |
| 114 | +/* Set pin's pull-up/down resistor */ |
| 115 | +static void pinmux_b91_set_pull_up(uint32_t pin, uint8_t val) |
| 116 | +{ |
| 117 | + uint8_t mask = 0; |
| 118 | + uint8_t analog_reg = reg_pull_up_en(pin); |
| 119 | + |
| 120 | + if (pin & 0x11) { |
| 121 | + val = val; |
| 122 | + mask = 0xfc; |
| 123 | + } else if (pin & 0x22) { |
| 124 | + val = val << 2; |
| 125 | + mask = 0xf3; |
| 126 | + } else if (pin & 0x44) { |
| 127 | + val = val << 4; |
| 128 | + mask = 0xcf; |
| 129 | + } else if (pin & 0x88) { |
| 130 | + val = val << 6; |
| 131 | + mask = 0x3f; |
| 132 | + } else { |
| 133 | + return; |
| 134 | + } |
| 135 | + |
| 136 | + analog_write_reg8(analog_reg, (analog_read_reg8(analog_reg) & mask) | val); |
| 137 | +} |
| 138 | + |
| 139 | +/* API implementation: init */ |
| 140 | +static int pinmux_b91_init(const struct device *dev) |
| 141 | +{ |
| 142 | + const struct pinmux_b91_config *cfg = GET_CFG(dev); |
| 143 | + |
| 144 | + reg_gpio_pad_mul_sel |= cfg->pad_mul_sel; |
| 145 | + |
| 146 | + return 0; |
| 147 | +} |
| 148 | + |
| 149 | +/* API implementation: set */ |
| 150 | +static int pinmux_b91_set(const struct device *dev, uint32_t pin, uint32_t func) |
| 151 | +{ |
| 152 | + ARG_UNUSED(dev); |
| 153 | + |
| 154 | + uint8_t mask = 0; |
| 155 | + uint8_t offset = 0; |
| 156 | + int32_t status = 0; |
| 157 | + |
| 158 | + /* calculate offset and mask for the func value */ |
| 159 | + status = pinmux_b91_get_func_offset(pin, &offset); |
| 160 | + if (status != 0) { |
| 161 | + return status; |
| 162 | + } |
| 163 | + mask = (uint8_t)~(BIT(offset) | BIT(offset + 1)); |
| 164 | + |
| 165 | + /* disable GPIO function (can be enabled back by GPIO init using GPIO driver) */ |
| 166 | + pinmux_b91_gpio_function_disable(pin); |
| 167 | + |
| 168 | + /* set func value */ |
| 169 | + reg_pin_mux(pin) = (reg_pin_mux(pin) & mask) | (func << offset); |
| 170 | + |
| 171 | + return status; |
| 172 | +} |
| 173 | + |
| 174 | +/* API implementation: get */ |
| 175 | +static int pinmux_b91_get(const struct device *dev, uint32_t pin, uint32_t *func) |
| 176 | +{ |
| 177 | + ARG_UNUSED(dev); |
| 178 | + |
| 179 | + uint8_t mask = 0u; |
| 180 | + uint8_t offset = 0; |
| 181 | + int32_t status = 0; |
| 182 | + |
| 183 | + /* calculate offset and mask for the func value */ |
| 184 | + status = pinmux_b91_get_func_offset(pin, &offset); |
| 185 | + if (status != 0) { |
| 186 | + return status; |
| 187 | + } |
| 188 | + mask = (uint8_t)(BIT(offset) | BIT(offset + 1)); |
| 189 | + |
| 190 | + /* get func value */ |
| 191 | + *func = (reg_pin_mux(pin) & mask) >> offset; |
| 192 | + |
| 193 | + return status; |
| 194 | +} |
| 195 | + |
| 196 | +/* API implementation: pullup */ |
| 197 | +static int pinmux_b91_pullup(const struct device *dev, uint32_t pin, uint8_t func) |
| 198 | +{ |
| 199 | + ARG_UNUSED(dev); |
| 200 | + |
| 201 | + switch (func) { |
| 202 | + case PINMUX_PULLUP_ENABLE: |
| 203 | + pinmux_b91_set_pull_up(pin, PINMUX_B91_PULLUP_10K); |
| 204 | + break; |
| 205 | + |
| 206 | + case PINMUX_PULLUP_DISABLE: |
| 207 | + pinmux_b91_set_pull_up(pin, PINMUX_B91_PULLUP_DISABLE); |
| 208 | + break; |
| 209 | + |
| 210 | + default: |
| 211 | + return -ENOTSUP; |
| 212 | + } |
| 213 | + |
| 214 | + return 0; |
| 215 | +} |
| 216 | + |
| 217 | +/* API implementation: input */ |
| 218 | +static int pinmux_b91_input(const struct device *dev, uint32_t pin, uint8_t func) |
| 219 | +{ |
| 220 | + ARG_UNUSED(dev); |
| 221 | + ARG_UNUSED(pin); |
| 222 | + ARG_UNUSED(func); |
| 223 | + |
| 224 | + /* Implemented by GPIO driver */ |
| 225 | + |
| 226 | + return -ENOTSUP; |
| 227 | +} |
| 228 | + |
| 229 | +/* PinMux driver APIs structure */ |
| 230 | +static const struct pinmux_driver_api pinmux_b91_api = { |
| 231 | + .set = pinmux_b91_set, |
| 232 | + .get = pinmux_b91_get, |
| 233 | + .pullup = pinmux_b91_pullup, |
| 234 | + .input = pinmux_b91_input, |
| 235 | +}; |
| 236 | + |
| 237 | +static const struct pinmux_b91_config pinmux_b91_cfg = { |
| 238 | + .pad_mul_sel = DT_INST_PROP(0, pad_mul_sel) |
| 239 | +}; |
| 240 | + |
| 241 | +/* PinMux driver registration */ |
| 242 | +DEVICE_DT_INST_DEFINE(0, pinmux_b91_init, |
| 243 | + NULL, NULL, &pinmux_b91_cfg, PRE_KERNEL_1, |
| 244 | + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, |
| 245 | + &pinmux_b91_api); |
0 commit comments