/** * @brief Get SPI specific chip-configured information * * This function can be called whether lock() has been called or not. * * @param dev pointer to structure of device data * @param devid the specific chip number * @param device_cfg pointer to the device_spi_device_config structure to * receive the configuration that is set in chip. * @return 0 on success, negative errno on error */ static int tsb_spi_get_device_config(struct device *dev, uint8_t devid, struct device_spi_device_config *device_cfg) { struct tsb_spi_dev_info *info = NULL; struct device *spi_board; /* check input parameters */ if (!dev || !device_get_private(dev) || !device_cfg) { return -EINVAL; } info = device_get_private(dev); if (!info->dev_spi_board || devid >= info->num_boards) { return -EINVAL; } sem_wait(&info->lock); spi_board = info->dev_spi_board[devid]; /* get device config */ device_spi_board_get_mode(spi_board, &device_cfg->mode); device_spi_board_get_bpw(spi_board, &device_cfg->bpw); device_spi_board_get_max_speed_hz(spi_board, &device_cfg->max_speed_hz); device_spi_board_get_type(spi_board, &device_cfg->device_type); device_spi_board_get_name(spi_board, device_cfg->name); sem_post(&info->lock); return 0; }
/** * @brief Close SPI device * * This function is called when the caller is no longer using this driver. It * should release or close all resources that were allocated by the open() * function. This function should be called after the open() function. If the * device is not opened yet, this function should return without any operations. * * @param dev pointer to structure of device data */ static void tsb_spi_dev_close(struct device *dev) { int i; struct tsb_spi_dev_info *info = NULL; /* check input parameter */ if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); sem_wait(&info->lock); up_disable_irq(TSB_IRQ_SPI); irq_detach(TSB_IRQ_SPI); tsb_spi_hw_deinit(info); for (i = 0; i < info->num_boards; i++) { device_close(info->dev_spi_board[i]); info->dev_spi_board[i] = NULL; } info->state = TSB_SPI_STATE_CLOSED; sem_post(&info->lock); }
static int sensor_accel_op_start_reporting(struct device *dev, uint8_t sensor_id, uint64_t sampling_period, uint64_t max_report_latency) { struct sensor_accel_info *info = NULL; gb_debug("%s:\n",__func__); if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); /* cancel any work and reset ourselves */ if (!work_available(&info->data_report_work)) work_cancel(LPWORK, &info->data_report_work); data = 1000; /* if not already scheduled, schedule start */ if (work_available(&info->data_report_work)) work_queue(LPWORK, &info->data_report_work, accel_data_report_worker, info, 0); atomic_inc(&txn); return OK; }
/** * @brief Disable the SPI chip select pin * * The implementation of this method must include handshaking. If a device is * selected, it must hold off all the other attempts to select the device * until the device is deselected. This function should be called after lock(); * if the driver isn’t in lock state, it returns an error code to notify a * problem. * * @param dev pointer to structure of device data * @param devid identifier of a selected SPI slave device * @return 0 on success, negative errno on error */ static int tsb_spi_deselect(struct device *dev, uint8_t devid) { struct tsb_spi_dev_info *info = NULL; int ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { ret = -EPERM; goto err_deselect; } tsb_spi_write(info->reg_base, DW_SPI_SER, 0); ret = device_spi_board_cs_select(info->dev_spi_board[devid], !info->curr_xfer.cs_high); err_deselect: sem_post(&info->lock); return ret; }
/** * @brief Hardware de-initialization * * The function will restore original pinshare value and deactivate GPIO pins. * * @param dev pointer to structure of device data * @return 0 on success, negative errno on error */ static int tsb_spi_hw_deinit(struct device *dev) { struct tsb_spi_info *info = NULL; uint32_t pinshare = 0; int i = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); /* release GPIO pins */ for (i = 0; i < info->caps.csnum; i++) { gpio_deactivate(info->chipselect[i]); } gpio_deactivate(SPI_SDO); gpio_deactivate(SPI_SDI); gpio_deactivate(SPI_SCK); /* restore pinshare#5 setting */ pinshare = tsb_get_pinshare() & TSB_PIN_GPIO10; /* current setting */ if ((info->pinshare & TSB_PIN_GPIO10)) { if (!pinshare) { tsb_set_pinshare(TSB_PIN_GPIO10); } } else { if (pinshare) { tsb_clr_pinshare(TSB_PIN_GPIO10); } } return 0; }
/** * @brief Lock SPI bus for exclusive access * * On SPI buses where there are multiple devices, it will be necessary to lock * SPI to have exclusive access to the buses for a sequence of transfers. * The bus should be locked before the chip is selected. After locking the SPI * bus, the caller should then also call the setfrequency(), setbpw(), and * setmode() methods to make sure that the SPI is properly configured for the * device. If the SPI bus is being shared, then it may have been left in an * incompatible state. * * @param dev pointer to structure of device data * @return 0 on success, negative errno on error */ static int tsb_spi_lock(struct device *dev) { struct tsb_spi_dev_info *info = NULL; int ret = 0, loop = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); if (info->spi_pmstate == PM_SLEEP) { pm_activity(TSB_SPI_ACTIVITY); /* SPI not powered, fail any accessing */; while (info->spi_pmstate == PM_SLEEP) { usleep(1000); if (++loop > 10) { return -EIO; } } } /* Take the semaphore (perhaps waiting) */ ret = sem_wait(&info->bus); if (ret != OK) { /* The sem_wait() call should fail only if we are awakened by * a signal. */ return -get_errno(); } info->state = TSB_SPI_STATE_LOCKED; return 0; }
/** * @brief Set the number of bits per word in transmission. * * This function should be called after lock(), if driver is not in lock state, * this function returns -EPERM error code. * * @param dev pointer to structure of device data * @param nbits The number of bits requested. The nbits value range is from * 1 to 32. The generic nbits value is 8, 16, 32, but this value still * depends on hardware supported. * @return 0 on success, negative errno on error */ static int tsb_spi_setbits(struct device *dev, int nbits) { struct tsb_spi_info *info = NULL; int ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { ret = -EPERM; goto err_unlock; } /* check hardware bpw capabilities */ if ((BIT(nbits - 1) & info->caps.bpw) == 0) { ret = -ENOSYS; goto err_unlock; } info->bpw = nbits; err_unlock: sem_post(&info->lock); return ret; }
/** * @brief Configure SPI mode * * The mode parameter is used to configure the clock polarity and phase of the * SPI master. This function will accept a value for one of the standard SPI * modes. If the value of the mode parameter is out of bounds or the requested * SPI mode is not supported by this hardware, an -ENOSYS error will be * returned. This function should be called after lock(); if the driver is not * in a locked state, this function will return -EPERM. * * @param dev pointer to structure of device data * @param devid the specific chip number * @param mode SPI protocol mode requested * @return 0 on success, negative errno on error */ static int tsb_spi_setmode(struct device *dev, uint8_t devid, uint16_t mode) { struct tsb_spi_dev_info *info = NULL; uint32_t ctrl0 = 0; uint16_t mode_slave; int ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); if (devid >= info->num_boards) return-EINVAL; if (info->state != TSB_SPI_STATE_LOCKED) return -EPERM; ret = device_spi_board_get_mode(info->dev_spi_board[devid], &mode_slave); if (ret) return ret; /* check hardware mode capabilities */ if (((mode & SPI_DEFAULT_MODE) != mode) && ((mode & mode_slave) != mode)) return -EINVAL; ctrl0 = tsb_spi_read(info->reg_base, DW_SPI_CTRLR0); /* set SPI clock phase */ if (mode & SPI_MODE_CPHA) ctrl0 |= SPI_CTRLR0_SCPH; else ctrl0 &= ~SPI_CTRLR0_SCPH; /* set SPI clock polarity */ if (mode & SPI_MODE_CPOL) ctrl0 |= SPI_CTRLR0_SCPOL; else ctrl0 &= ~SPI_CTRLR0_SCPOL; /* set SPI loopback mode */ if (mode & SPI_MODE_LOOP) ctrl0 |= SPI_CTRLR0_SRL; else ctrl0 &= ~SPI_CTRLR0_SRL; /* SPI CS_HIGH mode */ if (mode & SPI_MODE_CS_HIGH) info->curr_xfer.cs_high = 1; else info->curr_xfer.cs_high = 0; tsb_spi_write(info->reg_base, DW_SPI_CTRLR0, ctrl0); return ret; }
/** * @brief Configure SPI mode. * * To configure SPI configuration such as clock polarity and phase via the mode * parameter. Other possible definition of SPI mode can be found in SPI mode * definition. If the value of mode parameter is out of SPI mode definition or * this mode isn’t supported by the current hardware, this function should * return -ENOSYS error code. * This function should be called after lock(), if driver is not in lock state, * function returns -EPERM error code. * * @param dev pointer to structure of device data * @param mode SPI protocol mode requested * @return 0 on success, negative errno on error */ static int tsb_spi_setmode(struct device *dev, uint16_t mode) { struct tsb_spi_info *info = NULL; int i = 0, value = 0, ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { ret = -EPERM; goto err_unlock; } /* check hardware mode capabilities */ if (mode & ~info->caps.modes) { ret = -ENOSYS; goto err_unlock; } info->modes = mode; switch (mode & (SPI_MODE_CPHA | SPI_MODE_CPOL)) { case SPI_MODE_0: info->bitexchange = tsb_spi_bitexchange0; break; case SPI_MODE_1: info->bitexchange = tsb_spi_bitexchange1; break; case SPI_MODE_2: info->bitexchange = tsb_spi_bitexchange2; break; case SPI_MODE_3: info->bitexchange = tsb_spi_bitexchange3; break; } /* After changed SPI mode, we need to change the SCK default output level */ gpio_set_value(SPI_SCK, (mode & SPI_MODE_CPOL)? 1 : 0); /* After changed SPI mode, we need to change the CS default output level */ for (i = 0; i < info->caps.csnum; i++) { if (mode & SPI_MODE_CS_HIGH) { /* if not selected, set default CS outpot level to low */ value = (i == info->selected)? 1 : 0; } else { /* if not selected, set default CS outpot level to high */ value = (i == info->selected)? 0 : 1; } gpio_set_value(info->chipselect[i], value); } err_unlock: sem_post(&info->lock); return ret; }
/** * @brief SPI interrupt handler * * @param irq interrupt number * @param context argument for interrupt handler * @param priv attached private data * @return 0 if successful, negative error code otherwise. */ static int tsb_spi_irq_handler(int irq, void *context, void *priv) { struct device *dev = spi_dev; struct tsb_spi_dev_info *info = NULL; uint32_t isr, imr; if (!dev || !device_get_private(dev)) { return ERROR; } info = device_get_private(dev); isr = tsb_spi_read(info->reg_base, DW_SPI_ISR); imr = tsb_spi_read(info->reg_base, DW_SPI_IMR); if (!isr && !imr) { /* ignore unexpected interrupt */ return OK; } if (isr & (SPI_ISR_RXUIS_MASK | SPI_ISR_RXOIS_MASK)) { /* disable all interrupts */ tsb_spi_write(info->reg_base, DW_SPI_IMR, 0); /* clean interrupt status */ tsb_spi_read(info->reg_base, DW_SPI_RXOICR); tsb_spi_read(info->reg_base, DW_SPI_RXUICR); tsb_spi_read(info->reg_base, DW_SPI_ICR); /* abort the transfer and return error status*/ info->curr_xfer.status = -EIO; sem_post(&info->xfer_completed); return ERROR; } /* receive data */ tsb_spi_process_rx(info); if (!info->curr_xfer.rx_remaining) { /* disable Tx empty interrupt */ tsb_spi_write(info->reg_base, DW_SPI_IMR, (imr & ~SPI_ISR_TXEIS_MASK)); info->curr_xfer.status = 0; /* receive data completed */ sem_post(&info->xfer_completed); return OK; } if (isr & SPI_ISR_TXEIS_MASK) { /* disable Tx empty interrupt */ imr = tsb_spi_read(info->reg_base, DW_SPI_IMR); tsb_spi_write(info->reg_base, DW_SPI_IMR, (imr & ~SPI_ISR_TXEIS_MASK)); /* transfer data */ tsb_spi_process_tx(info); /* enable Tx empty interrupt */ tsb_spi_write(info->reg_base, DW_SPI_IMR, (imr | SPI_ISR_TXEIS_MASK)); } return OK; }
static int sensor_accel_op_flush(struct device *dev, uint8_t id) { struct sensor_event_data *event_data; struct sensor_accel_info *info; struct report_info_data *rinfo_data; struct report_info *rinfo; struct timespec ts; uint16_t payload_size; payload_size = (PRESSURE_READING_NUM * sizeof(struct sensor_event_data)) + (REPORTING_SENSORS * sizeof(struct report_info)); gb_debug("%s:\n", __func__); if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); if (info->callback) { rinfo_data = malloc(sizeof(struct report_info) + payload_size); if (!rinfo_data) return -ENOMEM; rinfo_data->num_sensors_reporting = REPORTING_SENSORS; rinfo = rinfo_data->reportinfo; rinfo->id = info->sensor_id; event_data = (struct sensor_event_data *)&rinfo->data_payload[0]; up_rtc_gettime(&ts); rinfo->reference_time = timespec_to_nsec(&ts); gb_debug("[%u.%03u]\n", ts.tv_sec, (ts.tv_nsec / 1000000)); rinfo->flags = REPORT_INFO_FLAG_FLUSHING | REPORT_INFO_FLAG_FLUSH_COMPLETE; #ifdef BATCH_PROCESS_ENABLED /* * Batch sensor data values and its time_deltas * until max fifo event count */ #else /* Single sensor event data */ rinfo->readings = PRESSURE_READING_NUM; event_data->time_delta = 0; event_data->data_value[0] = data++; event_data->data_value[1] = data++; event_data->data_value[2] = data++; #endif info->callback(info->sensor_id, rinfo_data, payload_size); free(rinfo_data); } return OK; }
/** * @brief Close SPI device * * This function is called when the caller no longer using this driver. It * should release or close all resources that allocated by the open() function. * This function should be called after the open() function. If the device * is not opened yet, this function should return without any operations. * * @param dev pointer to structure of device data */ static void tsb_spi_dev_close(struct device *dev) { struct tsb_spi_info *info = NULL; /* check input parameter */ if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); info->state = TSB_SPI_STATE_CLOSED; }
/** * @brief unlock SPI bus for exclusive access * * @param dev pointer to structure of device data * @return 0 on success, negative errno on error */ static int tsb_spi_unlock(struct device *dev) { struct tsb_spi_dev_info *info = NULL; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); info->state = TSB_SPI_STATE_OPEN; sem_post(&info->bus); return 0; }
/** * @brief Get SPI device driver hardware capabilities information. * * This function can be called whether lock() has been called or not. * * @param dev pointer to structure of device data * @param caps pointer to the spi_caps structure to receive the capabilities * information. * @return 0 on success, negative errno on error */ static int tsb_spi_getcaps(struct device *dev, struct device_spi_caps *caps) { struct tsb_spi_info *info = NULL; /* check input parameters */ if (!dev || !device_get_private(dev) || !caps) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); memcpy(caps, &info->caps, sizeof(struct device_spi_caps)); sem_post(&info->lock); return 0; }
static int tsb_spi_pm_prepare(struct pm_callback_s *cb, enum pm_state_e pmstate) { struct tsb_spi_dev_info *info = NULL; struct device *dev; irqstate_t flags; dev = cb->priv; info = device_get_private(dev); flags = irqsave(); switch (pmstate) { case PM_NORMAL: case PM_IDLE: case PM_STANDBY: /* Nothing to do in idle or standby. */ break; case PM_SLEEP: if (info->curr_xfer.rx_remaining) { /* return not ready to SLEEP because exchange not complete yet */ irqrestore(flags); return -EIO; } break; default: /* Can never happen. */ PANIC(); } irqrestore(flags); return OK; }
static int sensor_accel_op_register_callback(struct device *dev, uint8_t se_id, sensors_ext_event_callback callback) { struct sensor_accel_info *info = NULL; gb_debug("%s:\n", __func__); if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); info->callback = callback; info->sensor_id = se_id; return 0; }
/** * @brief Configure SPI clock * * If SPI hardware doesn’t support this frequency value, this function should * find the nearest lower frequency that is hardware supported and then * configure SPI clock to this value. It will return the actual frequency * selected value back to the caller via parameter frequency. * This function should be called after lock(); if the driver is not in lock * state, it returns an error code to notify a problem. * * @param dev pointer to structure of device data * @param devid the specific chip number * @param frequency SPI frequency requested (unit: Hz) * @return 0 on success, negative errno on error */ static int tsb_spi_setfrequency(struct device *dev, uint8_t devid, uint32_t *frequency) { struct tsb_spi_dev_info *info = NULL; uint32_t freq; uint32_t max_freq_slave; uint32_t div; int ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev) || !frequency || !(*frequency)) { return -EINVAL; } info = device_get_private(dev); if (devid >= info->num_boards) return -EINVAL; if (info->state != TSB_SPI_STATE_LOCKED) return -EPERM; freq = *frequency; ret = device_spi_board_get_max_speed_hz(info->dev_spi_board[devid], &max_freq_slave); if (ret) return ret; /* check the frequency range */ if (freq > SPI_MAX_FREQ || freq < SPI_MIN_FREQ || freq > max_freq_slave) return -EINVAL; div = SPI_BUS_CLOCK / freq; /* the 'div' doesn't support odd numbers */ div = (div + 1) & 0xFFFE; if (div > SPI_MAX_DIV) return -EINVAL; freq = SPI_BUS_CLOCK / div; tsb_spi_write(info->reg_base, DW_SPI_BAUDR, div); *frequency = freq; return ret; }
static int sensor_accel_op_get_sensor_info(struct device *dev, uint8_t sensor_id, struct sensor_info *sinfo) { struct sensor_accel_info *info = NULL; gb_debug("%s: %d\n",__func__, sensor_id); if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); info->sensor_id = sensor_id; sinfo->version = ACCEL_VERSION; sinfo->max_range = ACCEL_MAX_RANGE; sinfo->resolution = 1; sinfo->min_delay = ACCEL_MIN_DELAY; sinfo->max_delay = ACCEL_MAX_DELAY; #ifdef BATCH_PROCESS_ENABLED /* * Example to calculate number of sensor events that can be batched in the * payload. Each event consists of time_delta and sensor data fields. * Reading size provides the number of sensor data fields reported. */ sinfo->fifo_rec = PRESSURE_READING_NUM; sinfo->fifo_mec = sinfo->fifo_rec; #else sinfo->fifo_rec = ACCEL_FIFO_REC; sinfo->fifo_mec = ACCEL_FIFO_MEC; #endif sinfo->flags = ACCEL_FLAGS; sinfo->scale_int = ACCEL_SCALE_INT; sinfo->scale_nano = ACCEL_SCALE_NANO; sinfo->offset_int = ACCEL_OFFSET_INT; sinfo->offset_nano = ACCEL_OFFSET_NANO; sinfo->channels = ACCEL_CHANNEL_SIZE; sinfo->type = ACCELEROMETER_ID; sinfo->name_len = sizeof(ACCEL_DEVICE_NAME); memcpy(&sinfo->name[0], ACCEL_DEVICE_NAME, sizeof(ACCEL_DEVICE_NAME)); sinfo->vendor_len = sizeof(ACCEL_VENDOR_NAME); memcpy(&sinfo->vendor[0], ACCEL_VENDOR_NAME, sizeof(ACCEL_VENDOR_NAME)); sinfo->string_type_len = 0; return OK; }
/** * @brief Hardware initialization * * The function initializes the GPIO pins used in the bit-bang interface and * also assigned a default output value for SPI signal. * * @param dev pointer to structure of device data * @return 0 on success, negative errno on error */ static int tsb_spi_hw_init(struct device *dev) { struct tsb_spi_info *info = NULL; int i = 0; int retval; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); retval = tsb_request_pinshare(TSB_PIN_GPIO10); if (retval) { lowsyslog("SPI: cannot get ownership of GPIO10 pin.\n"); return retval; } /* backup pinshare#5 setting */ info->pinshare = tsb_get_pinshare(); /* set pinshare#5 (DBG) to normal GPIO */ if (!(info->pinshare & TSB_PIN_GPIO10)) { tsb_set_pinshare(TSB_PIN_GPIO10); } /* setup GPIO pins */ gpio_activate(SPI_SCK); gpio_direction_out(SPI_SCK, 0); gpio_activate(SPI_SDI); gpio_direction_in(SPI_SDI); gpio_activate(SPI_SDO); gpio_direction_out(SPI_SDO, 0); /* setup all chip-select pins */ for (i = 0; i < info->caps.csnum; i++) { gpio_activate(info->chipselect[i]); gpio_direction_out(info->chipselect[i], 1); } return 0; }
static int sensor_accel_dev_open(struct device *dev) { struct sensor_accel_info *info = NULL; gb_debug("%s:\n", __func__); if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); if (info->flags & SENSOR_ACCEL_FLAG_OPEN) { return -EBUSY; } info->flags |= SENSOR_ACCEL_FLAG_OPEN; return 0; }
/** * @brief Disable the SPI chip select pin * * The implementation of this method must include handshaking. If a device is * selected, it must hold off all the other attempts to select the device * until the device is deselected. This function should be called after lock(), * if the driver isn’t in lock state, it returns an error code to notify a * problem. * * @param dev pointer to structure of device data * @param devid identifier of a selected SPI slave device * @return 0 on success, negative errno on error */ static int tsb_spi_deselect(struct device *dev, int devid) { struct tsb_spi_info *info = NULL; int i = 0, ret = 0; bool selected = false; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { ret = -EPERM; goto err_unlock; } if (info->modes & SPI_MODE_NO_CS) { ret = -EINVAL; goto err_unlock; } if (devid > info->caps.csnum) { ret = -EINVAL; goto err_unlock; } info->selected = -1; if (!(info->modes & SPI_MODE_CS_HIGH)) { selected = true; } for (i = 0; i < info->caps.csnum; i++) { /* deactive all chip-select pin */ gpio_set_value(info->chipselect[i], selected); } err_unlock: sem_post(&info->lock); return ret; }
/** * @brief Remove SPI device * * This function is called by the system to unregister the driver. It should * release the hardware resource and interrupt setting, and then free memory * that was allocated by the probe() function. * This function should be called after probe() function. If driver was opened, * this function should call close() function before releasing resources. * * @param dev pointer to structure of device data */ static void tsb_spi_dev_remove(struct device *dev) { struct tsb_spi_dev_info *info = NULL; /* check input parameter */ if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); info->state = TSB_SPI_STATE_INVALID; sem_destroy(&info->lock); sem_destroy(&info->bus); sem_destroy(&info->xfer_completed); device_set_private(dev, NULL); spi_dev = NULL; free(info); }
static void sensor_accel_dev_remove(struct device *dev) { struct sensor_accel_info *info = NULL; gb_debug("%s:\n",__func__); if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); if (info->flags & SENSOR_ACCEL_FLAG_OPEN) { sensor_accel_dev_close(dev); } info->flags = 0; free(info); device_set_private(dev, NULL); }
/** * @brief Remove SPI device * * This function is called by the system to unregister the driver. It should * release the hardware resource and interrupt setting, and then free memory * that allocated by the probe() function. * This function should be called after probe() function. If driver was opened, * this function should call close() function before releasing resources. * * @param dev pointer to structure of device data */ static void tsb_spi_dev_remove(struct device *dev) { struct tsb_spi_info *info = NULL; /* check input parameter */ if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); info->state = TSB_SPI_STATE_INVALID; sem_destroy(&info->lock); sem_destroy(&info->bus); /* deinitialize gpio pins */ tsb_spi_hw_deinit(dev); device_set_private(dev, NULL); free(info); }
static int sensor_accel_op_stop_reporting(struct device *dev, uint8_t sensor_id) { struct sensor_accel_info *info = NULL; gb_debug("%s:\n",__func__); if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); /* cancel any work and reset ourselves */ if (!work_available(&info->data_report_work)) work_cancel(LPWORK, &info->data_report_work); atomic_dec(&txn); return OK; }
/** * @brief Enable the SPI chip select pin * * The implementation of this method must include handshaking. If a device is * selected, it must hold off all the other attempts to select the device * until the device is deselected. This function should be called after lock(); * if the driver isn’t in lock state, it returns an error code to notify a * problem. * * @param dev pointer to structure of device data * @param devid identifier of a selected SPI slave device * @return 0 on success, negative errno on error */ static int tsb_spi_select(struct device *dev, uint8_t devid) { struct tsb_spi_dev_info *info = NULL; int ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { ret = -EPERM; goto err_select; } if (devid >= info->num_boards) { ret = -EINVAL; goto err_select; } #if defined(CONFIG_TSB_SPI_GPIO) /* from the SPI master's point of view, we fake that we're always talking to * slave #1. The trick is that by default, CS1 doesn't belong to the SPI * master, so the transaction will still be initiated and meanwhile we can * manually set up the devid with GPIOs the way we want. */ tsb_spi_write(info->reg_base, DW_SPI_SER, 0x2); #else /* otherwise we really select the slave through the SPI master */ tsb_spi_write(info->reg_base, DW_SPI_SER, (1 << devid)); #endif ret = device_spi_board_cs_select(info->dev_spi_board[devid], info->curr_xfer.cs_high); err_select: sem_post(&info->lock); return ret; }
static void sensor_accel_dev_close(struct device *dev) { struct sensor_accel_info *info = NULL; gb_debug("%s:\n",__func__); if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); /* cancel any pending events */ if (!work_available(&info->data_report_work)) work_cancel(LPWORK, &info->data_report_work); if (!(info->flags & SENSOR_ACCEL_FLAG_OPEN)) { return; } info->flags &= ~SENSOR_ACCEL_FLAG_OPEN; }
/** * @brief Configure SPI clock. * * If SPI hardware doesn’t support this frequency value, this function should * find the nearest lower frequency in which hardware supported and then * configure SPI clock to this value. It will return the actual frequency * selected value back to the caller via parameter frequency. * This function should be called after lock(), if the driver is not in lock * state, it returns an error code to notify a problem. * * @param dev pointer to structure of device data * @param frequency SPI frequency requested (unit: Hz) * @return 0 on success, negative errno on error */ static int tsb_spi_setfrequency(struct device *dev, uint32_t *frequency) { struct tsb_spi_info *info = NULL; /* check input parameters */ if (!dev || !device_get_private(dev) || !frequency) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { sem_post(&info->lock); return -EPERM; } info->frequency = *frequency; /* We only supported SPI frequency from 1KHz to 500KHz */ if (info->frequency <= 1000) { info->frequency = 1000; } if (info->frequency >= 500000) { info->frequency = 500000; } /* calc holdtime */ info->holdtime = 500000 / info->frequency; if (info->holdtime > XFER_OVERHEAD) { info->holdtime = info->holdtime - XFER_OVERHEAD; } else { info->holdtime = 0; } *frequency = info->frequency; sem_post(&info->lock); return 0; }
static int tsb_spi_resume(struct device *dev) { struct tsb_spi_dev_info *info; info = device_get_private(dev); tsb_clk_enable(TSB_CLK_SPIP); tsb_clk_enable(TSB_CLK_SPIS); info->spi_pmstate = PM_NORMAL; return 0; }
/** * @brief Exchange a block of data from SPI * * Device driver uses this function to transfer and receive data from SPI bus. * This function should be called after lock() , if the driver is not in lock * state, it returns -EPERM error code. * The transfer structure is consists of the read/write buffer,transfer length, * transfer flags and callback function. * * @param dev pointer to structure of device data * @param transfer pointer to the spi transfer request * @return 0 on success, negative errno on error */ static int tsb_spi_exchange(struct device *dev, struct device_spi_transfer *transfer) { struct tsb_spi_info *info = NULL; int ret = 0; /* check input parameters */ if (!dev || !device_get_private(dev) || !transfer) { return -EINVAL; } /* check transfer buffer */ if(!transfer->txbuffer && !transfer->rxbuffer) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_LOCKED) { ret = -EPERM; goto err_unlock; } if (info->bpw <= 8) { tsb_spi_transfer_8(info, transfer); } else if (info->bpw <= 16) { tsb_spi_transfer_16(info, transfer); } else if (info->bpw <= 32) { tsb_spi_transfer_32(info, transfer); } else { ret = -EINVAL; } err_unlock: sem_post(&info->lock); return ret; }