summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/bluefruit_le.cpp (renamed from drivers/bluetooth/adafruit_ble.cpp)64
-rw-r--r--drivers/bluetooth/bluefruit_le.h (renamed from drivers/bluetooth/adafruit_ble.h)20
-rw-r--r--drivers/bluetooth/outputselect.c21
-rw-r--r--drivers/bluetooth/rn42.c99
-rw-r--r--drivers/bluetooth/rn42.h25
-rw-r--r--drivers/flash/flash_spi.c372
-rw-r--r--drivers/flash/flash_spi.h136
-rw-r--r--drivers/gpio/mcp23018.c108
-rw-r--r--drivers/gpio/mcp23018.h65
-rw-r--r--drivers/gpio/pca9555.c61
-rw-r--r--drivers/gpio/pca9555.h81
-rw-r--r--drivers/gpio/sn74x138.c65
-rw-r--r--drivers/gpio/sn74x138.h48
-rw-r--r--drivers/led/ckled2001.c11
-rw-r--r--drivers/led/issi/is31fl3733-simple.c248
-rw-r--r--drivers/led/issi/is31fl3733-simple.h260
-rw-r--r--drivers/led/issi/is31fl3742.h299
-rw-r--r--drivers/led/issi/is31fl3743.h327
-rw-r--r--drivers/led/issi/is31fl3745.h270
-rw-r--r--drivers/led/issi/is31fl3746.h198
-rw-r--r--drivers/led/issi/is31flcommon.c230
-rw-r--r--drivers/led/issi/is31flcommon.h78
-rw-r--r--drivers/sensors/adns9800.c16
-rw-r--r--drivers/sensors/adns9800_srom_A6.h2
-rw-r--r--drivers/sensors/pimoroni_trackball.c22
-rw-r--r--drivers/sensors/pimoroni_trackball.h9
-rw-r--r--drivers/sensors/pmw3360.c283
-rw-r--r--drivers/sensors/pmw3360.h35
-rw-r--r--drivers/sensors/pmw3389.c292
-rw-r--r--drivers/sensors/pmw3389.h76
-rw-r--r--drivers/sensors/pmw3389_firmware.h558
-rw-r--r--drivers/serial.h19
32 files changed, 3808 insertions, 590 deletions
diff --git a/drivers/bluetooth/adafruit_ble.cpp b/drivers/bluetooth/bluefruit_le.cpp
index 34a780e9a5..86581a1a48 100644
--- a/drivers/bluetooth/adafruit_ble.cpp
+++ b/drivers/bluetooth/bluefruit_le.cpp
@@ -1,4 +1,4 @@
-#include "adafruit_ble.h"
+#include "bluefruit_le.h"
#include <stdio.h>
#include <stdlib.h>
@@ -16,20 +16,20 @@
// These are the pin assignments for the 32u4 boards.
// You may define them to something else in your config.h
// if yours is wired up differently.
-#ifndef ADAFRUIT_BLE_RST_PIN
-# define ADAFRUIT_BLE_RST_PIN D4
+#ifndef BLUEFRUIT_LE_RST_PIN
+# define BLUEFRUIT_LE_RST_PIN D4
#endif
-#ifndef ADAFRUIT_BLE_CS_PIN
-# define ADAFRUIT_BLE_CS_PIN B4
+#ifndef BLUEFRUIT_LE_CS_PIN
+# define BLUEFRUIT_LE_CS_PIN B4
#endif
-#ifndef ADAFRUIT_BLE_IRQ_PIN
-# define ADAFRUIT_BLE_IRQ_PIN E6
+#ifndef BLUEFRUIT_LE_IRQ_PIN
+# define BLUEFRUIT_LE_IRQ_PIN E6
#endif
-#ifndef ADAFRUIT_BLE_SCK_DIVISOR
-# define ADAFRUIT_BLE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
+#ifndef BLUEFRUIT_LE_SCK_DIVISOR
+# define BLUEFRUIT_LE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
#endif
#define SAMPLE_BATTERY
@@ -143,7 +143,7 @@ static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool ver
// Send a single SDEP packet
static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
- spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
+ spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
uint16_t timerStart = timer_read();
bool success = false;
bool ready = false;
@@ -157,7 +157,7 @@ static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
// Release it and let it initialize
spi_stop();
wait_us(SdepBackOff);
- spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
+ spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
} while (timer_elapsed(timerStart) < timeout);
if (ready) {
@@ -190,7 +190,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
bool ready = false;
do {
- ready = readPin(ADAFRUIT_BLE_IRQ_PIN);
+ ready = readPin(BLUEFRUIT_LE_IRQ_PIN);
if (ready) {
break;
}
@@ -198,7 +198,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
} while (timer_elapsed(timerStart) < timeout);
if (ready) {
- spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
+ spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
do {
// Read the command type, waiting for the data to be ready
@@ -207,7 +207,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
// Release it and let it initialize
spi_stop();
wait_us(SdepBackOff);
- spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
+ spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
continue;
}
@@ -233,7 +233,7 @@ static void resp_buf_read_one(bool greedy) {
return;
}
- if (readPin(ADAFRUIT_BLE_IRQ_PIN)) {
+ if (readPin(BLUEFRUIT_LE_IRQ_PIN)) {
struct sdep_msg msg;
again:
@@ -244,7 +244,7 @@ static void resp_buf_read_one(bool greedy) {
dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
}
- if (greedy && resp_buf.peek(last_send) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
+ if (greedy && resp_buf.peek(last_send) && readPin(BLUEFRUIT_LE_IRQ_PIN)) {
goto again;
}
}
@@ -295,16 +295,16 @@ static bool ble_init(void) {
state.configured = false;
state.is_connected = false;
- setPinInput(ADAFRUIT_BLE_IRQ_PIN);
+ setPinInput(BLUEFRUIT_LE_IRQ_PIN);
spi_init();
// Perform a hardware reset
- setPinOutput(ADAFRUIT_BLE_RST_PIN);
- writePinHigh(ADAFRUIT_BLE_RST_PIN);
- writePinLow(ADAFRUIT_BLE_RST_PIN);
+ setPinOutput(BLUEFRUIT_LE_RST_PIN);
+ writePinHigh(BLUEFRUIT_LE_RST_PIN);
+ writePinLow(BLUEFRUIT_LE_RST_PIN);
wait_ms(10);
- writePinHigh(ADAFRUIT_BLE_RST_PIN);
+ writePinHigh(BLUEFRUIT_LE_RST_PIN);
wait_ms(1000); // Give it a second to initialize
@@ -424,9 +424,9 @@ bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
return at_command(cmdbuf, resp, resplen, verbose);
}
-bool adafruit_ble_is_connected(void) { return state.is_connected; }
+bool bluefruit_le_is_connected(void) { return state.is_connected; }
-bool adafruit_ble_enable_keyboard(void) {
+bool bluefruit_le_enable_keyboard(void) {
char resbuf[128];
if (!state.initialized && !ble_init()) {
@@ -498,16 +498,16 @@ static void set_connected(bool connected) {
}
}
-void adafruit_ble_task(void) {
+void bluefruit_le_task(void) {
char resbuf[48];
- if (!state.configured && !adafruit_ble_enable_keyboard()) {
+ if (!state.configured && !bluefruit_le_enable_keyboard()) {
return;
}
resp_buf_read_one(true);
send_buf_send_one(SdepShortTimeout);
- if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
+ if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(BLUEFRUIT_LE_IRQ_PIN)) {
// Must be an event update
if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
uint32_t mask = strtoul(resbuf, NULL, 16);
@@ -609,7 +609,7 @@ static bool process_queue_item(struct queue_item *item, uint16_t timeout) {
}
}
-void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
+void bluefruit_le_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
struct queue_item item;
bool didWait = false;
@@ -643,7 +643,7 @@ void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nk
}
}
-void adafruit_ble_send_consumer_key(uint16_t usage) {
+void bluefruit_le_send_consumer_key(uint16_t usage) {
struct queue_item item;
item.queue_type = QTConsumer;
@@ -655,7 +655,7 @@ void adafruit_ble_send_consumer_key(uint16_t usage) {
}
#ifdef MOUSE_ENABLE
-void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
+void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
struct queue_item item;
item.queue_type = QTMouseMove;
@@ -671,9 +671,9 @@ void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan,
}
#endif
-uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; }
+uint32_t bluefruit_le_read_battery_voltage(void) { return state.vbat; }
-bool adafruit_ble_set_mode_leds(bool on) {
+bool bluefruit_le_set_mode_leds(bool on) {
if (!state.configured) {
return false;
}
@@ -689,7 +689,7 @@ bool adafruit_ble_set_mode_leds(bool on) {
}
// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel
-bool adafruit_ble_set_power_level(int8_t level) {
+bool bluefruit_le_set_power_level(int8_t level) {
char cmd[46];
if (!state.configured) {
return false;
diff --git a/drivers/bluetooth/adafruit_ble.h b/drivers/bluetooth/bluefruit_le.h
index b43e0771d9..de301c6167 100644
--- a/drivers/bluetooth/adafruit_ble.h
+++ b/drivers/bluetooth/bluefruit_le.h
@@ -16,43 +16,43 @@ extern "C" {
#endif
/* Instruct the module to enable HID keyboard support and reset */
-extern bool adafruit_ble_enable_keyboard(void);
+extern bool bluefruit_le_enable_keyboard(void);
/* Query to see if the BLE module is connected */
-extern bool adafruit_ble_query_is_connected(void);
+extern bool bluefruit_le_query_is_connected(void);
/* Returns true if we believe that the BLE module is connected.
* This uses our cached understanding that is maintained by
* calling ble_task() periodically. */
-extern bool adafruit_ble_is_connected(void);
+extern bool bluefruit_le_is_connected(void);
/* Call this periodically to process BLE-originated things */
-extern void adafruit_ble_task(void);
+extern void bluefruit_le_task(void);
/* Generates keypress events for a set of keys.
* The hid modifier mask specifies the state of the modifier keys for
* this set of keys.
* Also sends a key release indicator, so that the keys do not remain
* held down. */
-extern void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
+extern void bluefruit_le_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
/* Send a consumer usage.
* (milliseconds) */
-extern void adafruit_ble_send_consumer_key(uint16_t usage);
+extern void bluefruit_le_send_consumer_key(uint16_t usage);
#ifdef MOUSE_ENABLE
/* Send a mouse/wheel movement report.
* The parameters are signed and indicate positive or negative direction
* change. */
-extern void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
+extern void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
#endif
/* Compute battery voltage by reading an analog pin.
* Returns the integer number of millivolts */
-extern uint32_t adafruit_ble_read_battery_voltage(void);
+extern uint32_t bluefruit_le_read_battery_voltage(void);
-extern bool adafruit_ble_set_mode_leds(bool on);
-extern bool adafruit_ble_set_power_level(int8_t level);
+extern bool bluefruit_le_set_mode_leds(bool on);
+extern bool bluefruit_le_set_power_level(int8_t level);
#ifdef __cplusplus
}
diff --git a/drivers/bluetooth/outputselect.c b/drivers/bluetooth/outputselect.c
index f758c65280..44bc4a9aa3 100644
--- a/drivers/bluetooth/outputselect.c
+++ b/drivers/bluetooth/outputselect.c
@@ -13,13 +13,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "outputselect.h"
+#include "usb_util.h"
-#if defined(PROTOCOL_LUFA)
-# include "lufa.h"
-#endif
-
-#ifdef MODULE_ADAFRUIT_BLE
-# include "adafruit_ble.h"
+#ifdef BLUETOOTH_BLUEFRUIT_LE
+# include "bluefruit_le.h"
#endif
uint8_t desired_output = OUTPUT_DEFAULT;
@@ -39,23 +36,17 @@ void set_output(uint8_t output) {
*/
__attribute__((weak)) void set_output_user(uint8_t output) {}
-static bool is_usb_configured(void) {
-#if defined(PROTOCOL_LUFA)
- return USB_DeviceState == DEVICE_STATE_Configured;
-#endif
-}
-
/** \brief Auto Detect Output
*
* FIXME: Needs doc
*/
uint8_t auto_detect_output(void) {
- if (is_usb_configured()) {
+ if (usb_connected_state()) {
return OUTPUT_USB;
}
-#ifdef MODULE_ADAFRUIT_BLE
- if (adafruit_ble_is_connected()) {
+#ifdef BLUETOOTH_BLUEFRUIT_LE
+ if (bluefruit_le_is_connected()) {
return OUTPUT_BLUETOOTH;
}
#endif
diff --git a/drivers/bluetooth/rn42.c b/drivers/bluetooth/rn42.c
new file mode 100644
index 0000000000..2ef40bb7e0
--- /dev/null
+++ b/drivers/bluetooth/rn42.c
@@ -0,0 +1,99 @@
+/* Copyright 2021
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "report.h"
+#include "uart.h"
+
+#ifndef RN42_BAUD_RATE
+# define RN42_BAUD_RATE 115200
+#endif
+
+// https://cdn.sparkfun.com/datasheets/Wireless/Bluetooth/bluetooth_cr_UG-v1.0r.pdf#G7.663734
+static inline uint16_t rn42_consumer_usage_to_bitmap(uint16_t usage) {
+ switch (usage) {
+ case AC_HOME:
+ return 0x0001;
+ case AL_EMAIL:
+ return 0x0002;
+ case AC_SEARCH:
+ return 0x0004;
+ case AL_KEYBOARD_LAYOUT:
+ return 0x0008;
+ case AUDIO_VOL_UP:
+ return 0x0010;
+ case AUDIO_VOL_DOWN:
+ return 0x0020;
+ case AUDIO_MUTE:
+ return 0x0040;
+ case TRANSPORT_PLAY_PAUSE:
+ return 0x0080;
+ case TRANSPORT_NEXT_TRACK:
+ return 0x0100;
+ case TRANSPORT_PREV_TRACK:
+ return 0x0200;
+ case TRANSPORT_STOP:
+ return 0x0400;
+ case TRANSPORT_EJECT:
+ return 0x0800;
+ case TRANSPORT_FAST_FORWARD:
+ return 0x1000;
+ case TRANSPORT_REWIND:
+ return 0x2000;
+ case TRANSPORT_STOP_EJECT:
+ return 0x4000;
+ case AL_LOCAL_BROWSER:
+ return 0x8000;
+ default:
+ return 0;
+ }
+}
+
+void rn42_init(void) { uart_init(RN42_BAUD_RATE); }
+
+void rn42_send_keyboard(report_keyboard_t *report) {
+ uart_write(0xFD);
+ uart_write(0x09);
+ uart_write(0x01);
+ uart_write(report->mods);
+ uart_write(0x00);
+ for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
+ uart_write(report->keys[i]);
+ }
+}
+
+void rn42_send_mouse(report_mouse_t *report) {
+ uart_write(0xFD);
+ uart_write(0x00);
+ uart_write(0x03);
+ uart_write(report->buttons);
+ uart_write(report->x);
+ uart_write(report->y);
+ uart_write(report->v); // should try sending the wheel v here
+ uart_write(report->h); // should try sending the wheel h here
+ uart_write(0x00);
+}
+
+void rn42_send_consumer(uint16_t data) {
+ static uint16_t last_data = 0;
+ if (data == last_data) return;
+ last_data = data;
+ uint16_t bitmap = rn42_consumer_usage_to_bitmap(data);
+ uart_write(0xFD);
+ uart_write(0x03);
+ uart_write(0x03);
+ uart_write(bitmap & 0xFF);
+ uart_write((bitmap >> 8) & 0xFF);
+}
diff --git a/drivers/bluetooth/rn42.h b/drivers/bluetooth/rn42.h
new file mode 100644
index 0000000000..4747759111
--- /dev/null
+++ b/drivers/bluetooth/rn42.h
@@ -0,0 +1,25 @@
+/* Copyright 2021
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "report.h"
+
+void rn42_init(void);
+
+void rn42_send_keyboard(report_keyboard_t *report);
+
+void rn42_send_mouse(report_mouse_t *report);
+
+void rn42_send_consumer(uint16_t data);
diff --git a/drivers/flash/flash_spi.c b/drivers/flash/flash_spi.c
new file mode 100644
index 0000000000..2fa8891e38
--- /dev/null
+++ b/drivers/flash/flash_spi.c
@@ -0,0 +1,372 @@
+/*
+Copyright (C) 2021 Westberry Technology (ChangZhou) Corp., Ltd
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "util.h"
+#include "wait.h"
+#include "debug.h"
+#include "timer.h"
+#include "flash_spi.h"
+#include "spi_master.h"
+
+/*
+ The time-out time of spi flash transmission.
+*/
+#ifndef EXTERNAL_FLASH_SPI_TIMEOUT
+# define EXTERNAL_FLASH_SPI_TIMEOUT 1000
+#endif
+
+/* ID comands */
+#define FLASH_CMD_RDID 0x9F /* RDID (Read Identification) */
+#define FLASH_CMD_RES 0xAB /* RES (Read Electronic ID) */
+#define FLASH_CMD_REMS 0x90 /* REMS (Read Electronic & Device ID) */
+
+/* register comands */
+#define FLASH_CMD_WRSR 0x01 /* WRSR (Write Status register) */
+#define FLASH_CMD_RDSR 0x05 /* RDSR (Read Status register) */
+
+/* READ comands */
+#define FLASH_CMD_READ 0x03 /* READ (1 x I/O) */
+#define FLASH_CMD_FASTREAD 0x0B /* FAST READ (Fast read data) */
+#define FLASH_CMD_DREAD 0x3B /* DREAD (1In/2 Out fast read) */
+
+/* Program comands */
+#define FLASH_CMD_WREN 0x06 /* WREN (Write Enable) */
+#define FLASH_CMD_WRDI 0x04 /* WRDI (Write Disable) */
+#define FLASH_CMD_PP 0x02 /* PP (page program) */
+
+/* Erase comands */
+#define FLASH_CMD_SE 0x20 /* SE (Sector Erase) */
+#define FLASH_CMD_BE 0xD8 /* BE (Block Erase) */
+#define FLASH_CMD_CE 0x60 /* CE (Chip Erase) hex code: 60 or C7 */
+
+/* Mode setting comands */
+#define FLASH_CMD_DP 0xB9 /* DP (Deep Power Down) */
+#define FLASH_CMD_RDP 0xAB /* RDP (Release form Deep Power Down) */
+
+/* Status register */
+#define FLASH_FLAG_WIP 0x01 /* Write in progress bit */
+#define FLASH_FLAG_WEL 0x02 /* Write enable latch bit */
+
+// #define DEBUG_FLASH_SPI_OUTPUT
+
+static bool spi_flash_start(void) { return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR); }
+
+static flash_status_t spi_flash_wait_while_busy(void) {
+ uint32_t deadline = timer_read32() + EXTERNAL_FLASH_SPI_TIMEOUT;
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+ uint8_t retval;
+
+ do {
+ bool res = spi_flash_start();
+ if (!res) {
+ dprint("Failed to start SPI! [spi flash wait while busy]\n");
+ return FLASH_STATUS_ERROR;
+ }
+
+ spi_write(FLASH_CMD_RDSR);
+
+ retval = (uint8_t)spi_read();
+
+ spi_stop();
+
+ if (timer_read32() >= deadline) {
+ response = FLASH_STATUS_TIMEOUT;
+ break;
+ }
+ } while (retval & FLASH_FLAG_WIP);
+
+ return response;
+}
+
+static flash_status_t spi_flash_write_enable(void) {
+ bool res = spi_flash_start();
+ if (!res) {
+ dprint("Failed to start SPI! [spi flash write enable]\n");
+ return FLASH_STATUS_ERROR;
+ }
+
+ spi_write(FLASH_CMD_WREN);
+
+ spi_stop();
+
+ return FLASH_STATUS_SUCCESS;
+}
+
+static flash_status_t spi_flash_write_disable(void) {
+ bool res = spi_flash_start();
+ if (!res) {
+ dprint("Failed to start SPI! [spi flash write disable]\n");
+ return FLASH_STATUS_ERROR;
+ }
+
+ spi_write(FLASH_CMD_WRDI);
+
+ spi_stop();
+
+ return FLASH_STATUS_SUCCESS;
+}
+
+/* This function is used for read transfer, write transfer and erase transfer. */
+static flash_status_t spi_flash_transaction(uint8_t cmd, uint32_t addr, uint8_t *data, size_t len) {
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+ uint8_t buffer[EXTERNAL_FLASH_ADDRESS_SIZE + 1];
+
+ buffer[0] = cmd;
+ for (int i = 0; i < EXTERNAL_FLASH_ADDRESS_SIZE; ++i) {
+ buffer[EXTERNAL_FLASH_ADDRESS_SIZE - i] = addr & 0xFF;
+ addr >>= 8;
+ }
+
+ bool res = spi_flash_start();
+ if (!res) {
+ dprint("Failed to start SPI! [spi flash transmit]\n");
+ return FLASH_STATUS_ERROR;
+ }
+
+ response = spi_transmit(buffer, sizeof(buffer));
+
+ if ((!response) && (data != NULL)) {
+ switch (cmd) {
+ case FLASH_CMD_READ:
+ response = spi_receive(data, len);
+ break;
+ case FLASH_CMD_PP:
+ response = spi_transmit(data, len);
+ break;
+ default:
+ response = FLASH_STATUS_ERROR;
+ break;
+ }
+ }
+
+ spi_stop();
+
+ return response;
+}
+
+void flash_init(void) { spi_init(); }
+
+flash_status_t flash_erase_chip(void) {
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+
+ /* Wait for the write-in-progress bit to be cleared. */
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash erase chip]\n");
+ return response;
+ }
+
+ /* Enable writes. */
+ response = spi_flash_write_enable();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to write-enable! [spi flash erase chip]\n");
+ return response;
+ }
+
+ /* Erase Chip. */
+ bool res = spi_flash_start();
+ if (!res) {
+ dprint("Failed to start SPI! [spi flash erase chip]\n");
+ return FLASH_STATUS_ERROR;
+ }
+ spi_write(FLASH_CMD_CE);
+ spi_stop();
+
+ /* Wait for the write-in-progress bit to be cleared.*/
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash erase chip]\n");
+ return response;
+ }
+
+ return response;
+}
+
+flash_status_t flash_erase_sector(uint32_t addr) {
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+
+ /* Check that the address exceeds the limit. */
+ if ((addr + (EXTERNAL_FLASH_SECTOR_SIZE)) >= (EXTERNAL_FLASH_SIZE) || ((addr % (EXTERNAL_FLASH_SECTOR_SIZE)) != 0)) {
+ dprintf("Flash erase sector address over limit! [addr:0x%x]\n", (uint32_t)addr);
+ return FLASH_STATUS_ERROR;
+ }
+
+ /* Wait for the write-in-progress bit to be cleared. */
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash erase sector]\n");
+ return response;
+ }
+
+ /* Enable writes. */
+ response = spi_flash_write_enable();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to write-enable! [spi flash erase sector]\n");
+ return response;
+ }
+
+ /* Erase Sector. */
+ response = spi_flash_transaction(FLASH_CMD_SE, addr, NULL, 0);
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to erase sector! [spi flash erase sector]\n");
+ return response;
+ }
+
+ /* Wait for the write-in-progress bit to be cleared.*/
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash erase sector]\n");
+ return response;
+ }
+
+ return response;
+}
+
+flash_status_t flash_erase_block(uint32_t addr) {
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+
+ /* Check that the address exceeds the limit. */
+ if ((addr + (EXTERNAL_FLASH_BLOCK_SIZE)) >= (EXTERNAL_FLASH_SIZE) || ((addr % (EXTERNAL_FLASH_BLOCK_SIZE)) != 0)) {
+ dprintf("Flash erase block address over limit! [addr:0x%x]\n", (uint32_t)addr);
+ return FLASH_STATUS_ERROR;
+ }
+
+ /* Wait for the write-in-progress bit to be cleared. */
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash erase block]\n");
+ return response;
+ }
+
+ /* Enable writes. */
+ response = spi_flash_write_enable();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to write-enable! [spi flash erase block]\n");
+ return response;
+ }
+
+ /* Erase Block. */
+ response = spi_flash_transaction(FLASH_CMD_BE, addr, NULL, 0);
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to erase block! [spi flash erase block]\n");
+ return response;
+ }
+
+ /* Wait for the write-in-progress bit to be cleared.*/
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash erase block]\n");
+ return response;
+ }
+
+ return response;
+}
+
+flash_status_t flash_read_block(uint32_t addr, void *buf, size_t len) {
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+ uint8_t * read_buf = (uint8_t *)buf;
+
+ /* Wait for the write-in-progress bit to be cleared. */
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash read block]\n");
+ memset(read_buf, 0, len);
+ return response;
+ }
+
+ /* Perform read. */
+ response = spi_flash_transaction(FLASH_CMD_READ, addr, read_buf, len);
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to read block! [spi flash read block]\n");
+ memset(read_buf, 0, len);
+ return response;
+ }
+
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_FLASH_SPI_OUTPUT)
+ dprintf("[SPI FLASH R] 0x%08lX: ", addr);
+ for (size_t i = 0; i < len; ++i) {
+ dprintf(" %02X", (int)(((uint8_t *)read_buf)[i]));
+ }
+ dprintf("\n");
+#endif // DEBUG_FLASH_SPI_OUTPUT
+
+ return response;
+}
+
+flash_status_t flash_write_block(uint32_t addr, const void *buf, size_t len) {
+ flash_status_t response = FLASH_STATUS_SUCCESS;
+ uint8_t * write_buf = (uint8_t *)buf;
+
+ while (len > 0) {
+ uint32_t page_offset = addr % EXTERNAL_FLASH_PAGE_SIZE;
+ size_t write_length = EXTERNAL_FLASH_PAGE_SIZE - page_offset;
+ if (write_length > len) {
+ write_length = len;
+ }
+
+ /* Wait for the write-in-progress bit to be cleared. */
+ response = spi_flash_wait_while_busy();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to check WIP flag! [spi flash write block]\n");
+ return response;
+ }
+
+ /* Enable writes. */
+ response = spi_flash_write_enable();
+ if (response != FLASH_STATUS_SUCCESS) {
+ dprint("Failed to write-enable! [spi flash write block]\n");
+ return response;
+ }
+
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_FLASH_SPI_OUTPUT)
+ dprintf("[SPI FLASH W] 0x%08lX: ", addr);
+ for (size_t i = 0; i < write_length; i++) {
+ dprintf(" %02X", (int)(uint8_t)(write_buf[i]));
+ }
+ dp