diff --git a/drivers/i2c/i2c_mchp_xec_v2.c b/drivers/i2c/i2c_mchp_xec_v2.c index c32c9b4a8ec..71744774c8e 100644 --- a/drivers/i2c/i2c_mchp_xec_v2.c +++ b/drivers/i2c/i2c_mchp_xec_v2.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -46,8 +46,8 @@ LOG_MODULE_REGISTER(i2c_mchp, CONFIG_I2C_LOG_LEVEL); #define I2C_RECOVER_SCL_DELAY_US 50 /* I2C SCL and SDA lines(signals) */ -#define I2C_LINES_SCL_HI BIT(0) -#define I2C_LINES_SDA_HI BIT(1) +#define I2C_LINES_SCL_HI BIT(SOC_I2C_SCL_POS) +#define I2C_LINES_SDA_HI BIT(SOC_I2C_SDA_POS) #define I2C_LINES_BOTH_HI (I2C_LINES_SCL_HI | I2C_LINES_SDA_HI) #define I2C_START 0U @@ -86,6 +86,7 @@ struct i2c_xec_config { uint8_t girq_pos; uint8_t pcr_idx; uint8_t pcr_bitpos; + const struct pinctrl_dev_config *pcfg; void (*irq_config_func)(void); }; @@ -132,90 +133,6 @@ static const struct xec_speed_cfg xec_cfg_params[] = { }, }; -struct xec_i2c_port { - uint8_t scl_pin; - uint8_t scl_func; - uint8_t sda_pin; - uint8_t sda_func; -}; - -/* Indexed by port number */ -static const struct xec_i2c_port xec_i2c_ports[] = { - { 0004, 1, 0003, 1 }, - { 0131, 1, 0130, 1 }, - { 0155, 1, 0154, 1 }, - { 0010, 1, 0007, 1 }, - { 0144, 1, 0143, 1 }, - { 0142, 1, 0141, 1 }, - { 0140, 1, 0132, 1 }, - { 0013, 1, 0012, 1 }, -#ifdef CONFIG_SOC_SERIES_MEC172X - { 0230, 1, 0231, 1 }, -#else - { 0212, 1, 0211, 1 }, -#endif - { 0146, 1, 0145, 1 }, - { 0107, 3, 0030, 2 }, - { 0062, 2, 0000, 3 }, - { 0027, 3, 0026, 3 }, - { 0065, 2, 0066, 2 }, - { 0071, 2, 0070, 2 }, - { 0150, 1, 0147, 1 }, -}; - -/* returns b[0]=SCL pin state, b[1]=SDA pin state */ -static uint32_t xec_i2c_port_lines(uint8_t port) -{ - uintptr_t base = (uintptr_t)XEC_GPIO_CTRL_BASE; - uint32_t lines = 0; - - if (port < ARRAY_SIZE(xec_i2c_ports)) { - const struct xec_i2c_port *p = &xec_i2c_ports[port]; - uintptr_t ctrl_addr = base + p->scl_pin * 4; - - lines = (sys_read32(ctrl_addr) >> 24) & BIT(0); - ctrl_addr = base + p->scl_pin * 4; - lines |= ((sys_read32(ctrl_addr) >> 23) & BIT(1)); - } - - return lines; -} - -#define XEC_I2C_PIN_PRE_CFG1 \ - (MCHP_GPIO_CTRL_OUTV_HI | MCHP_GPIO_CTRL_MUX_GPIO | \ - MCHP_GPIO_CTRL_DIR_OUTPUT | MCHP_GPIO_CTRL_BUFT_OPENDRAIN | \ - MCHP_GPIO_CTRL_IDET_DISABLE | MCHP_GPIO_CTRL_PUD_NONE) - -static int xec_i2c_port_cfg(uint8_t port, uint8_t enable) -{ - if (port >= ARRAY_SIZE(xec_i2c_ports)) { - return -EINVAL; - } - - const struct xec_i2c_port *p = &xec_i2c_ports[port]; - uintptr_t scl_addr = (uintptr_t)XEC_GPIO_CTRL_BASE + p->scl_pin * 4; - uintptr_t sda_addr = (uintptr_t)XEC_GPIO_CTRL_BASE + p->sda_pin * 4; - - if (enable) { - sys_write32(XEC_I2C_PIN_PRE_CFG1, sda_addr); - sys_write32(XEC_I2C_PIN_PRE_CFG1, scl_addr); - - k_busy_wait(PIN_CFG_WAIT); - - sys_write32(sys_read32(sda_addr) | - ((uint32_t)(p->sda_func) << MCHP_GPIO_CTRL_MUX_POS), - sda_addr); - sys_write32(sys_read32(scl_addr) | - ((uint32_t)(p->scl_func) << MCHP_GPIO_CTRL_MUX_POS), - scl_addr); - } else { - sys_write32(MCHP_GPIO_CTRL_DIS_PIN, scl_addr); - sys_write32(MCHP_GPIO_CTRL_DIS_PIN, sda_addr); - } - - return 0; -} - static void i2c_ctl_wr(const struct device *dev, uint8_t ctrl) { const struct i2c_xec_config *cfg = @@ -272,6 +189,11 @@ static int wait_bus_free(const struct device *dev, uint32_t nwait) /* * returns state of I2C SCL and SDA lines. * b[0] = SCL, b[1] = SDA + * Call soc specific routine to read GPIO pad input. + * Why? We can get the pins from our PINCTRL info but + * we do not know which pin is I2C clock and which pin + * is I2C data. There's no ordering in PINCTRL DT unless + * we impose an order. */ static uint32_t get_lines(const struct device *dev) { @@ -279,8 +201,11 @@ static uint32_t get_lines(const struct device *dev) (const struct i2c_xec_config *const) (dev->config); struct i2c_smb_regs *regs = (struct i2c_smb_regs *)cfg->base_addr; uint8_t port = regs->CFG & MCHP_I2C_SMB_CFG_PORT_SEL_MASK; + uint32_t lines = 0u; - return xec_i2c_port_lines(port); + soc_i2c_port_lines_get(port, &lines); + + return lines; } static int i2c_xec_reset_config(const struct device *dev) @@ -883,12 +808,10 @@ static void i2c_xec_bus_isr(void *arg) const struct i2c_slave_callbacks *target_cb = data->target_cfg->callbacks; struct i2c_smb_regs *regs = (struct i2c_smb_regs *)cfg->base_addr; - int ret; uint32_t status; uint32_t compl_status; uint8_t val; - uint8_t dummy = 0U; /* Get current status */ @@ -1127,8 +1050,9 @@ static int i2c_xec_init(const struct device *dev) data->target_cfg = NULL; data->target_attached = false; - ret = xec_i2c_port_cfg(cfg->port_sel, 1); - if (ret) { + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("XEC I2C pinctrl setup failed (%d)", ret); return ret; } @@ -1150,6 +1074,9 @@ static int i2c_xec_init(const struct device *dev) } #define I2C_XEC_DEVICE(n) \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ static void i2c_xec_irq_config_func_##n(void); \ \ static struct i2c_xec_data i2c_xec_data_##n; \ @@ -1162,6 +1089,7 @@ static int i2c_xec_init(const struct device *dev) .pcr_idx = DT_INST_PROP_BY_IDX(n, pcrs, 0), \ .pcr_bitpos = DT_INST_PROP_BY_IDX(n, pcrs, 1), \ .irq_config_func = i2c_xec_irq_config_func_##n, \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ }; \ I2C_DEVICE_DT_INST_DEFINE(n, i2c_xec_init, NULL, \ &i2c_xec_data_##n, &i2c_xec_config_##n, \ @@ -1169,7 +1097,7 @@ static int i2c_xec_init(const struct device *dev) &i2c_xec_driver_api); \ \ static void i2c_xec_irq_config_func_##n(void) \ - { \ + { \ IRQ_CONNECT(DT_INST_IRQN(n), \ DT_INST_IRQ(n, priority), \ i2c_xec_bus_isr, \ diff --git a/dts/bindings/i2c/microchip,xec-i2c-v2.yaml b/dts/bindings/i2c/microchip,xec-i2c-v2.yaml index 1934fe2dbb8..32b30fcc050 100644 --- a/dts/bindings/i2c/microchip,xec-i2c-v2.yaml +++ b/dts/bindings/i2c/microchip,xec-i2c-v2.yaml @@ -5,7 +5,7 @@ description: Microchip I2C/SMB V2 controller compatible: "microchip,xec-i2c-v2" -include: i2c-controller.yaml +include: [i2c-controller.yaml, pinctrl-device.yaml] properties: reg: @@ -26,6 +26,12 @@ properties: required: true description: PCR sleep register index and bit position + pinctrl-0: + required: true + + pinctrl-names: + required: true + "#girq-cells": type: int const: 2 diff --git a/soc/arm/microchip_mec/common/CMakeLists.txt b/soc/arm/microchip_mec/common/CMakeLists.txt index 7b4e1e885b8..d854656c9fb 100644 --- a/soc/arm/microchip_mec/common/CMakeLists.txt +++ b/soc/arm/microchip_mec/common/CMakeLists.txt @@ -1,3 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories_ifdef(CONFIG_SOC_SERIES_MEC172X .) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_MEC172X + soc_i2c.c +) diff --git a/soc/arm/microchip_mec/common/soc_i2c.c b/soc/arm/microchip_mec/common/soc_i2c.c new file mode 100644 index 00000000000..23a63fbdfa3 --- /dev/null +++ b/soc/arm/microchip_mec/common/soc_i2c.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2021 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "soc_i2c.h" + +/* pinctrl Node contains the base address of the GPIO Control Registers */ +#define MCHP_XEC_GPIO_REG_BASE ((struct gpio_regs *)DT_REG_ADDR(DT_NODELABEL(pinctrl))) + +/* Too many MEC1501 HAL bugs */ +#ifndef MEC_I2C_PORT_MASK +#define MEC_I2C_PORT_MASK 0xFFFFU +#endif + +/* encode GPIO pin number and alternate function for an I2C port */ +struct mec_i2c_port { + uint8_t scl_pin_no; + uint8_t scl_func; + uint8_t sda_pin_no; + uint8_t sda_func; +}; + +/* + * indexed by port number: all on VTR1 except as commented + * NOTE: MCHP MECxxxx data sheets specificy GPIO pin numbers in octal. + * TODO: MEC15xx and MEC172x handle ports with alternate pins. + */ +static const struct mec_i2c_port mec_i2c_ports[] = { +#if defined(CONFIG_SOC_SERIES_MEC172X) || defined(CONFIG_SOC_SERIES_MEC1501X) + { 0004, 1, 0003, 1 }, + { 0131, 1, 0130, 1 }, /* VTR2. ALT on eSPI VTR3 {0073, 2, 0072, 2} */ + { 0155, 1, 0154, 1 }, + { 0010, 1, 0007, 1 }, + { 0144, 1, 0143, 1 }, + { 0142, 1, 0141, 1 }, + { 0140, 1, 0132, 1 }, + { 0013, 1, 0012, 1 }, /* VTR2. ALT { 0024, 3, 0152, 3 } VTR1 */ +#if defined(CONFIG_SOC_SERIES_MEC172X) + { 0230, 1, 0231, 1 }, /* VTR2 176 pin only */ +#else + { 0212, 1, 0211, 1 }, /* VTR1 MEC1523 SZ and 3Y only */ +#endif + { 0146, 1, 0145, 1 }, + { 0107, 3, 0030, 2 }, + { 0062, 2, 0000, 3 }, /* SCL on VTR1, SDA on VBAT. ALT 176 pin only */ + { 0027, 3, 0026, 3 }, + { 0065, 2, 0066, 2 }, /* VTR3 */ + { 0071, 2, 0070, 2 }, /* VTR3 */ + { 0150, 1, 0147, 1 } +#elif defined(CONFIG_SOC_SERIES_MEC1701X) + { 0004, 1, 0003, 1 }, + { 0006, 1, 0005, 1 }, + { 0155, 1, 0154, 1 }, + { 0010, 1, 0007, 1 }, + { 0144, 1, 0143, 1 }, + { 0142, 1, 0141, 1 }, + { 0140, 1, 0132, 1 }, /* VTR2 */ + { 0013, 1, 0012, 1 }, /* VTR2 */ + { 0150, 1, 0147, 1 }, + { 0146, 1, 0145, 1 }, + { 0131, 1, 0130, 1 }, /* VTR2 */ + { 0xFF, 0, 0xFF, 0 }, /* No I2C Ports 11 - 15 */ + { 0xFF, 0, 0xFF, 0 }, + { 0xFF, 0, 0xFF, 0 }, + { 0xFF, 0, 0xFF, 0 }, + { 0xFF, 0, 0xFF, 0 } +#endif +}; + +/* + * Read pin states of specified I2C port. + * We GPIO control register always active RO pad input bit. + * lines b[0]=SCL pin state at pad, b[1]=SDA pin state at pad + */ +int soc_i2c_port_lines_get(uint8_t port, uint32_t *lines) +{ + struct gpio_regs *regs = MCHP_XEC_GPIO_REG_BASE; + uint32_t idx_scl = 0; + uint32_t idx_sda = 0; + uint32_t pinval = 0; + + if (!(BIT(port) & MEC_I2C_PORT_MASK) || !lines) { + return -EINVAL; + } + + idx_scl = (uint32_t)mec_i2c_ports[port].scl_pin_no; + idx_sda = (uint32_t)mec_i2c_ports[port].sda_pin_no; + + if ((idx_scl == 0xFF) || (idx_sda == 0xFF)) { + return -EINVAL; + } + + if (regs->CTRL[idx_scl] & BIT(MCHP_GPIO_CTRL_INPAD_VAL_POS)) { + pinval |= BIT(SOC_I2C_SCL_POS); + } + if (regs->CTRL[idx_sda] & BIT(MCHP_GPIO_CTRL_INPAD_VAL_POS)) { + pinval |= BIT(SOC_I2C_SDA_POS); + } + + *lines = pinval; + + return 0; +} diff --git a/soc/arm/microchip_mec/common/soc_i2c.h b/soc/arm/microchip_mec/common/soc_i2c.h new file mode 100644 index 00000000000..2398b1421bb --- /dev/null +++ b/soc/arm/microchip_mec/common/soc_i2c.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Microchip XEC MCU family I2C port support. + * + */ + +#ifndef _MICROCHIP_MEC_SOC_I2C_H_ +#define _MICROCHIP_MEC_SOC_I2C_H_ + +/* 144-pin package I2C port masks */ +#if defined(CONFIG_SOC_MEC172X_NSZ) +#define MEC_I2C_PORT_MASK 0xFEFFU +#elif defined(CONFIG_SOC_MEC1501_HSZ) +#define MEC_I2C_PORT_MASK 0xFEFFU +#elif defined(CONFIG_SOC_MEC1701_QSZ) +#define MEC_I2C_PORT_MASK 0x07FFU +#endif + +#define MCHP_I2C_PORT_0 0 +#define MCHP_I2C_PORT_1 1 +#define MCHP_I2C_PORT_2 2 +#define MCHP_I2C_PORT_3 3 +#define MCHP_I2C_PORT_4 4 +#define MCHP_I2C_PORT_5 5 +#define MCHP_I2C_PORT_6 6 +#define MCHP_I2C_PORT_7 7 +#define MCHP_I2C_PORT_8 8 +#define MCHP_I2C_PORT_9 9 +#define MCHP_I2C_PORT_10 10 +#define MCHP_I2C_PORT_11 11 +#define MCHP_I2C_PORT_12 12 +#define MCHP_I2C_PORT_13 13 +#define MCHP_I2C_PORT_14 14 +#define MCHP_I2C_PORT_15 15 +#define MCHP_I2C_PORT_MAX 16 + +/* + * Read pin states of specified I2C port. + * We GPIO control register always active RO pad input bit. + * lines b[0]=SCL pin state at pad, b[1]=SDA pin state at pad + * Returns 0 success or -EINVAL if port is not support or lines is NULL. + */ +#define SOC_I2C_SCL_POS 0 +#define SOC_I2C_SDA_POS 1 + +int soc_i2c_port_lines_get(uint8_t port, uint32_t *lines); + +#endif /* _MICROCHIP_MEC_SOC_I2C_H_ */ diff --git a/soc/arm/microchip_mec/mec172x/soc.h b/soc/arm/microchip_mec/mec172x/soc.h index d33ae1d56fb..092db77e3b9 100644 --- a/soc/arm/microchip_mec/mec172x/soc.h +++ b/soc/arm/microchip_mec/mec172x/soc.h @@ -283,6 +283,7 @@ typedef enum { #include "../common/soc_espi_channels.h" #include "../common/soc_espi_saf.h" #include "../common/soc_espi_v2.h" +#include "../common/soc_i2c.h" #endif