diff options
Diffstat (limited to 'driver/ppc/sn5s330.c')
-rw-r--r-- | driver/ppc/sn5s330.c | 752 |
1 files changed, 0 insertions, 752 deletions
diff --git a/driver/ppc/sn5s330.c b/driver/ppc/sn5s330.c deleted file mode 100644 index 4abf85cf50..0000000000 --- a/driver/ppc/sn5s330.c +++ /dev/null @@ -1,752 +0,0 @@ -/* Copyright 2017 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* TI SN5S330 USB-C Power Path Controller */ - -/* - * PP1 : Sourcing power path. - * PP2 : Sinking power path. - */ - -#include "common.h" -#include "console.h" -#include "sn5s330.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" -#include "usb_pd.h" -#include "usbc_ppc.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */ -static int source_enabled[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static int read_reg(uint8_t port, int reg, int *regval) -{ - return i2c_read8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int write_reg(uint8_t port, int reg, int regval) -{ - return i2c_write8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int set_flags(const int port, const int addr, const int flags_to_set) -{ - int val, rv; - - rv = read_reg(port, addr, &val); - if (rv) - return rv; - - val |= flags_to_set; - - return write_reg(port, addr, val); -} - - -static int clr_flags(const int port, const int addr, const int flags_to_clear) -{ - int val, rv; - - rv = read_reg(port, addr, &val); - if (rv) - return rv; - - val &= ~flags_to_clear; - - return write_reg(port, addr, val); -} - -#ifdef CONFIG_CMD_PPC_DUMP -static int sn5s330_dump(int port) -{ - int i; - int data; - const int i2c_port = ppc_chips[port].i2c_port; - const uint16_t i2c_addr_flags = ppc_chips[port].i2c_addr_flags; - - /* Flush after every set otherwise console buffer may get full. */ - - for (i = SN5S330_FUNC_SET1; i <= SN5S330_FUNC_SET12; i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("FUNC_SET%d [%02Xh] = 0x%02x\n", - i - SN5S330_FUNC_SET1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_STATUS_REG1; i <= SN5S330_INT_STATUS_REG4; i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_STATUS_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_STATUS_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_TRIP_RISE_REG1; i <= SN5S330_INT_TRIP_RISE_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_TRIP_RISE_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_TRIP_RISE_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_TRIP_FALL_REG1; i <= SN5S330_INT_TRIP_FALL_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_TRIP_FALL_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_TRIP_FALL_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_MASK_RISE_REG1; i <= SN5S330_INT_MASK_RISE_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_MASK_RISE_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_MASK_RISE_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_MASK_FALL_REG1; i <= SN5S330_INT_MASK_FALL_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_MASK_FALL_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_MASK_FALL_REG1 + 1, - i, - data); - } - - cflush(); - - return EC_SUCCESS; -} -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - -static int sn5s330_pp_fet_enable(uint8_t port, enum sn5s330_pp_idx pp, - int enable) -{ - int status; - int pp_bit; - - if (pp == SN5S330_PP1) - pp_bit = SN5S330_PP1_EN; - else if (pp == SN5S330_PP2) - pp_bit = SN5S330_PP2_EN; - else - return EC_ERROR_INVAL; - - status = enable ? set_flags(port, SN5S330_FUNC_SET3, pp_bit) - : clr_flags(port, SN5S330_FUNC_SET3, pp_bit); - - if (status) { - ppc_prints("Failed to set FUNC_SET3!", port); - return status; - } - - if (pp == SN5S330_PP1) - source_enabled[port] = enable; - - return EC_SUCCESS; -} - -static int sn5s330_init(int port) -{ - int regval; - int status; - int retries; - int reg; - const int i2c_port = ppc_chips[port].i2c_port; - const uint16_t i2c_addr_flags = ppc_chips[port].i2c_addr_flags; - -#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT - /* Set the sourcing current limit value. */ - switch (CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) { - case TYPEC_RP_3A0: - /* Set current limit to ~3A. */ - regval = SN5S330_ILIM_3_06; - break; - - case TYPEC_RP_1A5: - default: - /* Set current limit to ~1.5A. */ - regval = SN5S330_ILIM_1_62; - break; - } -#else /* !defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) */ - /* Default SRC current limit to ~1.5A. */ - regval = SN5S330_ILIM_1_62; -#endif /* defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) */ - - /* - * It seems that sometimes setting the FUNC_SET1 register fails - * initially. Therefore, we'll retry a couple of times. - */ - retries = 0; - do { - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET1, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET1! Retrying..", - port); - retries++; - msleep(1); - } else { - break; - } - } while (retries < 10); - - /* Set Vbus OVP threshold to ~22.325V. */ - regval = 0x37; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET5, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET5!", port); - return status; - } - - /* Set Vbus UVP threshold to ~2.75V. */ - status = i2c_read8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET6, ®val); - if (status) { - ppc_prints("Failed to read FUNC_SET6!", port); - return status; - } - regval &= ~0x3F; - regval |= 1; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET6, regval); - if (status) { - ppc_prints("Failed to write FUNC_SET6!", port); - return status; - } - - /* Enable SBU Fets and set PP2 current limit to ~3A. */ - regval = SN5S330_SBU_EN | 0x8; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET2, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET2!", port); - return status; - } - - /* - * Indicate we are using PP2 configuration 2 and enable OVP comparator - * for CC lines. - * - * Also, turn off under-voltage protection for incoming Vbus as it would - * prevent us from enabling SNK path before we hibernate the ec. We - * need to enable the SNK path so USB power will assert ACOK and wake - * the EC up went inserting USB power. We always turn off under-voltage - * protection because the battery charger will boost the voltage up - * to the needed battery voltage either way (and it will have its own - * low voltage protection). - */ - regval = SN5S330_OVP_EN_CC | SN5S330_PP2_CONFIG | SN5S330_CONFIG_UVP; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET9, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET9!", port); - return status; - } - - /* - * Set analog current limit delay to 200 us for PP1, - * set 1000 us for PP2 for compatibility. - */ - regval = (PPX_ILIM_DEGLITCH_0_US_200 << 3) | - PPX_ILIM_DEGLITCH_0_US_1000; - status = i2c_write8(i2c_port, i2c_addr_flags, SN5S330_FUNC_SET11, - regval); - if (status) { - ppc_prints("Failed to set FUNC_SET11", port); - return status; - } - -#ifdef CONFIG_USBC_PPC_VCONN - /* - * Set the deglitch timeout on the Vconn current limit to 640us. This - * improves compatibility with some USB C -> HDMI devices versus the - * reset default (20 us). - */ - regval = 0; - status = i2c_read8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET8, ®val); - if (status) { - ppc_prints("Failed to read FUNC_SET8!", port); - return status; - } - regval &= ~SN5S330_VCONN_DEGLITCH_MASK; - regval |= SN5S330_VCONN_DEGLITCH_640_US; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET8, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET8!", port); - return status; - } -#endif /* CONFIG_USBC_PPC_VCONN */ - - /* - * Turn off dead battery resistors, turn on CC FETs, and set the higher - * of the two VCONN current limits (min 0.6A). Many VCONN accessories - * trip the default current limit of min 0.35A. - */ - status = set_flags(port, SN5S330_FUNC_SET4, - SN5S330_CC_EN | SN5S330_VCONN_ILIM_SEL); - if (status) { - ppc_prints("Failed to set FUNC_SET4!", port); - return status; - } - - /* Set ideal diode mode for both PP1 and PP2. */ - status = set_flags(port, SN5S330_FUNC_SET3, - SN5S330_SET_RCP_MODE_PP1 | SN5S330_SET_RCP_MODE_PP2); - if (status) { - ppc_prints("Failed to set FUNC_SET3!", port); - return status; - } - - /* Turn off PP1 FET. */ - status = sn5s330_pp_fet_enable(port, SN5S330_PP1, 0); - if (status) { - ppc_prints("Failed to turn off PP1 FET!", port); - } - - /* - * Don't proceed with the rest of initialization if we're sysjumping. - * We would have already done this before. - */ - if (system_jumped_late()) - return EC_SUCCESS; - - /* - * Clear the digital reset bit, and mask off and clear vSafe0V - * interrupts. Leave the dead battery mode bit unchanged since it - * is checked below. - */ - regval = SN5S330_DIG_RES | SN5S330_VSAFE0V_MASK; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_STATUS_REG4, regval); - if (status) { - ppc_prints("Failed to write INT_STATUS_REG4!", port); - return status; - } - - /* - * Before turning on the PP2 FET, mask off all unwanted interrupts and - * then clear all pending interrupts. - * - * TODO(aaboagye): Unmask fast-role swap events once fast-role swap is - * implemented in the PD stack. - */ - - /* Enable PP1 overcurrent interrupts. */ - regval = ~SN5S330_ILIM_PP1_MASK; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_RISE_REG1, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_RISE1!", port); - return status; - } - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_FALL_REG1, 0xFF); - if (status) { - ppc_prints("Failed to write INT_MASK_FALL1!", port); - return status; - } - - /* Enable VCONN overcurrent and CC1/CC2 overvoltage interrupts. */ - regval = ~(SN5S330_VCONN_ILIM | SN5S330_CC1_CON | SN5S330_CC2_CON); - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_RISE_REG2, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_RISE2!", port); - return status; - } - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_FALL_REG2, 0xFF); - if (status) { - ppc_prints("Failed to write INT_MASK_FALL2!", port); - return status; - } - -#if defined(CONFIG_USB_PD_VBUS_DETECT_PPC) && defined(CONFIG_USB_CHARGER) - /* If PPC is being used to detect VBUS, enable VBUS interrupts. */ - regval = ~SN5S330_VBUS_GOOD_MASK; -#else - regval = 0xFF; -#endif /* CONFIG_USB_PD_VBUS_DETECT_PPC && CONFIG_USB_CHARGER */ - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_RISE_REG3, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_RISE3!", port); - return status; - } - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_FALL_REG3, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_FALL3!", port); - return status; - } - - /* Now clear any pending interrupts. */ - for (reg = SN5S330_INT_TRIP_RISE_REG1; - reg <= SN5S330_INT_TRIP_FALL_REG3; - reg++) { - status = i2c_write8(i2c_port, i2c_addr_flags, - reg, 0xFF); - if (status) { - CPRINTS("ppc p%d: Failed to write reg 0x%2x!", - port, reg); - return status; - } - } - - - /* - * For PP2, check to see if we booted in dead battery mode. If we - * booted in dead battery mode, the PP2 FET will already be enabled. - */ - status = i2c_read8(i2c_port, i2c_addr_flags, - SN5S330_INT_STATUS_REG4, ®val); - if (status) { - ppc_prints("Failed to read INT_STATUS_REG4!", port); - return status; - } - - if (regval & SN5S330_DB_BOOT) { - /* - * Clear the bit by writing 1 and keep vSafe0V_MASK - * unchanged. - */ - i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_STATUS_REG4, regval); - - /* Turn on PP2 FET. */ - status = sn5s330_pp_fet_enable(port, SN5S330_PP2, 1); - if (status) { - ppc_prints("Failed to turn on PP2 FET!", port); - return status; - } - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC -static int sn5s330_is_vbus_present(int port) -{ - int regval; - int rv; - - rv = read_reg(port, SN5S330_INT_STATUS_REG3, ®val); - if (rv) { - ppc_err_prints("VBUS present error", port, rv); - return 0; - } - - return !!(regval & SN5S330_VBUS_GOOD); -} -#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */ - -static int sn5s330_is_sourcing_vbus(int port) -{ - return source_enabled[port]; -} - -#ifdef CONFIG_USBC_PPC_POLARITY -static int sn5s330_set_polarity(int port, int polarity) -{ - if (polarity) - /* CC2 active. */ - return set_flags(port, SN5S330_FUNC_SET4, SN5S330_CC_POLARITY); - else - /* CC1 active. */ - return clr_flags(port, SN5S330_FUNC_SET4, SN5S330_CC_POLARITY); -} -#endif - -static int sn5s330_set_vbus_source_current_limit(int port, - enum tcpc_rp_value rp) -{ - int regval; - int status; - - status = read_reg(port, SN5S330_FUNC_SET1, ®val); - if (status) - return status; - - /* - * Note that we chose the lowest current limit setting that is just - * above indicated Rp value. This is because these are minimum values - * and we must be able to provide the current that we advertise. - */ - regval &= ~0x1F; /* The current limit settings are 4:0. */ - switch (rp) { - case TYPEC_RP_3A0: - regval |= SN5S330_ILIM_3_06; - break; - - case TYPEC_RP_1A5: - regval |= SN5S330_ILIM_1_62; - break; - - case TYPEC_RP_USB: - default: - regval |= SN5S330_ILIM_0_63; - break; - }; - - status = write_reg(port, SN5S330_FUNC_SET1, regval); - - return status; -} - -static int sn5s330_discharge_vbus(int port, int enable) -{ - int status = enable ? set_flags(port, SN5S330_FUNC_SET3, - SN5S330_VBUS_DISCH_EN) - : clr_flags(port, SN5S330_FUNC_SET3, - SN5S330_VBUS_DISCH_EN); - - if (status) { - CPRINTS("ppc p%d: Failed to %s vbus discharge", - port, enable ? "enable" : "disable"); - return status; - } - - return EC_SUCCESS; -} - -static int sn5s330_enter_low_power_mode(int port) -{ - int rv; - - /* Turn off both SRC and SNK FETs */ - rv = clr_flags(port, SN5S330_FUNC_SET3, - SN5S330_PP1_EN | SN5S330_PP2_EN); - - if (rv) { - ppc_err_prints("Could not disable both FETS", port, rv); - return rv; - } - - /* Turn off Vconn power */ - rv = clr_flags(port, SN5S330_FUNC_SET4, SN5S330_VCONN_EN); - - if (rv) { - ppc_err_prints("Could not disable Vconn", port, rv); - return rv; - } - - /* Turn off SBU path */ - rv = clr_flags(port, SN5S330_FUNC_SET2, SN5S330_SBU_EN); - - if (rv) { - ppc_err_prints("Could not disable SBU path", port, rv); - return rv; - } - - /* - * Turn off the Over Voltage Protection circuits. Needs to happen after - * FETs are disabled, otherwise OVP can automatically turned back on. - * Since FETs are off, any over voltage does not make it to the board - * side of the PPC. - */ - rv = clr_flags(port, SN5S330_FUNC_SET9, - SN5S330_FORCE_OVP_EN_SBU | SN5S330_FORCE_ON_VBUS_OVP | - SN5S330_FORCE_ON_VBUS_UVP); - - if (rv) { - ppc_err_prints("Could not disable OVP circuit", port, rv); - return rv; - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_USBC_PPC_VCONN -static int sn5s330_set_vconn(int port, int enable) -{ - int regval; - int status; - - status = read_reg(port, SN5S330_FUNC_SET4, ®val); - if (status) - return status; - - if (enable) - regval |= SN5S330_VCONN_EN; - else - regval &= ~SN5S330_VCONN_EN; - - return write_reg(port, SN5S330_FUNC_SET4, regval); -} -#endif - -static int sn5s330_vbus_sink_enable(int port, int enable) -{ - return sn5s330_pp_fet_enable(port, SN5S330_PP2, !!enable); -} - -static int sn5s330_vbus_source_enable(int port, int enable) -{ - return sn5s330_pp_fet_enable(port, SN5S330_PP1, !!enable); -} - -#ifdef CONFIG_USBC_PPC_SBU -static int sn5s330_set_sbu(int port, int enable) -{ - int rv; - - if (enable) - rv = set_flags(port, SN5S330_FUNC_SET2, SN5S330_SBU_EN); - else - rv = clr_flags(port, SN5S330_FUNC_SET2, SN5S330_SBU_EN); - - return rv; -} -#endif /* CONFIG_USBC_PPC_SBU */ - -static void sn5s330_handle_interrupt(int port) -{ - int attempt = 0; - - /* - * SN5S330's /INT pin is level, so process interrupts until it - * deasserts if the chip has a dedicated interrupt pin. - */ -#ifdef CONFIG_USBC_PPC_DEDICATED_INT - while (ppc_get_alert_status(port)) -#endif - { - int rise = 0; - int fall = 0; - - attempt++; - - if (attempt > 1) - ppc_prints("Could not clear interrupts on first " - "try, retrying", port); - - read_reg(port, SN5S330_INT_TRIP_RISE_REG1, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG1, &fall); - - /* Notify the system about the overcurrent event. */ - if (rise & SN5S330_ILIM_PP1_MASK) - pd_handle_overcurrent(port); - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG1, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG1, fall); - - read_reg(port, SN5S330_INT_TRIP_RISE_REG2, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG2, &fall); - - /* - * VCONN may be latched off due to an overcurrent. Indicate - * when the VCONN overcurrent happens. - */ - if (rise & SN5S330_VCONN_ILIM) - ppc_prints("VCONN OC!", port); - - /* Notify the system about the CC overvoltage event. */ - if (rise & SN5S330_CC1_CON || rise & SN5S330_CC2_CON) { - ppc_prints("CC OV!", port); - pd_handle_cc_overvoltage(port); - } - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG2, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG2, fall); - -#if defined(CONFIG_USB_PD_VBUS_DETECT_PPC) && defined(CONFIG_USB_CHARGER) - read_reg(port, SN5S330_INT_TRIP_RISE_REG3, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG3, &fall); - - /* Inform other modules about VBUS level */ - if (rise & SN5S330_VBUS_GOOD_MASK - || fall & SN5S330_VBUS_GOOD_MASK) - usb_charger_vbus_change(port, - sn5s330_is_vbus_present(port)); - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG3, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG3, fall); -#endif /* CONFIG_USB_PD_VBUS_DETECT_PPC && CONFIG_USB_CHARGER */ - - } -} - -static void sn5s330_irq_deferred(void) -{ - int i; - uint32_t pending = atomic_clear(&irq_pending); - - for (i = 0; i < board_get_usb_pd_port_count(); i++) - if (BIT(i) & pending) - sn5s330_handle_interrupt(i); -} -DECLARE_DEFERRED(sn5s330_irq_deferred); - -void sn5s330_interrupt(int port) -{ - atomic_or(&irq_pending, BIT(port)); - hook_call_deferred(&sn5s330_irq_deferred_data, 0); -} - -const struct ppc_drv sn5s330_drv = { - .init = &sn5s330_init, - .is_sourcing_vbus = &sn5s330_is_sourcing_vbus, - .vbus_sink_enable = &sn5s330_vbus_sink_enable, - .vbus_source_enable = &sn5s330_vbus_source_enable, - .set_vbus_source_current_limit = &sn5s330_set_vbus_source_current_limit, - .discharge_vbus = &sn5s330_discharge_vbus, - .enter_low_power_mode = &sn5s330_enter_low_power_mode, -#ifdef CONFIG_CMD_PPC_DUMP - .reg_dump = &sn5s330_dump, -#endif -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC - .is_vbus_present = &sn5s330_is_vbus_present, -#endif -#ifdef CONFIG_USBC_PPC_POLARITY - .set_polarity = &sn5s330_set_polarity, -#endif -#ifdef CONFIG_USBC_PPC_SBU - .set_sbu = &sn5s330_set_sbu, -#endif /* defined(CONFIG_USBC_PPC_SBU) */ -#ifdef CONFIG_USBC_PPC_VCONN - .set_vconn = &sn5s330_set_vconn, -#endif -}; |