zephyr/drivers/fpga/fpga_ice40_common.c
Benedikt Schmidt 760210f39d drivers: fpga: separate drivers of iCE40 for SPI and GPIO bitbang
Separate the current driver for the FPGA iCE40 into two different ones.
One implements only the SPI load mode, the other one only the GPIO
bitbang mode.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
2024-11-28 15:39:33 +00:00

123 lines
2.4 KiB
C

/*
* Copyright (c) 2022 Meta
* Copyright (c) 2024 SILA Embedded Solutions GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include "fpga_ice40_common.h"
LOG_MODULE_REGISTER(fpga_ice40);
void fpga_ice40_crc_to_str(uint32_t crc, char *s)
{
char ch;
uint8_t i;
uint8_t nibble;
const char *table = "0123456789abcdef";
for (i = 0; i < sizeof(crc) * NIBBLES_PER_BYTE; ++i, crc >>= BITS_PER_NIBBLE) {
nibble = crc & GENMASK(BITS_PER_NIBBLE, 0);
ch = table[nibble];
s[sizeof(crc) * NIBBLES_PER_BYTE - i - 1] = ch;
}
s[sizeof(crc) * NIBBLES_PER_BYTE] = '\0';
}
enum FPGA_status fpga_ice40_get_status(const struct device *dev)
{
enum FPGA_status st;
k_spinlock_key_t key;
struct fpga_ice40_data *data = dev->data;
key = k_spin_lock(&data->lock);
if (data->loaded && data->on) {
st = FPGA_STATUS_ACTIVE;
} else {
st = FPGA_STATUS_INACTIVE;
}
k_spin_unlock(&data->lock, key);
return st;
}
static int fpga_ice40_on_off(const struct device *dev, bool on)
{
int ret;
k_spinlock_key_t key;
struct fpga_ice40_data *data = dev->data;
const struct fpga_ice40_config *config = dev->config;
key = k_spin_lock(&data->lock);
ret = gpio_pin_configure_dt(&config->creset, on ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW);
if (ret < 0) {
goto unlock;
}
data->on = on;
ret = 0;
unlock:
k_spin_unlock(&data->lock, key);
return ret;
}
int fpga_ice40_on(const struct device *dev)
{
return fpga_ice40_on_off(dev, true);
}
int fpga_ice40_off(const struct device *dev)
{
return fpga_ice40_on_off(dev, false);
}
int fpga_ice40_reset(const struct device *dev)
{
return fpga_ice40_off(dev) || fpga_ice40_on(dev);
}
const char *fpga_ice40_get_info(const struct device *dev)
{
struct fpga_ice40_data *data = dev->data;
return data->info;
}
int fpga_ice40_init(const struct device *dev)
{
int ret;
const struct fpga_ice40_config *config = dev->config;
if (!device_is_ready(config->creset.port)) {
LOG_ERR("%s: GPIO for creset is not ready", dev->name);
return -ENODEV;
}
if (!device_is_ready(config->cdone.port)) {
LOG_ERR("%s: GPIO for cdone is not ready", dev->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(&config->creset, GPIO_OUTPUT_HIGH);
if (ret < 0) {
LOG_ERR("failed to configure CRESET: %d", ret);
return ret;
}
ret = gpio_pin_configure_dt(&config->cdone, GPIO_INPUT);
if (ret < 0) {
LOG_ERR("Failed to initialize CDONE: %d", ret);
return ret;
}
return 0;
}