/** * @brief Initialize dedicated HW (GPIO, ADC) and configure averaging * to enable current measurement of a given spring. * @warning Shall be called prior to any other spwrm_* call. * warning 'spring' index starts at 1, not 0. * @return 0 on success, standard error codes otherwise. * @param[in] spring: selected spring ([1..SPRING_COUNT]) * @param[in] count: averaging sample count * ([1..ADC_MAX_AVG_SAMPLE_COUNT]) */ int spwrm_init(uint8_t spring, uint8_t count) { uint8_t adc, chan; uint32_t spin; int ret; CHECK_SPRING(spring); CHECK_ARG_AVG_COUNT(count); adc = spwrm_get_adc_device(spring); chan = spwrm_get_adc_channel(spring); spin = spwrm_get_sign_pin(spring); dbg_verbose("%s(): Configuring %s... (adc=%u, spin=0x%08X)\n", __func__, spwrm_get_name(spring), adc, spin); /* Configure SIGN pin as input */ stm32_configgpio(spin); ret = adc_init(adc, chan, count); if (ret) { dbg_error("%s(): %s initialization failed!!! (%d).\n", __func__, spwrm_get_name(spring), ret); } else { dbg_verbose("%s(): %s initialization done.\n", __func__, spwrm_get_name(spring)); } return ret; }
/** * @brief Return sampled data of a given power rail. * @return 0 on success, standard error codes otherwise. * @param[in] bdbpm_r: power rail device structure * @param[out] m: power measurement data (voltage, current, power) */ int bdbpm_measure_rail(bdbpm_rail *bdbpm_r, pwr_measure *m) { int ret; if ((!bdbpm_r) || (!m)) { dbg_error("%s(): NULL pointer!\n", __func__); return -EINVAL; } dbg_verbose("%s(): measuring %s rail...\n", __func__, bdbpm_r->rail_name); /* Configure I2C Mux */ ret = bdbpm_ina230_select(bdbpm_r->dev); if (ret) { dbg_error("%s(): failed to configure i2c mux! (%d)\n", __func__, ret); return ret; } /* Get measurement data */ ret = ina230_get_data(bdbpm_r->ina230_dev, m); if (ret) { dbg_error("%s(): failed to retrieve measurement data! (%d)\n", __func__, ret); } else { dbg_verbose("%s(): %s measurement: %duV %duA %duW\n", __func__, bdbpm_r->rail_name, m->uV, m->uA, m->uW); } return ret; }
/** * @brief Measure the current consumption of a given spring. * @return current consumption of a given spring (in microamps) * warning 'spring' index starts at 1, not 0. * @param[in] spring: selected spring ([1..SPRING_COUNT]) * @param[out] uA: selected spring current measurement, in microamps) */ int spwrm_get_current(uint8_t spring, int32_t *uA) { int ret; uint8_t adc, chan; uint32_t spin, uV; CHECK_SPRING(spring); CHECK_NULL_ARG(uA); adc = spwrm_get_adc_device(spring); chan = spwrm_get_adc_channel(spring); spin = spwrm_get_sign_pin(spring); *uA = 0; ret = adc_get_data(adc, chan, &uV); if (ret) { dbg_error("%s(): failed to get %s data! (%d)\n", __func__, spwrm_get_name(spring), ret); return ret; } /* Convert to uV */ uV = adc_get_uV(uV); /* Get data sign */ if (stm32_gpioread(spin) == 0) { dbg_verbose("%s(): pin=0 => sign=-\n", __func__); *uA = -((int32_t) max9929f_get_Iload(uV)); } else { dbg_verbose("%s(): pin=1 => sign=+\n", __func__); *uA = (int32_t) max9929f_get_Iload(uV); } dbg_verbose("%s(): measured voltage=%uuV => current=%duA\n", __func__, uV, *uA); return 0; }
/** * @brief Deinitialize dedicated current measurement HW * (GPIO, ADC) of a given spring. * warning 'spring' index starts at 1, not 0. * @return 0 on success, standard error otherwise. * @param[in] spring: selected spring ([1..SPRING_COUNT]) */ int spwrm_deinit(uint8_t spring) { int ret; uint8_t adc, chan; uint32_t spin; CHECK_SPRING(spring); dbg_verbose("%s(): De-initializing %s...\n", __func__, spwrm_get_name(spring)); adc = spwrm_get_adc_device(spring); chan = spwrm_get_adc_channel(spring); spin = spwrm_get_sign_pin(spring); /* Unconfigure GPIO ADC channel pin */ stm32_unconfiggpio(spin); /* Shutdown ADC */ ret = adc_deinit(adc, chan); if (ret) { dbg_error("%s(): %s de-initialization failed!!! (%d)\n", __func__, spwrm_get_name(spring), ret); } else { dbg_verbose("%s(): %s de-initialization done.\n", __func__, spwrm_get_name(spring)); } return ret; }
static bool rexec_remote( char *host, int port, char *c ) { int ret, sockfd; char *cmd=NULL; cmd = (char*)malloc( strlen(c) + 10); sockfd = sock_connectTo( host, port ); if(sockfd==-1) return false; sprintf( cmd, "EXECUTE %s", c ); dbg_verbose( "%s\n", cmd ); sock_sendLine( sockfd, cmd ); ret = sock_getStatus( sockfd ); if( ret < 0 ) { dbg_error( "rexec: No remote confirmation!\n"); free(cmd); return false; } if( ret > 0 ) { dbg_error("rexec: Error: '%s'\n", strerror( ret ) ); dbg_error("rexec: Can't execute [%s].\n", c ); free(cmd); shutdown( sockfd, 2); close( sockfd ); return false; } free(cmd); shutdown( sockfd, 2); close( sockfd ); return true; }
/** * @brief Collect power measurements of all user-selected rails. * @return 0 on success, standard error codes otherwise */ static int bdbpm_main_collect_measurements(void) { int ret = 0; uint8_t d_start, d_end; uint8_t r_start, r_end; uint8_t d, r; bdbpm_main_get_device_list(&d_start, &d_end); for (d = d_start; d < d_end; d++) { bdbpm_main_get_rail_list(d, &r_start, &r_end); for (r = r_start; r < r_end; r++) { ret = bdbpm_measure_rail(bdbpm_rails[d][r], &measurements[d][r]); if (ret) { fprintf(stderr, "failed to collect %s measurements!!! (%d)\n", bdbpm_rail_name(d, r), ret); return ret; } else { dbg_verbose("%s(): %s: %uuV %uuA %uuW\n", __func__, bdbpm_rail_name(d, r), measurements[d][r].uV, measurements[d][r].uA, measurements[d][r].uW); } } } return 0; }
/* Control RGB LED */ void debug_rgb_led(uint8_t r, uint8_t g, uint8_t b) { dbg_verbose("%s(): rgb=%d%d%d\n", __func__, r, g, b); stm32_gpiowrite(GPIO_R_LED_EN, !r); stm32_gpiowrite(GPIO_G_LED_EN, !g); stm32_gpiowrite(GPIO_B_LED_EN, !b); }
/** * @brief Take ownership of WDx pins prior to issuing timesync strobe signals * ensuring a known initial state on WDM lines before APB/GPB get * transitioned to monitor incoming timesync strobe signals */ int timesync_wd_pins_init(uint32_t interface_strobe_mask) { struct interface *intf_apb1, *intf_apb2; if (timesync_state == TIMESYNC_STATE_SYNCING || timesync_state == TIMESYNC_STATE_INVALID) { return -EBUSY; } intf_apb1 = interface_get_by_name(INTF_APB1); intf_apb2 = interface_get_by_name(INTF_APB2); if (intf_apb1) { interface_strobe_mask |= 1 << intf_apb1->dev_id; } else { lldbg("Couldn't find APB1 interface!\n"); } if (intf_apb2) { interface_strobe_mask |= 1 << intf_apb2->dev_id; } else { lldbg("Couldn't find APB2 interface!\n"); } timesync_pin_strobe_mask = interfaces_timesync_init(interface_strobe_mask); dbg_verbose("interface-mask 0x%08lx strobe-mask 0x%08lx\n", interface_strobe_mask, timesync_pin_strobe_mask); return 0; }
/** * @brief Return the device ID given a device name. * @return device ID (>= 0) on success, standard error codes otherwise. * -ENODEV if not found * @param[in] name: power rail name * @param[out] dev: device ID */ int bdbpm_device_id(const char *name, uint8_t *dev) { int ret = 0; if ((!name) || (!dev)) { ret = -ENODEV; } else { *dev = DEV_COUNT; } if (strcmp(name, "SW") == 0) { *dev = DEV_SW; } else if (strcmp(name, "APB1") == 0) { *dev = DEV_APB1; } else if (strcmp(name, "APB2") == 0) { *dev = DEV_APB2; } else if (strcmp(name, "APB3") == 0) { *dev = DEV_APB3; } else if (strcmp(name, "GPB1") == 0) { *dev = DEV_GPB1; } else if (strcmp(name, "GPB2") == 0) { *dev = DEV_GPB2; #ifdef CONFIG_ARCH_BOARD_ARA_SDB_SVC } else if (strcmp(name, "SVC") == 0) { *dev = DEV_SVC; #endif } else { *dev = DEV_COUNT; ret = -ENODEV; } dbg_verbose("%s(): name=%s => device=%u\n", __func__, name, *dev); return ret; }
/* Main request processing thread */ static int r592_process_thread(void *data) { int error; struct r592_device *dev = (struct r592_device *)data; unsigned long flags; while (!kthread_should_stop()) { spin_lock_irqsave(&dev->io_thread_lock, flags); set_current_state(TASK_INTERRUPTIBLE); error = memstick_next_req(dev->host, &dev->req); spin_unlock_irqrestore(&dev->io_thread_lock, flags); if (error) { if (error == -ENXIO || error == -EAGAIN) { dbg_verbose("IO: done IO, sleeping"); } else { dbg("IO: unknown error from " "memstick_next_req %d", error); } if (kthread_should_stop()) set_current_state(TASK_RUNNING); schedule(); } else { set_current_state(TASK_RUNNING); r592_execute_tpc(dev); } } return 0; }
/** * @brief Configure all the GPIOs associated with a voltage regulator * to their default states. * @param vreg regulator to configure */ int vreg_config(struct vreg *vreg) { unsigned int i; int rc = 0; if (!vreg) { return -ENODEV; } dbg_verbose("%s %s\n", __func__, vreg->name ? vreg->name : "unknown"); for (i = 0; i < vreg->nr_vregs; i++) { if (!&vreg->vregs[i]) { rc = -EINVAL; break; } dbg_insane("%s: %s vreg, gpio %d\n", __func__, vreg->name ? vreg->name : "unknown", vreg->vregs[i].gpio); // First set default value then switch line to output mode gpio_set_value(vreg->vregs[i].gpio, vreg->vregs[i].def_val); gpio_direction_out(vreg->vregs[i].gpio, vreg->vregs[i].def_val); } atomic_init(&vreg->use_count, 0); vreg->power_state = false; return rc; }
/** * @brief Manage the regulator state; Turn it on when needed * @returns: 0 on success, <0 on error */ int vreg_get(struct vreg *vreg) { unsigned int i, rc = 0; if (!vreg) { return -ENODEV; } dbg_verbose("%s %s\n", __func__, vreg->name ? vreg->name : "unknown"); /* Enable the regulator on the first use; Update use count */ if (atomic_inc(&vreg->use_count) == 1) { for (i = 0; i < vreg->nr_vregs; i++) { if (!&vreg->vregs[i]) { rc = -EINVAL; break; } dbg_insane("%s: %s vreg, gpio %d to %d, hold %dus\n", __func__, vreg->name ? vreg->name : "unknown", vreg->vregs[i].gpio, !!vreg->vregs[i].active_high, vreg->vregs[i].hold_time); gpio_set_value(vreg->vregs[i].gpio, vreg->vregs[i].active_high); up_udelay(vreg->vregs[i].hold_time); } } /* Update state */ vreg->power_state = true; return rc; }
/** * @brief Manage the regulator state; Turn it off when unused * @returns: 0 on success, <0 on error */ int vreg_put(struct vreg *vreg) { unsigned int i, rc = 0; if (!vreg) { return -ENODEV; } dbg_verbose("%s %s\n", __func__, vreg->name ? vreg->name : "unknown"); /* If already disabled, do nothing */ if (!atomic_get(&vreg->use_count)) return rc; /* Disable the regulator on the last use; Update use count */ if (!atomic_dec(&vreg->use_count)) { for (i = 0; i < vreg->nr_vregs; i++) { if (!&vreg->vregs[i]) { rc = -EINVAL; break; } dbg_insane("%s: %s vreg, gpio %08x to %d\n", __func__, vreg->name ? vreg->name : "unknown", vreg->vregs[i].gpio, !vreg->vregs[i].active_high); gpio_set_value(vreg->vregs[i].gpio, !vreg->vregs[i].active_high); } /* Update state */ vreg->power_state = false; } return rc; }
/** * @brief Configure all the voltage regulators associated with an interface * to their default states. * @param iface interface to configure */ static int interface_config(struct interface *iface) { int rc = 0; dbg_verbose("Configuring interface %s.\n", iface->name ? iface->name : "unknown"); /* Configure default state for the regulator pins */ rc = vreg_config(iface->vreg); /* * Configure WAKEOUT as input, floating so that it does not interfere * with the wake and detect input pin */ if (iface->wake_out) { if (stm32_configgpio(iface->wake_out | GPIO_INPUT) < 0) { dbg_error("%s: Failed to configure WAKEOUT pin for interface %s\n", __func__, iface->name ? iface->name : "unknown"); rc = -1; } } iface->power_state = false; return rc; }
/** * @brief Initialize the power measurement HW and SW library. * To be called once, before any other call to the library. * @return 0 on success, standard error codes otherwise. * @param[in] current_lsb_uA: current measurement precision (LSB) in uA * @param[in] ct: sampling conversion time to be used * @param[in] avg_count: averaging sample count (>0) */ int bdbpm_init(uint32_t current_lsb_uA, ina230_conversion_time ct, ina230_avg_count avg_count) { dbg_verbose("%s(): Initializing with options lsb=%uuA, ct=%u, avg_count=%u...\n", __func__, current_lsb_uA, ct, avg_count); /* Initialize I2C internal structs */ i2c_dev = up_i2cinitialize(PWRM_I2C_BUS); if (!i2c_dev) { dbg_error("%s(): Failed to get I2C bus %u\n", __func__, PWRM_I2C_BUS); return -ENXIO; } bdbpm_current_lsb = current_lsb_uA; if (ct >= ina230_ct_count) { dbg_error("%s(): invalid conversion time! (%u)\n", __func__, ct); up_i2cuninitialize(i2c_dev); return -EINVAL; } if (avg_count >= ina230_avg_count_max) { dbg_error("%s(): invalid average count! (%u)\n", __func__, avg_count); up_i2cuninitialize(i2c_dev); return -EINVAL; } bdbpm_ct = ct; bdbpm_avg_count = avg_count; current_dev = -1; /* * Setup I/O selection pins on U135 * * Note: U135 is registered to gpio_chip from the board code */ gpio_direction_out(I2C_INA230_SEL1_A, 1); gpio_direction_out(I2C_INA230_SEL1_B, 1); gpio_direction_out(I2C_INA230_SEL1_INH, 1); gpio_direction_out(I2C_INA230_SEL2_A, 1); gpio_direction_out(I2C_INA230_SEL2_B, 1); gpio_direction_out(I2C_INA230_SEL2_INH, 1); dbg_verbose("%s(): done.\n", __func__); return OK; }
/** * @brief Convert voltage into current, following MAX9929F device * specifications. * @return Current (microamps) * @param[in] uV: voltage (in microvolts) */ static inline uint32_t max9929f_get_Iload(uint32_t uV) { uint32_t uA; uA = (uV / MAX9929F_AV_GAIN) * MAX9929F_RSENSE_RECIPROCAL; dbg_verbose("%s(): uV=%uuV, Rs=100 mohms, gain=%u uA=%u\n", __func__, uV, MAX9929F_AV_GAIN, uA); return uA; }
/** * @brief Convert sampled 12-bit data into voltage (microvolts), * considering ADC reference voltage and voltage LSB. * @return Voltage (microvolts) * @param[in] data: ADC sampled data */ static inline uint32_t adc_get_uV(uint32_t data) { uint32_t uV; uV = data * ADC_VOLTAGE_LSB; dbg_verbose("%s(): data=%u, lsb=%uuV, uV=%uuV\n", __func__, data, ADC_VOLTAGE_LSB, uV); return uV; }
/** * @brief Return time required to sample spring current consumption * warning 'spring' index starts at 1, not 0. * @return spring current consumption sampling time (in microseconds), * standard error codes otherwise (<0) * @param[in] spring: selected spring ([1..SPRING_COUNT]) */ int32_t spwrm_get_sampling_time(uint8_t spring) { uint8_t adc; CHECK_SPRING(spring); adc = spwrm_get_adc_device(spring); dbg_verbose("%s(): %s sampling time = %dus\n", __func__, spwrm_get_name(spring), adc_get_sampling_time(adc)); return adc_get_sampling_time(adc); }
/* Interrupt handler */ static irqreturn_t r592_irq(int irq, void *data) { struct r592_device *dev = (struct r592_device *)data; irqreturn_t ret = IRQ_NONE; u32 reg; u16 irq_enable, irq_status; unsigned long flags; int error; spin_lock_irqsave(&dev->irq_lock, flags); reg = r592_read_reg(dev, R592_REG_MSC); irq_enable = reg >> 16; irq_status = reg & 0xFFFF; /* Ack the interrupts */ reg &= ~irq_status; r592_write_reg(dev, R592_REG_MSC, reg); /* Get the IRQ status minus bits that aren't enabled */ irq_status &= (irq_enable); /* Due to limitation of memstick core, we don't look at bits that indicate that card was removed/inserted and/or present */ if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) { bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT; ret = IRQ_HANDLED; message("IRQ: card %s", card_was_added ? "added" : "removed"); mod_timer(&dev->detect_timer, jiffies + msecs_to_jiffies(card_was_added ? 500 : 50)); } if (irq_status & (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) { ret = IRQ_HANDLED; if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) { message("IRQ: DMA error"); error = -EIO; } else { dbg_verbose("IRQ: dma done"); error = 0; } r592_stop_dma(dev, error); complete(&dev->dma_done); } spin_unlock_irqrestore(&dev->irq_lock, flags); return ret; }
/** * @brief Return device start and end IDs depending on user options. * @return device start and end IDs * @param[out] d_start: device start ID * @param[out] d_end: device end ID */ static void bdbpm_main_get_device_list(uint8_t *d_start, uint8_t *d_end) { if (user_dev_id == DEV_COUNT) { *d_start = 0; *d_end = DEV_COUNT; } else { *d_start = user_dev_id; *d_end = user_dev_id + 1; } dbg_verbose("%s(): user_dev_id=%u => d_start=%u d_end=%u\n", __func__, user_dev_id, *d_start, *d_end); }
/** * @brief Return rail start and end IDs depending on user options. * @return rail start and end IDs * @param[in] dev: device ID * @param[out] r_start: power rail start ID * @param[out] r_end: power rail end ID */ static void bdbpm_main_get_rail_list(uint8_t dev, uint8_t *r_start, uint8_t *r_end) { if (user_rail_id == DEV_MAX_RAIL_COUNT) { *r_start = 0; *r_end = bdbpm_dev_rail_count(dev); } else { *r_start = user_rail_id; *r_end = user_rail_id + 1; } dbg_verbose("%s(): dev=%u => r_start=%u r_end=%u\n", __func__, dev, *r_start, *r_end); }
/* External interface: submit requests */ static void r592_submit_req(struct memstick_host *host) { struct r592_device *dev = memstick_priv(host); unsigned long flags; if (dev->req) return; spin_lock_irqsave(&dev->io_thread_lock, flags); if (wake_up_process(dev->io_thread)) dbg_verbose("IO thread woken to process requests"); spin_unlock_irqrestore(&dev->io_thread_lock, flags); }
/** * @brief Deinitialize HW & SW structure of a given power rail. * @param[in] bdbpm_r: power rail device structure */ void bdbpm_deinit_rail(bdbpm_rail *bdbpm_r) { int ret; if (!bdbpm_r) { dbg_error("%s(): invalid bdbpm_r!\n", __func__); return; } dbg_verbose("%s(): deinitializing %s device...\n", __func__, bdbpm_r->rail_name); /* Configure I2C Mux */ ret = bdbpm_ina230_select(bdbpm_r->dev); if (ret) { dbg_error("%s(): failed to configure i2c mux! (%d)\n", __func__, ret); return; } /* Deinit device */ ina230_deinit(bdbpm_r->ina230_dev); /* Free memory */ free(bdbpm_r); dbg_verbose("%s(): device deinit done.\n", __func__); }
/** * @brief Turn on the power to this interface * @returns: 0 on success, <0 on error */ int interface_pwr_enable(struct interface *iface) { if (!iface) { return -ENODEV; } dbg_verbose("Enabling interface %s.\n", iface->name ? iface->name : "unknown"); vreg_get(iface->vreg); /* Update state */ iface->power_state = true; return 0; }
/** * @brief Return maximum rail count depending on user options. * @return maximum rail count */ static uint8_t bdbpm_main_get_max_rail_count(void) { uint8_t max_rcount; if (user_dev_id == DEV_COUNT) { max_rcount = DEV_MAX_RAIL_COUNT; } else { if (user_rail_id == DEV_MAX_RAIL_COUNT) { max_rcount = bdbpm_dev_rail_count(user_dev_id); } else { max_rcount = 1; } } dbg_verbose("%s(): max_rcount=%u\n", __func__, max_rcount); return max_rcount; }
/* Send data from SVC to switch */ inline int i2c_switch_send_msg(uint8_t *buf, unsigned int size) { int ret; dbg_verbose("%s()\n", __func__); dbg_print_buf(DBG_VERBOSE, buf, size); i2c_select_device(I2C_ADDR_SWITCH); ret = I2C_WRITE(sw_exp_dev, buf, size); if (ret) { dbg_error("%s(): Error %d\n", __func__, ret); return ERROR; } return 0; }
/* Write data to the IO Expander */ int i2c_ioexp_write(uint8_t *msg, int size, uint8_t addr) { int ret; i2c_select_device(addr); ret = I2C_WRITE(sw_exp_dev, msg, size); if (ret) { dbg_error("%s(): Error %d\n", __func__, ret); return ERROR; } dbg_verbose("%s()\n", __func__); dbg_print_buf(DBG_VERBOSE, msg, size); return ret; }
/* Transfers fifo contents in/out using DMA */ static int r592_transfer_fifo_dma(struct r592_device *dev) { int len, sg_count; bool is_write; if (!dev->dma_capable || !dev->req->long_data) return -EINVAL; len = dev->req->sg.length; is_write = dev->req->data_dir == WRITE; if (len != R592_LFIFO_SIZE) return -EINVAL; dbg_verbose("doing dma transfer"); dev->dma_error = 0; INIT_COMPLETION(dev->dma_done); /* TODO: hidden assumption about nenth beeing always 1 */ sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (sg_count != 1 || (sg_dma_len(&dev->req->sg) < dev->req->sg.length)) { message("problem in dma_map_sg"); return -EIO; } r592_start_dma(dev, is_write); /* Wait for DMA completion */ if (!wait_for_completion_timeout( &dev->dma_done, msecs_to_jiffies(1000))) { message("DMA timeout"); r592_stop_dma(dev, -ETIMEDOUT); } dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); return dev->dma_error; }
/* * @brief Generate a WAKEOUT signal to wake-up/power-up modules. * If assert is true, keep the WAKEOUT lines asserted. * * The corresponding power supplies must already be enabled. */ int interface_generate_wakeout(struct interface *iface, bool assert) { int rc; if (!iface) { return -ENODEV; } /* * Assert the WAKEOUT line on the interfaces in order to power up the * modules. * When the WAKEOUT signal is de-asserted the bridges have to assert * the PS_HOLD signal asap in order to stay powered up. */ dbg_verbose("Generating WAKEOUT on interface %s.\n", iface->name ? iface->name : "unknown"); if (iface->wake_out) { rc = stm32_configgpio(iface->wake_out | GPIO_OUTPUT | GPIO_OUTPUT_SET); if (rc < 0) { dbg_error("%s: Failed to assert WAKEOUT pin for interface %s\n", __func__, iface->name ? iface->name : "unknown"); return rc; } if (!assert) { /* Wait for the bridges to react */ usleep(WAKEOUT_PULSE_DURATION_IN_US); /* De-assert the lines */ rc = stm32_configgpio(iface->wake_out | GPIO_INPUT); if (rc < 0) { dbg_error("%s: Failed to de-assert WAKEOUT pin for interface %s\n", __func__, iface->name ? iface->name : "unknown"); return rc; } } } return 0; }
/** * @brief Generate a ping to the given bit-mask of interfaces * return authoritative time at the ping. * AP must have already completed a timesync_wd_pins_init() routine */ int timesync_ping(uint64_t *frame_time) { irqstate_t flags; if (!frame_time) return -EINVAL; if (timesync_state != TIMESYNC_STATE_DEBUG_ACTIVE && timesync_state != TIMESYNC_STATE_ACTIVE) { lldbg("timesync invalid state %d cannot ping\n", timesync_state); return -ENODEV; } flags = irqsave(); timesync_strobe(timesync_pin_strobe_mask, frame_time); irqrestore(flags); dbg_verbose("Ping pinmask=0x%08lx frame-time=%llu\n", timesync_pin_strobe_mask, *frame_time); return 0; }