bc12: API and 1st driver implementation.

Add portable-device mode to the Diodes PI3USB9201 USB charging detector.

Signed-off-by: Keith Short <keithshort@google.com>
This commit is contained in:
Keith Short 2022-12-06 10:53:16 -07:00 committed by Anas Nashif
parent 443986159e
commit e0dd45ba31
11 changed files with 733 additions and 0 deletions

View file

@ -3,4 +3,5 @@
add_subdirectory_ifdef(CONFIG_UDC_DRIVER udc)
add_subdirectory_ifdef(CONFIG_UHC_DRIVER uhc)
add_subdirectory_ifdef(CONFIG_UVB uvb)
add_subdirectory_ifdef(CONFIG_USB_BC12 bc12)
add_subdirectory_ifdef(CONFIG_USB_DEVICE_DRIVER device)

View file

@ -3,6 +3,7 @@
# Copyright (c) 2016 Wind River Systems, Inc.
# SPDX-License-Identifier: Apache-2.0
source "drivers/usb/bc12/Kconfig"
source "drivers/usb/udc/Kconfig"
source "drivers/usb/uhc/Kconfig"
source "drivers/usb/uvb/Kconfig"

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_USB_BC12_PI3USB9201 bc12_pi3usb9201.c)

17
drivers/usb/bc12/Kconfig Normal file
View file

@ -0,0 +1,17 @@
# Copyright (c) 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
menuconfig USB_BC12
bool "USB BC1.2 Drivers"
help
Enable USB BC1.2 (battery charging detection) drivers.
if USB_BC12
module = USB_BC12
module-str = usb_bc12
source "subsys/logging/Kconfig.template.log_config"
source "drivers/usb/bc12/Kconfig.pi3usb9201"
endif # USB_BC12

View file

@ -0,0 +1,14 @@
# Copyright (c) 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
config USB_BC12_PI3USB9201
bool "Diodes PI3USB9201"
default y
depends on DT_HAS_DIODES_PI3USB9201_ENABLED
help
This is a Dual-Role USB Charging-Type Detector. It can operate in
host or client mode. It supports Battery Charging Specification, rev
1.2 (BC1.2) with Standard/Charging/Dedicated downstream port
(SDP/CDP/DCP) advertisement when in host mode. In portable device or
client mode it starts BC1.2 detection to detect the attached host
type. It provides an I2C interface to report detection results.

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/usb/usb_bc12.h>
#include <zephyr/syscall_handler.h>
static inline int z_vrfy_bc12_set_role(const struct device *dev, enum bc12_role role)
{
Z_OOPS(Z_SYSCALL_DRIVER_BC12(dev, set_role));
return z_impl_bc12_set_role(dev, role);
}
static inline int z_vrfy_bc12_set_result_cb(const struct device *dev, bc12_callback_t cb,
void *user_data)
{
Z_OOPS(Z_SYSCALL_DRIVER_BC12(dev, set_result_cb));
Z_OOPS(Z_SYSCALL_VERIFY_MSG(cb == NULL, "callbacks may not be set from user mode"));
return z_impl_bc12_set_result_cb(dev, cb, user_data);
}

View file

