diff --git a/Documentation/platforms/arm/rp2040/boards/raspberrypi-pico/index.rst b/Documentation/platforms/arm/rp2040/boards/raspberrypi-pico/index.rst index 5d5636f6d740c..a1bf5c901abca 100644 --- a/Documentation/platforms/arm/rp2040/boards/raspberrypi-pico/index.rst +++ b/Documentation/platforms/arm/rp2040/boards/raspberrypi-pico/index.rst @@ -235,6 +235,53 @@ ENC28J60 SPI ethernet controller supports: * - RESET - GP10 (Pin 14) +husb238 +------- + +NuttShell configuration (console enabled in USB Port, at 115200 bps) with support for Hynetek HUSB238 USB Type-C +Power Delivery Sink Controller connected via I2C: + +.. list-table:: HUSB238 connections + :widths: auto + :header-rows: 1 + + * - HUSB238 + - Raspberry Pi Pico + * - GND + - GND (Pin 3 or 38 or ...) + * - SDA + - GP4 (I2C0 SDA) (Pin 6) + * - SCL + - GP5 (I2C0 SCL) (Pin 7) + * - Other pins as per datasheet + - N/A + +.. code-block:: console + + nsh> husb238 + --- PD Status 0 --- + Source voltage: 12V + Source current: 1.25A + + --- PD Status 1 --- + CC Direction: CC1 is connected to CC line or unattached mode + Attached: HUSB238 is in modes other than unattached mode + PD Response: Success + 5V Voltage: 5V + 5V Current: 3.0A + + --- PDOs --- + 5V: Detected (1.00A) + 9V: Detected (1.00A) + 12V: Detected (1.00A) + 15V: Detected (1.00A) + 18V: Not detected + 20V: Detected (2.25A) + + --- Selected PDO --- + Selected PDO: None + nsh> + lcd1602 ------- diff --git a/boards/arm/rp2040/common/include/rp2040_husb238.h b/boards/arm/rp2040/common/include/rp2040_husb238.h new file mode 100644 index 0000000000000..d54e6e4e1cce5 --- /dev/null +++ b/boards/arm/rp2040/common/include/rp2040_husb238.h @@ -0,0 +1,87 @@ +/**************************************************************************** + * boards/arm/rp2040/common/include/rp2040_husb238.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_RP2040_COMMON_INCLUDE_RP2040_HUSB238_H +#define __BOARDS_ARM_RP2040_COMMON_INCLUDE_RP2040_HUSB238_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Type Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_husb238_initialize + * + * Description: + * Initialize and register the HUSB238 USB-C PD sink controller. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use. + * devno - The device number, used to build the device path as /dev/usbpdN. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int board_husb238_initialize(FAR struct i2c_master_s *i2c, int devno); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __BOARDS_ARM_RP2040_COMMON_INCLUDE_RP2040_HUSB238_H */ diff --git a/boards/arm/rp2040/common/src/Make.defs b/boards/arm/rp2040/common/src/Make.defs index 187e9aa1028d1..a14b73fa9e182 100644 --- a/boards/arm/rp2040/common/src/Make.defs +++ b/boards/arm/rp2040/common/src/Make.defs @@ -117,6 +117,10 @@ ifeq ($(CONFIG_ADC_ADS7046),y) CSRCS += rp2040_ads7046.c endif +ifeq ($(CONFIG_USBPD_HUSB238),y) + CSRCS += rp2040_husb238.c +endif + DEPPATH += --dep-path src VPATH += :src CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src diff --git a/boards/arm/rp2040/common/src/rp2040_common_bringup.c b/boards/arm/rp2040/common/src/rp2040_common_bringup.c index 5393c8ace6ac1..bce10fa1e3442 100644 --- a/boards/arm/rp2040/common/src/rp2040_common_bringup.c +++ b/boards/arm/rp2040/common/src/rp2040_common_bringup.c @@ -118,6 +118,12 @@ #include "rp2040_ads7046.h" #endif +#ifdef CONFIG_USBPD_HUSB238 +#include +#include "rp2040_husb238.h" +#include "rp2040_i2c.h" +#endif + #if defined(CONFIG_RP2040_BOARD_HAS_WS2812) && defined(CONFIG_WS2812) #include "rp2040_ws2812.h" #endif @@ -797,5 +803,17 @@ int rp2040_common_bringup(void) } #endif + +#ifdef CONFIG_USBPD_HUSB238 + /* Try to register HUSB238 device at I2C0 */ + + ret = board_husb238_initialize(rp2040_i2cbus_initialize(0), 0); + + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize HUSB238 driver: %d\n", ret); + } +#endif + return ret; } diff --git a/boards/arm/rp2040/common/src/rp2040_husb238.c b/boards/arm/rp2040/common/src/rp2040_husb238.c new file mode 100644 index 0000000000000..0f09374a51fc2 --- /dev/null +++ b/boards/arm/rp2040/common/src/rp2040_husb238.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * boards/arm/rp2040/common/src/rp2040_husb238.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "rp2040_i2c.h" +#include "rp2040_husb238.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_husb238_initialize + * + * Description: + * Initialize and register the HUSB238 USB-C PD sink controller. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use. + * devno - The device number, used to build the device path as /dev/usbpdN. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int board_husb238_initialize(FAR struct i2c_master_s *i2c, int devno) +{ + char devpath[12]; + int ret; + + pwrinfo("Initializing HUSB238\n"); + + if (i2c) + { + snprintf(devpath, sizeof(devpath), "/dev/usbpd%d", devno); + ret = husb238_register(devpath, i2c); + if (ret < 0) + { + pwrerr("ERROR: Error registering HUSB238 at /dev/usbpd%d\n", + devno); + } + } + else + { + ret = -ENODEV; + } + + return ret; +} diff --git a/boards/arm/rp2040/raspberrypi-pico/configs/husb238/defconfig b/boards/arm/rp2040/raspberrypi-pico/configs/husb238/defconfig new file mode 100644 index 0000000000000..4b261eb06d851 --- /dev/null +++ b/boards/arm/rp2040/raspberrypi-pico/configs/husb238/defconfig @@ -0,0 +1,56 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_DEV_CONSOLE is not set +# CONFIG_LIBC_LONG_LONG is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_DISABLE_DATE is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +# CONFIG_RP2040_UART0 is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="raspberrypi-pico" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_RASPBERRYPI_PICO=y +CONFIG_ARCH_CHIP="rp2040" +CONFIG_ARCH_CHIP_RP2040=y +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=10450 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_CONSOLE=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_HUSB238=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_NSH_USBCONSOLE=y +CONFIG_RAM_SIZE=270336 +CONFIG_RAM_START=0x20000000 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RP2040_I2C0=y +CONFIG_RP2040_I2C=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=9 +CONFIG_START_MONTH=2 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y +CONFIG_USBPD_HUSB238=y diff --git a/drivers/power/supply/CMakeLists.txt b/drivers/power/supply/CMakeLists.txt index 35d88d20d8fc3..07c2c0020a3cd 100644 --- a/drivers/power/supply/CMakeLists.txt +++ b/drivers/power/supply/CMakeLists.txt @@ -51,4 +51,8 @@ if(CONFIG_REGULATOR) endif() +if(CONFIG_USBPD_HUSB238) + list(APPEND SRCS husb238.c) +endif() + target_sources(drivers PRIVATE ${SRCS}) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 91876e23b3875..65e03e3ecd31d 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -561,4 +561,20 @@ endif # REGULATOR_ACT8945A endif # REGULATOR +config USBPD_HUSB238 + bool "Hynetek HUSB238 USB-C PD Sink Controller support" + default n + select I2C + ---help--- + Enable driver support for the Hynetek HUSB238 USB Type-C + Power Delivery (PD) sink controller. + +if USBPD_HUSB238 + +config USBPD_HUSB238_I2C_FREQUENCY + int "HUSB238 I2C frequency" + default 400000 + +endif # USBPD_HUSB238 + endmenu diff --git a/drivers/power/supply/Make.defs b/drivers/power/supply/Make.defs index b21ff288cd6f7..6a4a1f0c142d0 100644 --- a/drivers/power/supply/Make.defs +++ b/drivers/power/supply/Make.defs @@ -43,6 +43,10 @@ ifeq ($(CONFIG_REGULATOR_ACT8945A), y) CSRCS += act8945a.c endif +endif # CONFIG_REGULATOR + +ifeq ($(CONFIG_USBPD_HUSB238), y) +CSRCS += husb238.c endif DEPPATH += --dep-path power/supply diff --git a/drivers/power/supply/husb238.c b/drivers/power/supply/husb238.c new file mode 100644 index 0000000000000..9787e171f919d --- /dev/null +++ b/drivers/power/supply/husb238.c @@ -0,0 +1,467 @@ +/**************************************************************************** + * drivers/power/supply/husb238.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define HUSB238_REG_PD_STATUS0 0x00 +#define HUSB238_REG_PD_STATUS1 0x01 +#define HUSB238_REG_SRC_PDO_5V 0x02 +#define HUSB238_REG_SRC_PDO_9V 0x03 +#define HUSB238_REG_SRC_PDO_12V 0x04 +#define HUSB238_REG_SRC_PDO_15V 0x05 +#define HUSB238_REG_SRC_PDO_18V 0x06 +#define HUSB238_REG_SRC_PDO_20V 0x07 +#define HUSB238_REG_SRC_PDO 0x08 +#define HUSB238_REG_GO_COMMAND 0x09 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct husb238_dev_s +{ + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* HUSB238 I2C address */ + int freq; /* HUSB238 Frequency */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int husb238_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_husb238fops = +{ + NULL, /* open */ + NULL, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + husb238_ioctl /* ioctl */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int husb238_getreg8(FAR struct husb238_dev_s *priv, uint8_t regaddr) +{ + struct i2c_config_s config; + uint8_t regval = 0; + int ret; + + /* Set up the I2C configuration */ + + config.frequency = priv->freq; + config.address = priv->addr; + config.addrlen = 7; + + /* Register to read */ + + ret = i2c_write(priv->i2c, &config, ®addr, 1); + if (ret < 0) + { + pwrerr("ERROR: i2c_write failed: %s (%d)\n", strerror(-ret), ret); + return ret; + } + + /* Read register */ + + ret = i2c_read(priv->i2c, &config, (FAR uint8_t *)®val, 1); + if (ret < 0) + { + pwrerr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + return regval; +} + +static int husb238_putreg8(FAR struct husb238_dev_s *priv, uint8_t regaddr, + uint8_t regval) +{ + struct i2c_config_s config; + uint8_t data[2]; + int ret; + + /* Set up the I2C configuration */ + + config.frequency = priv->freq; + config.address = priv->addr; + config.addrlen = 7; + + data[0] = regaddr; + data[1] = regval; + + /* Write the register address and value */ + + ret = i2c_write(priv->i2c, &config, (FAR uint8_t *)&data, 2); + if (ret < 0) + { + pwrerr("ERROR: i2c_write failed: %s (%d)\n", strerror(-ret), ret); + return ret; + } + + return OK; +} + +static int husb238_get_pdstatus_0(FAR struct husb238_dev_s *priv, + FAR struct husb238_pdstatus_0_s *status) +{ + int ret; + uint8_t regval; + + ret = husb238_getreg8(priv, HUSB238_REG_PD_STATUS0); + if (ret < 0) + { + return ret; + } + + regval = ret; + status->src_voltage = (regval >> 4) & 0x0f; + status->src_current = regval & 0x0f; + + return OK; +} + +static int husb238_get_pdstatus_1(FAR struct husb238_dev_s *priv, + FAR struct husb238_pdstatus_1_s *status) +{ + int ret; + uint8_t regval; + + ret = husb238_getreg8(priv, HUSB238_REG_PD_STATUS1); + if (ret < 0) + { + return ret; + } + + regval = ret; + status->cc_dir = (regval >> 7) & 0x1; + status->attached = (regval >> 6) & 0x1; + status->pd_response = (regval >> 3) & 0x7; + status->voltage_5v = (regval >> 2) & 0x1; + status->current_5v = regval & 0x3; + + return OK; +} + +static int husb238_get_src_pdos(FAR struct husb238_dev_s *priv, + FAR struct husb238_src_pdos_s *pdos) +{ + int ret; + uint8_t pdo; + + /* Read the SRC_PDO_5V register */ + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO_5V); + if (ret < 0) + { + return ret; + } + + pdo = ret; + pdos->detected_5v = (pdo >> 7) & 0x1; + pdos->current_5v = pdo & 0x7; + + /* Read the SRC_PDO_9V register */ + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO_9V); + if (ret < 0) + { + return ret; + } + + pdo = ret; + pdos->detected_9v = (pdo >> 7) & 0x1; + pdos->current_9v = pdo & 0x7; + + /* Read the SRC_PDO_12V register */ + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO_12V); + if (ret < 0) + { + return ret; + } + + pdo = ret; + pdos->detected_12v = (pdo >> 7) & 0x1; + pdos->current_12v = pdo & 0x7; + + /* Read the SRC_PDO_15V register */ + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO_15V); + if (ret < 0) + { + return ret; + } + + pdo = ret; + pdos->detected_15v = (pdo >> 7) & 0x1; + pdos->current_15v = pdo & 0x7; + + /* Read the SRC_PDO_18V register */ + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO_18V); + if (ret < 0) + { + return ret; + } + + pdo = ret; + pdos->detected_18v = (pdo >> 7) & 0x1; + pdos->current_18v = pdo & 0x7; + + /* Read the SRC_PDO_20V register */ + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO_20V); + if (ret < 0) + { + return ret; + } + + pdo = ret; + pdos->detected_20v = (pdo >> 7) & 0x1; + pdos->current_20v = pdo & 0x7; + + return OK; +} + +static int husb238_get_selected_pdo(FAR struct husb238_dev_s *priv, + uint8_t *pdo) +{ + int ret; + + ret = husb238_getreg8(priv, HUSB238_REG_SRC_PDO); + if (ret < 0) + { + return ret; + } + + *pdo = (ret >> 4) & 0x0f; + + return OK; +} + +static int husb238_set_selected_pdo(FAR struct husb238_dev_s *priv, + uint8_t pdo_select) +{ + int ret; + + if (pdo_select != HUSB238_SRC_PDO_NONE && + pdo_select != HUSB238_SRC_PDO_5V && + pdo_select != HUSB238_SRC_PDO_9V && + pdo_select != HUSB238_SRC_PDO_12V && + pdo_select != HUSB238_SRC_PDO_15V && + pdo_select != HUSB238_SRC_PDO_18V && + pdo_select != HUSB238_SRC_PDO_20V) + { + syslog(LOG_ERR, "Unsupported PDO_SELECT specified\n"); + return -EINVAL; + } + + ret = husb238_putreg8(priv, HUSB238_REG_SRC_PDO, pdo_select << 4); + if (ret < 0) + { + return ret; + } + + return ret; +} + +static int husb238_send_command(FAR struct husb238_dev_s *priv, + uint8_t command) +{ + int ret; + + if (command != HUSB238_CMD_REQUEST_PDO && + command != HUSB238_CMD_SEND_GETSRCCAP && + command != HUSB238_CMD_SEND_HARDRESET) + { + syslog(LOG_ERR, "Unsupported command specified\n"); + return -EINVAL; + } + + ret = husb238_putreg8(priv, HUSB238_REG_GO_COMMAND, command); + if (ret < 0) + { + return ret; + } + + return OK; +} + +static int husb238_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct husb238_dev_s *priv = inode->i_private; + + int ret = OK; + + switch (cmd) + { + /* Read and parse the contents of the PD_STATUS0 register */ + + case PWRIOC_HUSB238_GET_PDSTATUS_0: + { + FAR struct husb238_pdstatus_0_s *pdstatus_0 = + (FAR struct husb238_pdstatus_0_s *)((uintptr_t)arg); + ret = husb238_get_pdstatus_0(priv, pdstatus_0); + break; + } + + /* Read and parse the contents of the PD_STATUS1 register */ + + case PWRIOC_HUSB238_GET_PDSTATUS_1: + { + FAR struct husb238_pdstatus_1_s *pdstatus_1 = + (FAR struct husb238_pdstatus_1_s *)((uintptr_t)arg); + ret = husb238_get_pdstatus_1(priv, pdstatus_1); + break; + } + + /* Read and parse the contents of all the SRC_PDO_* registers */ + + case PWRIOC_HUSB238_GET_SRC_PDOS: + { + FAR struct husb238_src_pdos_s *src_pdos = + (FAR struct husb238_src_pdos_s *)((uintptr_t)arg); + ret = husb238_get_src_pdos(priv, src_pdos); + break; + } + + /* Read and parse the contents of the SRC_PDO register */ + + case PWRIOC_HUSB238_GET_SELECTED_PDO: + { + FAR uint8_t *pdo = (FAR uint8_t *)((uintptr_t)arg); + ret = husb238_get_selected_pdo(priv, pdo); + break; + } + + /* Write the contents of the SRC_PDO register */ + + case PWRIOC_HUSB238_SET_SELECTED_PDO: + { + FAR uint8_t *pdo = (FAR uint8_t *)((uintptr_t)arg); + ret = husb238_set_selected_pdo(priv, *pdo); + break; + } + + /* Write the contents of the GO_COMMAND register */ + + case PWRIOC_HUSB238_SEND_COMMAND: + { + FAR uint8_t *command = (FAR uint8_t *)((uintptr_t)arg); + ret = husb238_send_command(priv, *command); + break; + } + + /* Command was not recognized */ + + default: + { + pwrerr("ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: husb238_register + * + * Description: + * Register the HUSB238 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/usbpd0" + * i2c - An instance of the I2C interface to use. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int husb238_register(FAR const char *devpath, FAR struct i2c_master_s *i2c) +{ + FAR struct husb238_dev_s *priv; + int ret; + + /* Initialize the HUSB238 device structure */ + + priv = kmm_malloc(sizeof(struct husb238_dev_s)); + if (priv == NULL) + { + pwrerr("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = 0x08; + priv->freq = CONFIG_USBPD_HUSB238_I2C_FREQUENCY; + + /* Register the character driver */ + + ret = register_driver(devpath, &g_husb238fops, 0666, priv); + if (ret < 0) + { + pwrerr("ERROR: Failed to register driver: %d\n", ret); + kmm_free(priv); + } + + return ret; +} diff --git a/include/nuttx/power/husb238.h b/include/nuttx/power/husb238.h new file mode 100644 index 0000000000000..d8c208c6a3bfc --- /dev/null +++ b/include/nuttx/power/husb238.h @@ -0,0 +1,216 @@ +/**************************************************************************** + * include/nuttx/power/husb238.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_POWER_HUSB238_H +#define __INCLUDE_NUTTX_POWER_HUSB238_H + +#if defined(CONFIG_I2C) && defined(CONFIG_USBPD_HUSB238) + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Values for the PD_STATUS0 register ***************************************/ + +/* The voltage information when an explicit contract is established */ + +#define HUSB238_PD_SRC_VOLTAGE_UNATTACHED 0b0000 /* Unattached */ +#define HUSB238_PD_SRC_VOLTAGE_5V 0b0001 /* PD 5V */ +#define HUSB238_PD_SRC_VOLTAGE_9V 0b0010 /* PD 9V */ +#define HUSB238_PD_SRC_VOLTAGE_12V 0b0011 /* PD 12V */ +#define HUSB238_PD_SRC_VOLTAGE_15V 0b0100 /* PD 15V */ +#define HUSB238_PD_SRC_VOLTAGE_18V 0b0101 /* PD 18V */ +#define HUSB238_PD_SRC_VOLTAGE_20V 0b0110 /* PD 20V */ + +/* The current information when an explicit contract is established */ + +/* (See HUSB238_CURRENT_* macros) */ + +/* Values for the PD_STATUS1 register ***************************************/ + +#define HUSB238_CC_DIR_CC1_CONNECTED 0 /* CC1 is connected to CC line or unattached mode */ +#define HUSB238_CC_DIR_CC2_CONNECTED 1 /* CC2 is connected to CC line */ +#define HUSB238_ATTACH_UNATTACHED 0 /* CC1 is connected to CC line or unattached mode */ +#define HUSB238_ATTACH_ATTACHED 1 /* HUSB238 is in modes other than unattached mode */ +#define HUSB238_PD_RESPONSE_NONE 0b000 /* No response */ +#define HUSB238_PD_RESPONSE_SUCCESS 0b001 /* Success */ +#define HUSB238_PD_RESPONSE_INVALID_CMD 0b011 /* Invalid command or argument */ +#define HUSB238_PD_RESPONSE_UNSUPPORTED 0b100 /* Command not supported */ +#define HUSB238_PD_RESPONSE_FAIL 0b101 /* Transaction fail (no GoodCRC is received after sending) */ + +/* Voltage information of 5V contract */ + +#define HUSB238_5V_CONTRACT_VOLTAGE_OTHERS 0 /* Others */ +#define HUSB238_5V_CONTRACT_VOLTAGE_5V 1 /* 5V */ + +/* Current information of 5V contract */ + +#define HUSB238_5V_CONTRACT_CURRENT_DEFAULT 0b00 /* Default current */ +#define HUSB238_5V_CONTRACT_CURRENT_1_5A 0b01 /* 1.5A */ +#define HUSB238_5V_CONTRACT_CURRENT_2_4A 0b10 /* 2.4A */ +#define HUSB238_5V_CONTRACT_CURRENT_3A 0b11 /* 3A */ + +/* Values for the SRC_PDO_* register ****************************************/ + +#define HUSB238_VOLTAGE_NOT_DETECTED 0 /* Not detected */ +#define HUSB238_VOLTAGE_DETECTED 1 /* Detected */ + +/* Common current values */ + +#define HUSB238_CURRENT_0_5A 0b0000 /* 0.50A */ +#define HUSB238_CURRENT_0_7A 0b0001 /* 0.70A */ +#define HUSB238_CURRENT_1A 0b0010 /* 1.00A */ +#define HUSB238_CURRENT_1_25A 0b0011 /* 1.25A */ +#define HUSB238_CURRENT_1_5A 0b0100 /* 1.50A */ +#define HUSB238_CURRENT_1_75A 0b0101 /* 1.75A */ +#define HUSB238_CURRENT_2A 0b0110 /* 2.00A */ +#define HUSB238_CURRENT_2_25A 0b0111 /* 2.25A */ +#define HUSB238_CURRENT_2_5A 0b1000 /* 2.50A */ +#define HUSB238_CURRENT_2_75A 0b1001 /* 2.75A */ +#define HUSB238_CURRENT_3A 0b1010 /* 3.00A */ +#define HUSB238_CURRENT_3_25A 0b1011 /* 3.25A */ +#define HUSB238_CURRENT_3_5A 0b1100 /* 3.50A */ +#define HUSB238_CURRENT_4A 0b1101 /* 4.00A */ +#define HUSB238_CURRENT_4_5A 0b1110 /* 4.50A */ +#define HUSB238_CURRENT_5A 0b1111 /* 5.00A */ + +/* Values for the SRC_PDO register ******************************************/ + +#define HUSB238_SRC_PDO_NONE 0b0000 /* Not selected */ +#define HUSB238_SRC_PDO_5V 0b0001 /* SRC_PDO_5V */ +#define HUSB238_SRC_PDO_9V 0b0010 /* SRC_PDO_9V */ +#define HUSB238_SRC_PDO_12V 0b0011 /* SRC_PDO_12V */ +#define HUSB238_SRC_PDO_15V 0b1000 /* SRC_PDO_15V */ +#define HUSB238_SRC_PDO_18V 0b1001 /* SRC_PDO_18V */ +#define HUSB238_SRC_PDO_20V 0b1010 /* SRC_PDO_20V */ + +/* Values for the GO_CIMMAND register ***************************************/ + +#define HUSB238_CMD_REQUEST_PDO 0b00001 /* Requests the PDO set by PDO_SELECT */ +#define HUSB238_CMD_SEND_GETSRCCAP 0b00100 /* Send out Get_SRC_Cap command */ +#define HUSB238_CMD_SEND_HARDRESET 0b10000 /* Send out hard reset command */ + +/* IOCTL Commands ***********************************************************/ + +/* Cmd: PWRIOC_HUSB238_GET_SELECTED_PDO + * Arg: uint8_t *pdo_select (See HUSB238_SRC_PDO_* macros) + * + * Cmd: PWRIOC_HUSB238_SET_SELECTED_PDO + * Arg: uint8_t *pdo_select (See HUSB238_SRC_PDO_* macros) + * + * Cmd: PWRIOC_HUSB238_GET_PDSTATUS_0 + * Arg: husb238_pdstatus_0_s *pdstatus_0 + * + * Cmd: PWRIOC_HUSB238_GET_PDSTATUS_1 + * Arg: husb238_pdstatus_1_s *pdstatus_1 + * + * Cmd: PWRIOC_HUSB238_GET_SRC_PDOS + * Arg: husb238_pdos_s *src_pdos + * + * Cmd: PWRIOC_HUSB238_SEND_COMMAND + * Arg: uint8_t *command (See HUSB238_CMD_* macros) + */ + +#define PWRIOC_HUSB238_GET_PDSTATUS_0 _PWRIOC(PWR_HUSB238_FIRST + 1) +#define PWRIOC_HUSB238_GET_PDSTATUS_1 _PWRIOC(PWR_HUSB238_FIRST + 2) +#define PWRIOC_HUSB238_GET_SRC_PDOS _PWRIOC(PWR_HUSB238_FIRST + 3) +#define PWRIOC_HUSB238_GET_SELECTED_PDO _PWRIOC(PWR_HUSB238_FIRST + 4) +#define PWRIOC_HUSB238_SET_SELECTED_PDO _PWRIOC(PWR_HUSB238_FIRST + 5) +#define PWRIOC_HUSB238_SEND_COMMAND _PWRIOC(PWR_HUSB238_FIRST + 6) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct husb238_pdstatus_0_s + { + uint8_t src_voltage; /* See HUSB238_PD_SRC_VOLTAGE_* macros */ + uint8_t src_current; /* See HUSB238_CURRENT_* macros */ + }; + +struct husb238_pdstatus_1_s + { + uint8_t cc_dir; /* See HUSB238_CC_DIR_CC* macros */ + uint8_t attached; /* See HUSB238_ATTACH_* macros */ + uint8_t pd_response; /* See HUSB238_PD_RESPONSE_* macros */ + uint8_t voltage_5v; /* See HUSB238_5V_CONTRACT_VOLTAGE_* macros */ + uint8_t current_5v; /* See HUSB238_5V_CONTRACT_CURRENT_* macros */ + }; +struct husb238_src_pdos_s + { + uint8_t detected_5v; /* See HUSB238_VOLTAGE_* macros */ + uint8_t current_5v; /* See HUSB238_CURRENT_* macros */ + uint8_t detected_9v; /* See HUSB238_VOLTAGE_* macros */ + uint8_t current_9v; /* See HUSB238_CURRENT_* macros */ + uint8_t detected_12v; /* See HUSB238_VOLTAGE_* macros */ + uint8_t current_12v; /* See HUSB238_CURRENT_* macros */ + uint8_t detected_15v; /* See HUSB238_VOLTAGE_* macros */ + uint8_t current_15v; /* See HUSB238_CURRENT_* macros */ + uint8_t detected_18v; /* See HUSB238_VOLTAGE_* macros */ + uint8_t current_18v; /* See HUSB238_CURRENT_* macros */ + uint8_t detected_20v; /* See HUSB238_VOLTAGE_* macros */ + uint8_t current_20v; /* See HUSB238_CURRENT_* macros */ + }; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: husb238_register + * + * Description: + * Register the HUSB238 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/usbpd0" + * i2c - An instance of the I2C interface to use. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int husb238_register(FAR const char *devpath, FAR struct i2c_master_s *i2c); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_USBPD_HUSB238 */ +#endif /* __INCLUDE_NUTTX_POWER_HUSB238_H */ diff --git a/include/nuttx/power/power_ioctl.h b/include/nuttx/power/power_ioctl.h index 62c03fef3496d..aaa26e335c2da 100644 --- a/include/nuttx/power/power_ioctl.h +++ b/include/nuttx/power/power_ioctl.h @@ -39,6 +39,12 @@ * aliased. */ +/* The power driver sub-system uses the standard character driver framework. + * However, since the driver is a devices control interface rather than a + * data transfer interface, the majority of the functionality is implemented + * in driver ioctl calls. Standard ioctl commands are listed below: + */ + #define PWRIOC_START _PWRIOC(1) #define PWRIOC_STOP _PWRIOC(2) #define PWRIOC_SET_MODE _PWRIOC(3) @@ -50,4 +56,19 @@ #define PWRIOC_CLEAN_FAULT _PWRIOC(9) #define PWRIOC_SET_PARAMS _PWRIOC(10) +#define PWR_FIRST 0x0001 /* First common command */ +#define PWR_NCMDS 10 /* Number of common commands */ + +/* User defined ioctl commands are also supported. These will be forwarded + * by the upper-half driver to the lower-half driver via the ioctl() + * method of the lower-half interface. However, the lower-half driver + * must reserve a block of commands as follows in order prevent IOCTL + * command numbers from overlapping. + */ + +/* See include/nuttx/power/husb238.h */ + +#define PWR_HUSB238_FIRST (PWR_FIRST + PWR_NCMDS) +#define PWS_HUSB238_NCMDS 6 + #endif /* __INCLUDE_NUTTX_POWER_POWER_IOCTL_H */