246 lines
5.8 KiB
C
246 lines
5.8 KiB
C
|
/*
|
||
|
* Copyright (c) 2021 Telink Semiconductor
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*/
|
||
|
|
||
|
#define DT_DRV_COMPAT telink_b91_pinmux
|
||
|
|
||
|
#include "analog.h"
|
||
|
#include <drivers/pinmux.h>
|
||
|
|
||
|
|
||
|
/**
|
||
|
* 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)))
|
||
|
|
||
|
/* GPIO Pull-Up options */
|
||
|
#define PINMUX_B91_PULLUP_DISABLE ((uint8_t)0u)
|
||
|
#define PINMUX_B91_PULLUP_10K ((uint8_t)3u)
|
||
|
|
||
|
/* Get PinMux configuration */
|
||
|
#define GET_CFG(dev) ((const struct pinmux_b91_config *)dev->config)
|
||
|
|
||
|
|
||
|
/* B91 PinMux config structure */
|
||
|
struct pinmux_b91_config {
|
||
|
uint8_t pad_mul_sel;
|
||
|
};
|
||
|
|
||
|
|
||
|
/* Act as GPIO function disable */
|
||
|
static inline void pinmux_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 pinmux_b91_get_func_offset(uint32_t pin, uint8_t *offset)
|
||
|
{
|
||
|
switch ((pin & 0x0fu) != 0u ? pin & 0x0fu : (pin & 0xf0u) >> 4u) {
|
||
|
case BIT(0):
|
||
|
*offset = 0u;
|
||
|
break;
|
||
|
case BIT(1):
|
||
|
*offset = 2u;
|
||
|
break;
|
||
|
case BIT(2):
|
||
|
*offset = 4u;
|
||
|
break;
|
||
|
case BIT(3):
|
||
|
*offset = 6u;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Set pin's pull-up/down resistor */
|
||
|
static void pinmux_b91_set_pull_up(uint32_t pin, uint8_t val)
|
||
|
{
|
||
|
uint8_t mask = 0;
|
||
|
uint8_t analog_reg = reg_pull_up_en(pin);
|
||
|
|
||
|
if (pin & 0x11) {
|
||
|
val = val;
|
||
|
mask = 0xfc;
|
||
|
} else if (pin & 0x22) {
|
||
|
val = val << 2;
|
||
|
mask = 0xf3;
|
||
|
} else if (pin & 0x44) {
|
||
|
val = val << 4;
|
||
|
mask = 0xcf;
|
||
|
} else if (pin & 0x88) {
|
||
|
val = val << 6;
|
||
|
mask = 0x3f;
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
analog_write_reg8(analog_reg, (analog_read_reg8(analog_reg) & mask) | val);
|
||
|
}
|
||
|
|
||
|
/* API implementation: init */
|
||
|
static int pinmux_b91_init(const struct device *dev)
|
||
|
{
|
||
|
const struct pinmux_b91_config *cfg = GET_CFG(dev);
|
||
|
|
||
|
reg_gpio_pad_mul_sel |= cfg->pad_mul_sel;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* API implementation: set */
|
||
|
static int pinmux_b91_set(const struct device *dev, uint32_t pin, uint32_t func)
|
||
|
{
|
||
|
ARG_UNUSED(dev);
|
||
|
|
||
|
uint8_t mask = 0;
|
||
|
uint8_t offset = 0;
|
||
|
int32_t status = 0;
|
||
|
|
||
|
/* calculate offset and mask for the func value */
|
||
|
status = pinmux_b91_get_func_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) */
|
||
|
pinmux_b91_gpio_function_disable(pin);
|
||
|
|
||
|
/* set func value */
|
||
|
reg_pin_mux(pin) = (reg_pin_mux(pin) & mask) | (func << offset);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/* API implementation: get */
|
||
|
static int pinmux_b91_get(const struct device *dev, uint32_t pin, uint32_t *func)
|
||
|
{
|
||
|
ARG_UNUSED(dev);
|
||
|
|
||
|
uint8_t mask = 0u;
|
||
|
uint8_t offset = 0;
|
||
|
int32_t status = 0;
|
||
|
|
||
|
/* calculate offset and mask for the func value */
|
||
|
status = pinmux_b91_get_func_offset(pin, &offset);
|
||
|
if (status != 0) {
|
||
|
return status;
|
||
|
}
|
||
|
mask = (uint8_t)(BIT(offset) | BIT(offset + 1));
|
||
|
|
||
|
/* get func value */
|
||
|
*func = (reg_pin_mux(pin) & mask) >> offset;
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/* API implementation: pullup */
|
||
|
static int pinmux_b91_pullup(const struct device *dev, uint32_t pin, uint8_t func)
|
||
|
{
|
||
|
ARG_UNUSED(dev);
|
||
|
|
||
|
switch (func) {
|
||
|
case PINMUX_PULLUP_ENABLE:
|
||
|
pinmux_b91_set_pull_up(pin, PINMUX_B91_PULLUP_10K);
|
||
|
break;
|
||
|
|
||
|
case PINMUX_PULLUP_DISABLE:
|
||
|
pinmux_b91_set_pull_up(pin, PINMUX_B91_PULLUP_DISABLE);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return -ENOTSUP;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* API implementation: input */
|
||
|
static int pinmux_b91_input(const struct device *dev, uint32_t pin, uint8_t func)
|
||
|
{
|
||
|
ARG_UNUSED(dev);
|
||
|
ARG_UNUSED(pin);
|
||
|
ARG_UNUSED(func);
|
||
|
|
||
|
/* Implemented by GPIO driver */
|
||
|
|
||
|
return -ENOTSUP;
|
||
|
}
|
||
|
|
||
|
/* PinMux driver APIs structure */
|
||
|
static const struct pinmux_driver_api pinmux_b91_api = {
|
||
|
.set = pinmux_b91_set,
|
||
|
.get = pinmux_b91_get,
|
||
|
.pullup = pinmux_b91_pullup,
|
||
|
.input = pinmux_b91_input,
|
||
|
};
|
||
|
|
||
|
static const struct pinmux_b91_config pinmux_b91_cfg = {
|
||
|
.pad_mul_sel = DT_INST_PROP(0, pad_mul_sel)
|
||
|
};
|
||
|
|
||
|
/* PinMux driver registration */
|
||
|
DEVICE_DT_INST_DEFINE(0, pinmux_b91_init,
|
||
|
NULL, NULL, &pinmux_b91_cfg, PRE_KERNEL_1,
|
||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||
|
&pinmux_b91_api);
|