Angel Pons has uploaded this change for review.
[UNTESTED] bitbang_spi.c: Support changing clock polarity and phase
Change-Id: I415a528c013f1a523e883d812b6890be39bfcc7b
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
---
M bitbang_spi.c
1 file changed, 45 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/71/49271/1
diff --git a/bitbang_spi.c b/bitbang_spi.c
index 00c631f..252adab 100644
--- a/bitbang_spi.c
+++ b/bitbang_spi.c
@@ -21,6 +21,9 @@
#include "programmer.h"
#include "spi.h"
+static int cpol = 0; /* Clock Polarity */
+static int cpha = 0; /* Clock Phase */
+
/* Note that CS# is active low, so val=0 means the chip is active. */
static void bitbang_spi_set_cs(const struct bitbang_spi_master * const master, int val)
{
@@ -29,7 +32,7 @@
static void bitbang_spi_set_sck(const struct bitbang_spi_master * const master, int val)
{
- master->set_sck(val);
+ master->set_sck(val ^ cpol);
}
static void bitbang_spi_request_bus(const struct bitbang_spi_master * const master)
@@ -54,6 +57,10 @@
return master->set_sck_get_miso(sck);
}
+/*
+ * For CPHA=0, the "in" side captures the data on (or shortly after) the leading edge of the clock cycle.
+ * For CPHA=1, the "in" side captures the data on (or shortly after) the trailing edge of the clock cycle.
+ */
static uint8_t bitbang_spi_read_byte(const struct bitbang_spi_master *master)
{
uint8_t ret = 0;
@@ -61,25 +68,29 @@
for (i = 7; i >= 0; i--) {
if (i == 0)
- bitbang_spi_set_mosi_set_sck(master, 0, 0);
+ bitbang_spi_set_mosi_set_sck(master, 0, cpha);
else
bitbang_spi_set_sck(master, 0);
programmer_delay(master->half_period);
ret <<= 1;
- ret |= bitbang_spi_set_sck_get_miso(master, 1);
+ ret |= bitbang_spi_set_sck_get_miso(master, !cpha);
programmer_delay(master->half_period);
}
return ret;
}
+/*
+ * For CPHA=0, the "out" side changes the data on the trailing edge of the preceding clock cycle.
+ * For CPHA=1, the "out" side changes the data on the leading edge of the current clock cycle.
+ */
static void bitbang_spi_write_byte(const struct bitbang_spi_master *master, uint8_t val)
{
int i;
for (i = 7; i >= 0; i--) {
- bitbang_spi_set_mosi_set_sck(master, (val >> i) & 1, 0);
+ bitbang_spi_set_mosi_set_sck(master, (val >> i) & 1, cpha);
programmer_delay(master->half_period);
- bitbang_spi_set_sck(master, 1);
+ bitbang_spi_set_sck(master, !cpha);
programmer_delay(master->half_period);
}
}
@@ -98,13 +109,17 @@
*/
bitbang_spi_request_bus(master);
bitbang_spi_set_cs(master, 0);
+ if (cpha)
+ programmer_delay(master->half_period);
+
for (i = 0; i < writecnt; i++)
bitbang_spi_write_byte(master, writearr[i]);
for (i = 0; i < readcnt; i++)
readarr[i] = bitbang_spi_read_byte(master);
bitbang_spi_set_sck(master, 0);
- programmer_delay(master->half_period);
+ if (!cpha)
+ programmer_delay(master->half_period);
bitbang_spi_set_cs(master, 1);
programmer_delay(master->half_period);
/* FIXME: Run bitbang_spi_release_bus here or in programmer init? */
@@ -132,6 +147,27 @@
}
#endif
+static int parse_spi_mode(int *polarity, int *phase)
+{
+ char *mode = extract_programmer_param("mode");
+ if (!mode)
+ return 0;
+
+ if (strlen(mode)) {
+ char *endptr;
+ int v = strtol(mode, &endptr, 0);
+ if (mode == endptr || v > 3 || v < 0) {
+ msg_perr("Invalid bitbang SPI mode, valid values are 0..3\n");
+ free(mode);
+ return -1;
+ }
+ *polarity = (v >> 1) & 1;
+ *phase = (v >> 0) & 1;
+ }
+ free(mode);
+ return 0;
+}
+
int register_spi_bitbang_master(const struct bitbang_spi_master *master)
{
struct spi_master mst = spi_master_bitbang;
@@ -145,6 +181,9 @@
return ERROR_FLASHROM_BUG;
}
+ if (parse_spi_mode(&cpol, &cpha))
+ return ERROR_FATAL;
+
mst.data = master;
register_spi_master(&mst);
To view, visit change 49271. To unsubscribe, or for help writing mail filters, visit settings.