@ -0,0 +1,432 @@
/*
* Copyright (c) 2022 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
/* PI3USB9201 USB BC 1.2 Charger Detector driver. */
#define DT_DRV_COMPAT diodes_pi3usb9201
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/usb/usb_bc12.h>
#include <zephyr/logging/log.h>
#include "bc12_pi3usb9201.h"
LOG_MODULE_REGISTER(PI3USB9201, CONFIG_USB_BC12_LOG_LEVEL);
/* Constant configuration data */
struct pi3usb9201_config {
struct i2c_dt_spec i2c;
struct gpio_dt_spec intb_gpio;
enum bc12_type charging_mode;
};
/* Run-time configuration data */
struct pi3usb9201_data {
const struct device *dev;
struct k_work work;
enum bc12_type partner_type;
struct gpio_callback gpio_cb;
bc12_callback_t result_cb;
void *result_cb_data;
};
enum pi3usb9201_client_sts {
CHG_OTHER = 0,
CHG_2_4A = 1,
CHG_2_0A = 2,
CHG_1_0A = 3,
CHG_RESERVED = 4,
CHG_CDP = 5,
CHG_SDP = 6,
CHG_DCP = 7,
};
struct bc12_status {
enum bc12_type partner_type;
int current_limit;
};
/*
* The USB Type-C specification limits the maximum amount of current from BC 1.2
* suppliers to 1.5A. Technically, proprietary methods are not allowed, but we
* will continue to allow those.
*/
static const struct bc12_status bc12_chg_limits[] = {
/* For unknown chargers return Isusp. */
[CHG_OTHER] = {BC12_TYPE_PROPRIETARY, BC12_CURR_UA(BC12_CHARGER_MIN_CURR_UA)},
[CHG_2_4A] = {BC12_TYPE_PROPRIETARY, BC12_CURR_UA(2400000)},
[CHG_2_0A] = {BC12_TYPE_PROPRIETARY, BC12_CURR_UA(2000000)},
[CHG_1_0A] = {BC12_TYPE_PROPRIETARY, BC12_CURR_UA(1000000)},
[CHG_RESERVED] = {BC12_TYPE_NONE, 0},
[CHG_CDP] = {BC12_TYPE_CDP, BC12_CURR_UA(1500000)},
/* BC1.2 driver contract specifies to return Isusp for SDP ports. */
[CHG_SDP] = {BC12_TYPE_SDP, BC12_CURR_UA(BC12_CHARGER_MIN_CURR_UA)},
[CHG_DCP] = {BC12_TYPE_DCP, BC12_CURR_UA(1500000)},
};
static int pi3usb9201_interrupt_enable(const struct device *dev, const bool enable)
{
const struct pi3usb9201_config *cfg = dev->config;
/* Clear the interrupt mask bit to enable the interrupt */
return i2c_reg_update_byte_dt(&cfg->i2c, PI3USB9201_REG_CTRL_1,
PI3USB9201_REG_CTRL_1_INT_MASK,
enable ? 0 : PI3USB9201_REG_CTRL_1_INT_MASK);
}
static int pi3usb9201_bc12_detect_ctrl(const struct device *dev, const bool enable)
{
const struct pi3usb9201_config *cfg = dev->config;
return i2c_reg_update_byte_dt(&cfg->i2c, PI3USB9201_REG_CTRL_2,
PI3USB9201_REG_CTRL_2_START_DET,
enable ? PI3USB9201_REG_CTRL_2_START_DET : 0);
}
static int pi3usb9201_bc12_usb_switch(const struct device *dev, bool enable)
{
const struct pi3usb9201_config *cfg = dev->config;
/* USB data switch enabled when PI3USB9201_REG_CTRL_2_AUTO_SW is clear */
return i2c_reg_update_byte_dt(&cfg->i2c, PI3USB9201_REG_CTRL_2,
PI3USB9201_REG_CTRL_2_START_DET,
enable ? 0 : PI3USB9201_REG_CTRL_2_AUTO_SW);
}
static int pi3usb9201_set_mode(const struct device *dev, enum pi3usb9201_mode mode)
{
const struct pi3usb9201_config *cfg = dev->config;
return i2c_reg_update_byte_dt(&cfg->i2c, PI3USB9201_REG_CTRL_1,
PI3USB9201_REG_CTRL_1_MODE_MASK
<< PI3USB9201_REG_CTRL_1_MODE_SHIFT,
mode << PI3USB9201_REG_CTRL_1_MODE_SHIFT);
}
static int pi3usb9201_get_status(const struct device *dev, uint8_t *const client,
uint8_t *const host)
{
const struct pi3usb9201_config *cfg = dev->config;
uint8_t status;
int rv;
rv = i2c_reg_read_byte_dt(&cfg->i2c, PI3USB9201_REG_CLIENT_STS, &status);
if (rv < 0) {
return rv;
}
if (client != NULL) {
*client = status;
}
rv = i2c_reg_read_byte_dt(&cfg->i2c, PI3USB9201_REG_HOST_STS, &status);
if (rv < 0) {
return rv;
}
if (host != NULL) {
*host = status;
}
return 0;
}
static void pi3usb9201_notify_callback(const struct device *dev,
struct bc12_partner_state *const state)
{
struct pi3usb9201_data *pi3usb9201_data = dev->data;
if (pi3usb9201_data->result_cb) {
pi3usb9201_data->result_cb(dev, state, pi3usb9201_data->result_cb_data);
}
}
static void pi3usb9201_update_charging_partner(const struct device *dev,
struct bc12_partner_state *const state)
{
struct pi3usb9201_data *pi3usb9201_data = dev->data;
if (state && state->type == pi3usb9201_data->partner_type) {
/* No change to the charging partner */
return;
}
if (state && state->type != BC12_TYPE_NONE) {
/* Now update the current charger type */
pi3usb9201_data->partner_type = state->type;
pi3usb9201_notify_callback(dev, state);
} else {
pi3usb9201_data->partner_type = BC12_TYPE_NONE;
pi3usb9201_notify_callback(dev, NULL);
}
}
static int pi3usb9201_client_detect_start(const struct device *dev)
{
int rv;
/*
* Read both status registers to ensure that all interrupt indications
* are cleared prior to starting bc1.2 detection.
*/
pi3usb9201_get_status(dev, NULL, NULL);
/* Put pi3usb9201 into client mode */
rv = pi3usb9201_set_mode(dev, PI3USB9201_CLIENT_MODE);
if (rv < 0) {
return rv;
}
/* Have pi3usb9201 start bc1.2 detection */
rv = pi3usb9201_bc12_detect_ctrl(dev, true);
if (rv < 0) {
return rv;
}
/* Enable interrupt to wake task when detection completes */
return pi3usb9201_interrupt_enable(dev, true);
}
static void pi3usb9201_client_detect_finish(const struct device *dev, const int status)
{
struct bc12_partner_state new_chg;
int bit_pos;
bool enable_usb_data;
/* Set charge voltage to 5V */
new_chg.voltage_uv = BC12_CHARGER_VOLTAGE_UV;
/*
* Find set bit position. Note that this function is only called if a
* bit was set in client_status, so bit_pos won't be negative.
*/
bit_pos = __builtin_ffs(status) - 1;
new_chg.current_ua = bc12_chg_limits[bit_pos].current_limit;
new_chg.type = bc12_chg_limits[bit_pos].partner_type;
LOG_DBG("client status = 0x%x, current = %d mA, type = %d",
status, new_chg.current_ua, new_chg.type);
/* bc1.2 is complete and start bit does not auto clear */
if (pi3usb9201_bc12_detect_ctrl(dev, false) < 0) {
LOG_ERR("failed to clear client detect");
}
/* If DCP mode, disable USB swtich */
if (status & BIT(CHG_DCP)) {
enable_usb_data = false;
} else {
enable_usb_data = true;
}
if (pi3usb9201_bc12_usb_switch(dev, enable_usb_data) < 0) {
LOG_ERR("failed to set USB data mode");
}
/* Inform charge manager of new supplier type and current limit */
pi3usb9201_update_charging_partner(dev, &new_chg);
}
static int pi3usb9201_disconnect(const struct device *dev)
{
int rv;
/* Ensure USB switch auto-on is enabled */
rv = pi3usb9201_bc12_usb_switch(dev, true);
if (rv < 0) {
return rv;
}
/* Put pi3usb9201 into its power down mode */
rv = pi3usb9201_set_mode(dev, PI3USB9201_POWER_DOWN);
if (rv < 0) {
return rv;
}
/* The start bc1.2 bit does not auto clear */
rv = pi3usb9201_bc12_detect_ctrl(dev, false);
if (rv < 0) {
return rv;
}
/* Mask interrupts until next bc1.2 detection event */
rv = pi3usb9201_interrupt_enable(dev, false);
if (rv < 0) {
return rv;
}
/*
* Let the application know there's no more charge available for the
* supplier type that was most recently detected.
*/
pi3usb9201_update_charging_partner(dev, NULL);
return 0;
}
static int pi3usb9201_set_portable_device(const struct device *dev)
{
int rv;
/* Disable interrupts during mode change */
rv = pi3usb9201_interrupt_enable(dev, false);
if (rv < 0) {
return rv;
}
if (pi3usb9201_client_detect_start(dev) < 0) {
struct bc12_partner_state new_result;
/*
* VBUS is present, but starting bc1.2 detection failed
* for some reason. Set the partner type to unknown limit
* current to the minimum allowed for a suspended USB device.
*/
new_result.voltage_uv = BC12_CHARGER_VOLTAGE_UV;
new_result.current_ua = BC12_CHARGER_MIN_CURR_UA;
new_result.type = BC12_TYPE_UNKNOWN;
/* Save supplier type and notify callbacks */
pi3usb9201_update_charging_partner(dev, &new_result);
LOG_ERR("bc1.2 detection failed, using defaults");
return -EIO;
}
return 0;
}
static void pi3usb9201_isr_work(struct k_work *item)
{
struct pi3usb9201_data *pi3usb9201_data = CONTAINER_OF(item, struct pi3usb9201_data, work);
const struct device *dev = pi3usb9201_data->dev;
uint8_t client;
uint8_t host;
int rv;
rv = pi3usb9201_get_status(dev, &client, &host);
if (rv < 0) {
LOG_ERR("Failed to get host/client status");
return;
}
if (client != 0) {
/*
* Any bit set in client status register indicates that
* BC1.2 detection has completed.
*/
pi3usb9201_client_detect_finish(dev, client);
}
}
static void pi3usb9201_gpio_callback(const struct device *dev, struct gpio_callback *cb,
uint32_t pins)
{
struct pi3usb9201_data *pi3usb9201_data = CONTAINER_OF(cb, struct pi3usb9201_data, gpio_cb);
k_work_submit(&pi3usb9201_data->work);
}
static int pi3usb9201_set_role(const struct device *dev, const enum bc12_role role)
{
switch (role) {
case BC12_DISCONNECTED:
return pi3usb9201_disconnect(dev);
case BC12_PORTABLE_DEVICE:
return pi3usb9201_set_portable_device(dev);
default:
LOG_ERR("unsupported BC12 role: %d", role);
return -EINVAL;
}
return 0;
}
int pi3usb9201_set_result_cb(const struct device *dev, bc12_callback_t cb, void *const user_data)
{
struct pi3usb9201_data *pi3usb9201_data = dev->data;
pi3usb9201_data->result_cb = cb;
pi3usb9201_data->result_cb_data = user_data;
return 0;
}
static const struct bc12_driver_api pi3usb9201_driver_api = {
.set_role = pi3usb9201_set_role,
.set_result_cb = pi3usb9201_set_result_cb,
};
static int pi3usb9201_init(const struct device *dev)
{
const struct pi3usb9201_config *cfg = dev->config;
struct pi3usb9201_data *pi3usb9201_data = dev->data;
int rv;
if (!i2c_is_ready_dt(&cfg->i2c)) {
LOG_ERR("Bus device is not ready.");
return -ENODEV;
}
if (!gpio_is_ready_dt(&cfg->intb_gpio)) {
LOG_ERR("intb_gpio device is not ready.");
return -ENODEV;
}
pi3usb9201_data->dev = dev;
/*
* Set most recent bc1.2 detection type result to
* BC12_TYPE_NONE for the port.
*/
pi3usb9201_data->partner_type = BC12_TYPE_NONE;
rv = gpio_pin_configure_dt(&cfg->intb_gpio, GPIO_INPUT);
if (rv < 0) {
LOG_DBG("Failed to set gpio callback.");
return rv;
}
gpio_init_callback(&pi3usb9201_data->gpio_cb, pi3usb9201_gpio_callback,
BIT(cfg->intb_gpio.pin));
k_work_init(&pi3usb9201_data->work, pi3usb9201_isr_work);
rv = gpio_add_callback(cfg->intb_gpio.port, &pi3usb9201_data->gpio_cb);
if (rv < 0) {
LOG_DBG("Failed to set gpio callback.");
return rv;
}
rv = gpio_pin_interrupt_configure_dt(&cfg->intb_gpio, GPIO_INT_EDGE_FALLING);
if (rv < 0) {
LOG_DBG("Failed to configure gpio interrupt.");
return rv;
}
/*
* The is no specific initialization required for the pi3usb9201 other
* than disabling the interrupt.
*/
return pi3usb9201_interrupt_enable(dev, false);
}
#define PI2USB9201_DEFINE(inst) \
static struct pi3usb9201_data pi3usb9201_data_##inst; \
\
static const struct pi3usb9201_config pi3usb9201_config_##inst = { \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
.intb_gpio = GPIO_DT_SPEC_INST_GET(inst, intb_gpios), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, pi3usb9201_init, NULL, &pi3usb9201_data_##inst, \
&pi3usb9201_config_##inst, POST_KERNEL, \
CONFIG_APPLICATION_INIT_PRIORITY, &pi3usb9201_driver_api);
DT_INST_FOREACH_STATUS_OKAY(PI2USB9201_DEFINE)

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
/* PI3USB9201 USB BC 1.2 Charger Detector driver definitions */
#ifndef ZEPHYR_INCLUDE_USB_BC12_PI3USB9201_H
#define ZEPHYR_INCLUDE_USB_BC12_PI3USB9201_H
#define PI3USB9201_REG_CTRL_1 0x0
#define PI3USB9201_REG_CTRL_2 0x1
#define PI3USB9201_REG_CLIENT_STS 0x2
#define PI3USB9201_REG_HOST_STS 0x3
/* Flags */
#define PI3USB9201_ALWAYS_POWERED BIT(0)
/* Control_1 register bit definitions */
#define PI3USB9201_REG_CTRL_1_INT_MASK BIT(0)
#define PI3USB9201_REG_CTRL_1_MODE_SHIFT 1
#define PI3USB9201_REG_CTRL_1_MODE_MASK BIT_MASK(3)
/* Control_2 register bit definitions */
#define PI3USB9201_REG_CTRL_2_AUTO_SW BIT(1)
#define PI3USB9201_REG_CTRL_2_START_DET BIT(3)
/* Host status register bit definitions */
#define PI3USB9201_REG_HOST_STS_BC12_DET BIT(0)
#define PI3USB9201_REG_HOST_STS_DEV_PLUG BIT(1)
#define PI3USB9201_REG_HOST_STS_DEV_UNPLUG BIT(2)
enum pi3usb9201_mode {
PI3USB9201_POWER_DOWN,
PI3USB9201_SDP_HOST_MODE,
PI3USB9201_DCP_HOST_MODE,
PI3USB9201_CDP_HOST_MODE,
PI3USB9201_CLIENT_MODE,
PI3USB9201_RESERVED_1,
PI3USB9201_RESERVED_2,
PI3USB9201_USB_PATH_ON,
};
#endif /* ZEPHYR_INCLUDE_USB_BC12_PI3USB9201_H */

