Exemplo n.º 1
0
SOL_API struct sol_i2c *
sol_i2c_open_raw(uint8_t bus, enum sol_i2c_speed speed)
{
    struct sol_i2c *i2c;
    qm_i2c_config_t cfg;
    qm_i2c_speed_t bus_speed;
    qm_rc_t ret;

    if (bus >= QM_I2C_NUM) {
        SOL_WRN("I2C bus #%" PRIu8 " doesn't exist.", bus);
        return NULL;
    }

    if ((i2c = buses[bus]) != NULL)
        return i2c;

    switch (speed) {
    case SOL_I2C_SPEED_10KBIT:
    case SOL_I2C_SPEED_100KBIT:
        bus_speed = QM_I2C_SPEED_STD;
        break;
    case SOL_I2C_SPEED_400KBIT:
        bus_speed = QM_I2C_SPEED_FAST;
        break;
    case SOL_I2C_SPEED_1MBIT:
    case SOL_I2C_SPEED_3MBIT_400KBIT:
        bus_speed = QM_I2C_SPEED_FAST_PLUS;
        break;
    default:
        SOL_WRN("Unsupported speed value: %d", speed);
        return NULL;
    };

    switch (bus) {
    case QM_I2C_0:
        qm_irq_request(QM_IRQ_I2C_0, qm_i2c_0_isr);
        clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_I2C_M0_REGISTER);
        break;
#if QUARK_SE
    case QM_I2C_1:
        qm_irq_request(QM_IRQ_I2C_1, qm_i2c_1_isr);
        clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_I2C_M1_REGISTER);
        break;
#endif
    case QM_I2C_NUM:
        /* We checked if we were passed the limit before, so we should never
         * hit this point. Using all the enum values and no default, however,
         * allows us to rely on the compiler to know if there are values
         * we are not considering (depending on warning levels) */
        break;
    }

    i2c = calloc(1, sizeof(*i2c));
    SOL_NULL_CHECK(i2c, NULL);

    i2c->bus = bus;

    ret = qm_i2c_get_config(i2c->bus, &cfg);
    SOL_EXP_CHECK_GOTO(ret != QM_RC_OK, error);

    cfg.speed = bus_speed;
    cfg.address_mode = QM_I2C_7_BIT;
    cfg.mode = QM_I2C_MASTER;
    cfg.slave_addr = 0;

    ret = qm_i2c_set_config(i2c->bus, &cfg);
    SOL_EXP_CHECK_GOTO(ret != QM_RC_OK, error);

    if (!i2c_irq_event) {
        bool r;

        i2c_irq_event = process_alloc_event();
        r = sol_mainloop_contiki_event_handler_add(&i2c_irq_event, NULL,
            i2c_cb_dispatch, NULL);
        SOL_EXP_CHECK_GOTO(!r, error);
    }

    buses[i2c->bus] = i2c;

    return i2c;

error:
    free(i2c);
    return NULL;
}
Exemplo n.º 2
0
SOL_API struct sol_spi *
sol_spi_open(unsigned int bus, const struct sol_spi_config *config)
{
    struct sol_spi *spi;
    qm_spi_t max_bus_available;
    int ret;

    SOL_LOG_INTERNAL_INIT_ONCE;

    /* QM_SPI_NUM is always considering that both master and the slave
     * exist, so we can't use it to check the valid buses to use */
#if QUARK_SE
    max_bus_available = QM_SPI_MST_1;
#else
    max_bus_available = QM_SPI_MST_0;
#endif

    SOL_EXP_CHECK(bus >= max_bus_available, NULL);
    SOL_NULL_CHECK(config, NULL);

#ifndef SOL_NO_API_VERSION
    if (unlikely(config->api_version != SOL_SPI_CONFIG_API_VERSION)) {
        SOL_WRN("Couldn't open SPI that has unsupported version '%u', "
            "expected version is '%u'",
            config->api_version, SOL_SPI_CONFIG_API_VERSION);
        return NULL;
    }
#endif

    if (config->chip_select > 3) {
        SOL_WRN("Invalid chip_select value '%u'. Value must be between 0 and 3.",
            config->chip_select);
        return NULL;
    }

    if ((config->bits_per_word < 4) || (config->bits_per_word > 32)) {
        SOL_WRN("Invalid bits_per_word value '%" PRIu8 "'. Value must be "
            "between 4 and 32.", config->bits_per_word);
        return NULL;
    }

    spi = calloc(1, sizeof(*spi));
    SOL_NULL_CHECK(spi, NULL);

    if (!spi_irq_event) {
        bool r;

        spi_irq_event = process_alloc_event();
        r = sol_mainloop_contiki_event_handler_add(&spi_irq_event, NULL,
            spi_cb_dispatch, NULL);
        SOL_EXP_CHECK_GOTO(!r, error);
    }

    spi->bus = bus;
    spi->slave = BIT(config->chip_select);
    spi->config.frame_size = config->bits_per_word - 1;
    spi->config.transfer_mode = QM_SPI_TMOD_TX_RX;
    spi->config.bus_mode = config->mode;
    spi->config.clk_divider = 32000000 / config->frequency;

    switch (spi->bus) {
    case QM_SPI_MST_0:
        clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_SPI_M0_REGISTER);
        qm_irq_request(QM_IRQ_SPI_MASTER_0, qm_spi_master_0_isr);
        break;
#if QUARK_SE
    case QM_SPI_MST_1:
        qm_irq_request(QM_IRQ_SPI_MASTER_1, qm_spi_master_1_isr);
        break;
#endif
    case QM_SPI_SLV_0:
    case QM_SPI_NUM:
        /* We checked if we were passed the limit before, so we should never
         * hit this point. Using all the enum values and no default, however,
         * allows us to rely on the compiler to know if there are values
         * we are not considering (depending on warning levels) */
        break;
    }

    ret = spi_set_gpio_ss(spi);
    SOL_INT_CHECK_GOTO(ret, < 0, error);

    return spi;

error:
    free(spi);
    return NULL;
}