1 /*
2  * Copyright (c) 2022 Meta
3  * Copyright (c) 2024 SILA Embedded Solutions GmbH
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/logging/log.h>
10 
11 #include "fpga_ice40_common.h"
12 
13 LOG_MODULE_REGISTER(fpga_ice40);
14 
fpga_ice40_crc_to_str(uint32_t crc,char * s)15 void fpga_ice40_crc_to_str(uint32_t crc, char *s)
16 {
17 	char ch;
18 	uint8_t i;
19 	uint8_t nibble;
20 	const char *table = "0123456789abcdef";
21 
22 	for (i = 0; i < sizeof(crc) * NIBBLES_PER_BYTE; ++i, crc >>= BITS_PER_NIBBLE) {
23 		nibble = crc & GENMASK(BITS_PER_NIBBLE, 0);
24 		ch = table[nibble];
25 		s[sizeof(crc) * NIBBLES_PER_BYTE - i - 1] = ch;
26 	}
27 
28 	s[sizeof(crc) * NIBBLES_PER_BYTE] = '\0';
29 }
30 
fpga_ice40_get_status(const struct device * dev)31 enum FPGA_status fpga_ice40_get_status(const struct device *dev)
32 {
33 	enum FPGA_status st;
34 	k_spinlock_key_t key;
35 	struct fpga_ice40_data *data = dev->data;
36 
37 	key = k_spin_lock(&data->lock);
38 
39 	if (data->loaded && data->on) {
40 		st = FPGA_STATUS_ACTIVE;
41 	} else {
42 		st = FPGA_STATUS_INACTIVE;
43 	}
44 
45 	k_spin_unlock(&data->lock, key);
46 
47 	return st;
48 }
49 
fpga_ice40_on_off(const struct device * dev,bool on)50 static int fpga_ice40_on_off(const struct device *dev, bool on)
51 {
52 	int ret;
53 	k_spinlock_key_t key;
54 	struct fpga_ice40_data *data = dev->data;
55 	const struct fpga_ice40_config *config = dev->config;
56 
57 	key = k_spin_lock(&data->lock);
58 
59 	ret = gpio_pin_configure_dt(&config->creset, on ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW);
60 	if (ret < 0) {
61 		goto unlock;
62 	}
63 
64 	data->on = on;
65 	ret = 0;
66 
67 unlock:
68 	k_spin_unlock(&data->lock, key);
69 
70 	return ret;
71 }
72 
fpga_ice40_on(const struct device * dev)73 int fpga_ice40_on(const struct device *dev)
74 {
75 	return fpga_ice40_on_off(dev, true);
76 }
77 
fpga_ice40_off(const struct device * dev)78 int fpga_ice40_off(const struct device *dev)
79 {
80 	return fpga_ice40_on_off(dev, false);
81 }
82 
fpga_ice40_reset(const struct device * dev)83 int fpga_ice40_reset(const struct device *dev)
84 {
85 	return fpga_ice40_off(dev) || fpga_ice40_on(dev);
86 }
87 
fpga_ice40_get_info(const struct device * dev)88 const char *fpga_ice40_get_info(const struct device *dev)
89 {
90 	struct fpga_ice40_data *data = dev->data;
91 
92 	return data->info;
93 }
94 
fpga_ice40_init(const struct device * dev)95 int fpga_ice40_init(const struct device *dev)
96 {
97 	int ret;
98 	const struct fpga_ice40_config *config = dev->config;
99 
100 	if (!device_is_ready(config->creset.port)) {
101 		LOG_ERR("%s: GPIO for creset is not ready", dev->name);
102 		return -ENODEV;
103 	}
104 
105 	if (!device_is_ready(config->cdone.port)) {
106 		LOG_ERR("%s: GPIO for cdone is not ready", dev->name);
107 		return -ENODEV;
108 	}
109 
110 	ret = gpio_pin_configure_dt(&config->creset, GPIO_OUTPUT_HIGH);
111 	if (ret < 0) {
112 		LOG_ERR("failed to configure CRESET: %d", ret);
113 		return ret;
114 	}
115 
116 	ret = gpio_pin_configure_dt(&config->cdone, GPIO_INPUT);
117 	if (ret < 0) {
118 		LOG_ERR("Failed to initialize CDONE: %d", ret);
119 		return ret;
120 	}
121 
122 	return 0;
123 }
124