View file

@ -0,0 +1,15 @@
# Copyright (c) 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
description: Diodes PI3USB9201, Dual-Role USB Charging-Type Detector
compatible: "diodes,pi3usb9201"
include: [i2c-device.yaml, usb-bc12.yaml]
properties:
intb-gpios:
type: phandle-array
required: true
description: |
GPIO input connected to the active low interrupt INTB pin on the PI3USB9201.

View file

@ -0,0 +1,6 @@
# Copyright (c) 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
# Common fields for USB BC1.2 devices
include: base.yaml

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2022 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Public APIs for the USB BC1.2 battery charging detect drivers.
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_USB_USB_BC12_H_
#define ZEPHYR_INCLUDE_DRIVERS_USB_USB_BC12_H_
#include <zephyr/device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief BC1.2 driver APIs
* @defgroup b12_interface BC1.2 driver APIs
* @ingroup io_interfaces
* @{
*/
/* FIXME - make these Kconfig options */
/**
* @name BC1.2 constants
* @{
*/
/** BC1.2 USB charger voltage. */
#define BC12_CHARGER_VOLTAGE_UV 5000 * 1000
/**
* BC1.2 USB charger minimum current. Set to match the Isusp of 2.5 mA parameter.
* This is returned by the driver when either BC1.2 detection fails, or the
* attached partner is a SDP (standard downstream port).
*
* The application may increase the current draw after determing the USB device
* state of suspended/unconfigured/configured.
* Suspended: 2.5 mA
* Unconfigured: 100 mA
* Configured: 500 mA (USB 2.0)
*/
#define BC12_CHARGER_MIN_CURR_UA 2500
/** BC1.2 USB charger maximum current. */
#define BC12_CHARGER_MAX_CURR_UA 1500 * 1000
/** @} */
/** @cond INTERNAL_HIDDEN
* @brief Helper macro for setting a BC1.2 current limit
*
* @param val Current limit value, in uA.
* @return A valid BC1.2 current limit, in uA, clamped between the BC1.2 minimum
* and maximum values.
*/
#define BC12_CURR_UA(val) CLAMP(val, BC12_CHARGER_MIN_CURR_UA, BC12_CHARGER_MAX_CURR_UA)
/** @endcond */
/** @brief BC1.2 device role. */
enum bc12_role {
BC12_DISCONNECTED,
BC12_PORTABLE_DEVICE,
};
/** @brief BC1.2 charging partner type. */
enum bc12_type {
/** No partner connected. */
BC12_TYPE_NONE,
/** Standard Downstream Port */
BC12_TYPE_SDP,
/** Dedicated Charging Port */
BC12_TYPE_DCP,
/** Charging Downstream Port */
BC12_TYPE_CDP,
/** Proprietary charging port */
BC12_TYPE_PROPRIETARY,
/** Unknown charging port, BC1.2 detection failed. */
BC12_TYPE_UNKNOWN,
};
/**
* @brief BC1.2 detected partner state.
*
* @param type Charging partner type.
* @param current_ma Current, in uA, that the charging partner provides.
* @param voltage_mv Voltage, in uV, that the charging partner provides.
*/
struct bc12_partner_state {
enum bc12_type type;
int current_ua;
int voltage_uv;
};
/**
* @brief BC1.2 callback for charger configuration
*
* @param dev BC1.2 device which is notifying of the new charger state.
* @param state Current state of the BC1.2 client, including BC1.2 type
* detected, voltage, and current limits.
* If NULL, then the partner charger is disconnected or the BC1.2 device is
* operating in host mode.
* @param user_data Requester supplied data which is passed along to the callback.
*/
typedef void (*bc12_callback_t)(const struct device *dev, struct bc12_partner_state *state,
void *user_data);
/**
* @cond INTERNAL_HIDDEN
*
* These are for internal use only, so skip these in public documentation.
*/
__subsystem struct bc12_driver_api {
int (*set_role)(const struct device *dev, enum bc12_role role);
int (*set_result_cb)(const struct device *dev, bc12_callback_t cb, void *user_data);
};
/**
* @endcond
*/
/**
* @brief Set the BC1.2 role.
*
* @param dev Pointer to the device structure for the BC1.2 driver instance.
* @param role New role for the BC1.2 device.
*
* @retval 0 If successful.
* @retval -EIO general input/output error.
*/
__syscall int bc12_set_role(const struct device *dev, enum bc12_role role);
static inline int z_impl_bc12_set_role(const struct device *dev, enum bc12_role role)
{
const struct bc12_driver_api *api = (const struct bc12_driver_api *)dev->api;
return api->set_role(dev, role);
}
/**
* @brief Register a callback for BC1.2 results.
*
* @param dev Pointer to the device structure for the BC1.2 driver instance.
* @param cb Function pointer for the result callback.
* @param user_data Requester supplied data which is passed along to the callback.
*
* @retval 0 If successful.
* @retval -EIO general input/output error.
*/
__syscall int bc12_set_result_cb(const struct device *dev, bc12_callback_t cb, void *user_data);
static inline int z_impl_bc12_set_result_cb(const struct device *dev, bc12_callback_t cb,
void *user_data)
{
const struct bc12_driver_api *api = (const struct bc12_driver_api *)dev->api;
return api->set_result_cb(dev, cb, user_data);
}
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#include <syscalls/usb_bc12.h>
#endif /* ZEPHYR_INCLUDE_DRIVERS_USB_USB_BC12_H_ */