Esempio n. 1
0
/**
 * @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;
}
Esempio n. 2
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);
}
Esempio n. 3
0
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;
}
Esempio n. 4
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, 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;
}
Esempio n. 5
0
/**
 * @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;
}
Esempio n. 6
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;
}
Esempio n. 7
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;
}
Esempio n. 8
0
/**
 * @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;
}
Esempio n. 9
0
/**
 * @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;
}
Esempio n. 10
0
/**
 * @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;
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
/**
 * @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;
}
Esempio n. 13
0
/**
 * @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;
}
Esempio n. 14
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;
}
Esempio n. 15
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
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;
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
/**
 * @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;
}
Esempio n. 20
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;
}
Esempio n. 21
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;
}
Esempio n. 22
0
/**
 * @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);
}
Esempio n. 23
0
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);
}
Esempio n. 24
0
/**
 * @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);
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
/**
 * @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;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
/**
 * @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;
}
Esempio n. 29
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;
}
Esempio n. 30
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;
}