modify spi protocol a bit for kernel driver work
This commit is contained in:
parent
bad06fe9b4
commit
7e4bea1a37
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/spi.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/stdlib.h>
|
||||
|
@ -11,16 +12,18 @@
|
|||
|
||||
#include "m_default/serprog.h"
|
||||
|
||||
static bool cs_asserted;
|
||||
//static bool cs_asserted;
|
||||
|
||||
static uint32_t freq;
|
||||
static enum serprog_flags sflags;
|
||||
static uint8_t bpw;
|
||||
|
||||
void sp_spi_init(void) {
|
||||
cs_asserted = false;
|
||||
//cs_asserted = false;
|
||||
|
||||
freq = 512*1000; // default to 512 kHz
|
||||
sflags = 0; // CPOL 0, CPHA 0, 8bit
|
||||
sflags = 0; // CPOL 0, CPHA 0, MSB first
|
||||
bpw = 8;
|
||||
spi_init(PINOUT_SPI_DEV, freq);
|
||||
|
||||
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_SPI);
|
||||
|
@ -36,9 +39,10 @@ void sp_spi_init(void) {
|
|||
bi_decl(bi_1pin_with_name(PINOUT_SPI_nCS, "SPI #CS"));
|
||||
}
|
||||
void sp_spi_deinit(void) {
|
||||
cs_asserted = false;
|
||||
//cs_asserted = false;
|
||||
sflags = 0;
|
||||
freq = 512*1000;
|
||||
bpw = 8;
|
||||
|
||||
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_NULL);
|
||||
|
@ -51,19 +55,61 @@ void sp_spi_deinit(void) {
|
|||
spi_deinit(PINOUT_SPI_DEV);
|
||||
}
|
||||
|
||||
uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) {
|
||||
uint32_t sp_spi_set_freq(uint32_t freq_wanted) {
|
||||
freq = spi_set_baudrate(PINOUT_SPI_DEV, freq_wanted);
|
||||
return freq;
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_set_flags)(enum serprog_flags flags) {
|
||||
sflags = flags;
|
||||
spi_set_format(PINOUT_SPI_DEV, (flags & S_FLG_16BIT) ? 16 : 8,
|
||||
(flags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0,
|
||||
(flags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0,
|
||||
SPI_MSB_FIRST);
|
||||
|
||||
static void apply_settings(void) {
|
||||
/*spi_set_format(PINOUT_SPI_DEV, bpw,
|
||||
(sflags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0,
|
||||
(sflags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0,
|
||||
SPI_MSB_FIRST);*/
|
||||
|
||||
hw_write_masked(&spi_get_hw(PINOUT_SPI_DEV)->cr0,
|
||||
((uint32_t)(bpw - 1) << SPI_SSPCR0_DSS_LSB)
|
||||
| ((uint32_t)((sflags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0) << SPI_SSPCR0_SPO_LSB)
|
||||
| ((uint32_t)((sflags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0) << SPI_SSPCR0_SPH_LSB)
|
||||
| ((uint32_t)((sflags >> 2) & 3) << SPI_SSPCR0_FRF_LSB),
|
||||
SPI_SSPCR0_DSS_BITS | SPI_SSPCR0_SPO_BITS | SPI_SSPCR0_SPH_BITS | SPI_SSPCR0_FRF_BITS
|
||||
);
|
||||
}
|
||||
enum serprog_flags sp_spi_set_flags(enum serprog_flags flags) {
|
||||
if ((flags & (3<<2)) == (3<<2)) flags &= ~(uint32_t)(3<<2); // change to moto if bad value
|
||||
|
||||
sflags = flags & ~S_FLG_LSBFST; // ignore LSB-first flag, we don't support it
|
||||
|
||||
apply_settings();
|
||||
|
||||
return sflags;
|
||||
}
|
||||
uint8_t sp_spi_set_bpw(uint8_t bpw_) {
|
||||
bpw = bpw_;
|
||||
if (bpw < 4) bpw = 4;
|
||||
if (bpw > 16) bpw = 16;
|
||||
|
||||
apply_settings();
|
||||
|
||||
return bpw;
|
||||
}
|
||||
|
||||
__attribute__((__const__)) const struct sp_spi_caps* sp_spi_get_caps(void) {
|
||||
static struct sp_spi_caps caps = {
|
||||
.freq_min = ~(uint32_t)0,
|
||||
.freq_max = 0,
|
||||
.num_cs = 1,
|
||||
.min_bpw = 4,
|
||||
.max_bpw = 16,
|
||||
.caps = S_CAP_CPOL_HI | S_CAP_CPOL_LO | S_CAP_CPHA_HI | S_CAP_CPHA_LO
|
||||
| S_CAP_MOTO | S_CAP_NATSEM | S_CAP_TI | S_CAP_MSBFST | S_CAP_LSBFST
|
||||
| S_CAP_CSACHI
|
||||
};
|
||||
|
||||
caps.freq_min = clock_get_hz(clk_peri) / 254;
|
||||
caps.freq_max = clock_get_hz(clk_peri) / 1;
|
||||
|
||||
return ∩︀
|
||||
}
|
||||
__attribute__((__const__))
|
||||
int __not_in_flash_func(sp_spi_get_num_cs)(void) { return 1; }
|
||||
|
||||
void __not_in_flash_func(sp_spi_cs_deselect)(uint8_t csflags) {
|
||||
(void)csflags;
|
||||
|
@ -71,7 +117,7 @@ void __not_in_flash_func(sp_spi_cs_deselect)(uint8_t csflags) {
|
|||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
cs_asserted = false;
|
||||
//cs_asserted = false;
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_cs_select)(uint8_t csflags) {
|
||||
(void)csflags;
|
||||
|
@ -79,14 +125,15 @@ void __not_in_flash_func(sp_spi_cs_select)(uint8_t csflags) {
|
|||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 0);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
cs_asserted = true;
|
||||
//cs_asserted = true;
|
||||
}
|
||||
|
||||
void __not_in_flash_func(sp_spi_op_begin)(uint8_t csflags) {
|
||||
// sp_spi_cs_select(csflags);
|
||||
(void)csflags;
|
||||
|
||||
if (!cs_asserted) {
|
||||
//if (!cs_asserted)
|
||||
{
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 0);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
|
@ -96,7 +143,8 @@ void __not_in_flash_func(sp_spi_op_end)(uint8_t csflags) {
|
|||
// sp_spi_cs_deselect(csflags);
|
||||
(void)csflags;
|
||||
|
||||
if (!cs_asserted) { // YES, this condition is the intended one!
|
||||
//if (!cs_asserted) { // YES, this condition is the intended one!
|
||||
{
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
|
@ -104,24 +152,23 @@ void __not_in_flash_func(sp_spi_op_end)(uint8_t csflags) {
|
|||
}
|
||||
|
||||
// TODO: use dma?
|
||||
// TODO: routines for non-8/16-bit xfers??
|
||||
void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const void* write_data) {
|
||||
if (sflags & S_FLG_16BIT) {
|
||||
void sp_spi_op_write(uint32_t write_len, const void* write_data) {
|
||||
if (bpw > 8) {
|
||||
spi_write16_blocking(PINOUT_SPI_DEV, (const uint16_t*)write_data, write_len >> 1);
|
||||
} else {
|
||||
spi_write_blocking(PINOUT_SPI_DEV, (const uint8_t*)write_data, write_len);
|
||||
}
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, void* read_data) {
|
||||
if (sflags & S_FLG_16BIT) {
|
||||
void sp_spi_op_read(uint32_t read_len, void* read_data) {
|
||||
if (bpw > 8) {
|
||||
spi_read16_blocking(PINOUT_SPI_DEV, 0, (uint16_t*)read_data, read_len >> 1);
|
||||
} else {
|
||||
spi_read_blocking(PINOUT_SPI_DEV, 0, (uint8_t*)read_data, read_len);
|
||||
}
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_read_write)(uint32_t len, void* read_data,
|
||||
void sp_spi_op_read_write(uint32_t len, void* read_data,
|
||||
const void* write_data) {
|
||||
if (sflags & S_FLG_16BIT) {
|
||||
if (bpw > 8) {
|
||||
spi_write16_read16_blocking(PINOUT_SPI_DEV, (const uint16_t*)write_data,
|
||||
(uint16_t*)read_data, len >> 1);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
obj-m := dmj.o dmj-char.o i2c-dmj.o
|
||||
obj-m := dmj.o dmj-char.o i2c-dmj.o spi-dmj.c
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
|
@ -14,7 +14,10 @@ clean:
|
|||
load:
|
||||
sudo insmod ./dmj.ko
|
||||
sudo insmod ./dmj-char.ko
|
||||
sudo insmod ./spi-dmj.ko
|
||||
|
||||
unload:
|
||||
sudo rmmod spi-dmj
|
||||
sudo rmmod i2c-dmj
|
||||
sudo rmmod dmj-char
|
||||
sudo rmmod dmj
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Driver for the DapperMime-JTAG USB multitool: base MFD driver
|
||||
*
|
||||
* Copyright (c) sys64738 and haskal
|
||||
* Copyright (c) 2021 sys64738 and haskal
|
||||
*
|
||||
* Adapted from:
|
||||
* dln2.c Copyright (c) 2014 Intel Corporation
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Driver for the DapperMime-JTAG USB multitool: USB-I2C adapter
|
||||
*
|
||||
* Copyright (c) sys64738 and haskal
|
||||
* Copyright (c) 2021 sys64738 and haskal
|
||||
*
|
||||
* Adapted from:
|
||||
* i2c-dln2.c Copyright (c) 2014 Intel Corporation
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
#define HARDWARE_NAME "DapperMime-JTAG"
|
||||
|
||||
#define DMJ_I2C_MAX_XSFER_SIZE 64
|
||||
#define DMJ_I2C_MAX_XFER_SIZE 64
|
||||
|
||||
#define DMJ_I2C_CMD_ECHO 0x00
|
||||
#define DMJ_I2C_CMD_GET_FUNC 0x01
|
||||
|
@ -195,8 +195,8 @@ static const struct i2c_algorithm dmj_i2c_algo = {
|
|||
.functionality = dmj_i2c_func
|
||||
};
|
||||
static const struct i2c_adapter_quirks dmj_i2c_quirks = {
|
||||
.max_read_len = DMJ_I2C_MAX_XSFER_SIZE,
|
||||
.max_write_len = DMJ_I2C_MAX_XSFER_SIZE,
|
||||
.max_read_len = DMJ_I2C_MAX_XFER_SIZE,
|
||||
.max_write_len = DMJ_I2C_MAX_XFER_SIZE,
|
||||
};
|
||||
|
||||
static int dmj_i2c_check_hw(struct platform_device *pdev)
|
||||
|
|
|
@ -24,7 +24,7 @@ static const uint8_t serprog_cmdmap[32] = {
|
|||
0, // 20..27
|
||||
0, // 28..2f
|
||||
0, // 30..37
|
||||
0x3f, // cmd 40..45
|
||||
0xff, // cmd 40..47
|
||||
0, // rest is 0
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -162,7 +162,42 @@ static void handle_cmd(uint8_t cmd, uint8_t ud, uint8_t (*read_byte)(void),
|
|||
tx_buf[4] = (nfreq >> 24) & 0xff;
|
||||
nresp = 5;
|
||||
} break;
|
||||
case S_CMD_S_PINSTATE: {
|
||||
case S_CMD_S_PINSTATE:
|
||||
// that's not what this command is supposed to do, so, aaa
|
||||
/*if (read_byte() == 0)
|
||||
sp_spi_cs_deselect(selchip);
|
||||
else
|
||||
sp_spi_cs_select(selchip);*/
|
||||
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
break;
|
||||
|
||||
case S_CMD_Q_SPI_CAPS: {
|
||||
const struct sp_spi_caps* caps = sp_spi_get_caps();
|
||||
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = caps->freq_min & 0xff;
|
||||
tx_buf[2] = (caps->freq_min >> 8) & 0xff;
|
||||
tx_buf[3] = (caps->freq_min >> 16) & 0xff;
|
||||
tx_buf[4] = (caps->freq_min >> 24) & 0xff;
|
||||
tx_buf[5] = caps->freq_max & 0xff;
|
||||
tx_buf[6] = (caps->freq_max >> 8) & 0xff;
|
||||
tx_buf[7] = (caps->freq_max >> 16) & 0xff;
|
||||
tx_buf[8] = (caps->freq_max >> 24) & 0xff;
|
||||
tx_buf[9] = caps->caps & 0xff;
|
||||
tx_buf[10] = (caps->caps >> 8) & 0xff;
|
||||
tx_buf[11] = caps->num_cs;
|
||||
tx_buf[12] = caps->min_bpw;
|
||||
tx_buf[13] = caps->max_bpw;
|
||||
nresp = 14;
|
||||
} break;
|
||||
case S_CMD_S_SPI_CHIPN:
|
||||
selchip = read_byte();
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
break;
|
||||
case S_CMD_S_SPI_SETCS:
|
||||
if (read_byte() == 0)
|
||||
sp_spi_cs_deselect(selchip);
|
||||
else
|
||||
|
@ -170,21 +205,15 @@ static void handle_cmd(uint8_t cmd, uint8_t ud, uint8_t (*read_byte)(void),
|
|||
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
} break;
|
||||
|
||||
case S_CMD_Q_NUM_CS:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = sp_spi_get_num_cs();
|
||||
nresp = 2;
|
||||
break;
|
||||
break;
|
||||
case S_CMD_S_SPI_FLAGS:
|
||||
sp_spi_set_flags(read_byte());
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = sp_spi_set_flags(read_byte());
|
||||
nresp = 1;
|
||||
break;
|
||||
case S_CMD_S_SPI_CHIPN:
|
||||
selchip = read_byte();
|
||||
case S_CMD_S_SPI_BPW:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = sp_spi_set_bpw(read_byte());
|
||||
nresp = 1;
|
||||
break;
|
||||
|
||||
|
|
|
@ -28,22 +28,45 @@ enum serprog_cmd {
|
|||
S_CMD_S_PINSTATE = 0x15,
|
||||
|
||||
// TODO: upstream this to flashrom? could be useful to others maybe
|
||||
S_CMD_Q_NUM_CS = 0x40,
|
||||
S_CMD_S_SPI_FLAGS = 0x41,
|
||||
S_CMD_Q_SPI_CAPS = 0x40,
|
||||
// number of chip (well, bitflags) to use when asserting/deasserting the chip select line
|
||||
S_CMD_S_SPI_CHIPN = 0x42,
|
||||
S_CMD_SPI_READ = 0x43,
|
||||
S_CMD_SPI_WRITE = 0x44,
|
||||
S_CMD_S_SPI_CHIPN = 0x41,
|
||||
// sets chip select line high or low (device does no translation wrt. S_FLG_CSACHI!)
|
||||
S_CMD_S_SPI_SETCS = 0x42,
|
||||
S_CMD_S_SPI_FLAGS = 0x43,
|
||||
S_CMD_S_SPI_BPW = 0x44, // set bits per word
|
||||
S_CMD_SPI_READ = 0x45,
|
||||
S_CMD_SPI_WRITE = 0x46,
|
||||
// as opposed to S_CMD_SPIOP, this one is full-duplex instead of half-duplex
|
||||
S_CMD_SPI_RDWR = 0x45,
|
||||
S_CMD_SPI_RDWR = 0x47,
|
||||
};
|
||||
|
||||
enum serprog_response { S_ACK = 0x06, S_NAK = 0x15 };
|
||||
|
||||
enum serprog_flags {
|
||||
S_FLG_CPOL = 1<<0, // 1: clock polarity 1, else clkpol 0
|
||||
S_FLG_CPHA = 1<<1, // 1: clock phase 1, else clkpha 1
|
||||
S_FLG_16BIT = 1<<2, // 1: 16-bit transfers, else 8-bit xfers
|
||||
S_FLG_CPHA = 1<<0, // 1: clock phase 1, else clkpha 1
|
||||
S_FLG_CPOL = 1<<1, // 1: clock polarity 1, else clkpol 0
|
||||
S_FLG_STDSPI = 0<<2, // frame format
|
||||
S_FLG_TISSP = 1<<2, // frame format
|
||||
S_FLG_MICROW = 2<<2, // frame format
|
||||
S_FLG_MSBFST = 0<<4, // MSBit sent first
|
||||
S_FLG_LSBFST = 1<<4, // LSBit sent first
|
||||
S_FLG_CSACLO = 0<<5, // chip select active-low (common)
|
||||
S_FLG_CSACHI = 1<<5, // chip select active-high
|
||||
S_FLG_3WIRE = 1<<6,
|
||||
};
|
||||
enum serprog_caps {
|
||||
S_CAP_CPHA_HI = 1<<0,
|
||||
S_CAP_CPHA_LO = 1<<1,
|
||||
S_CAP_CPOL_HI = 1<<2,
|
||||
S_CAP_CPOL_LO = 1<<3,
|
||||
S_CAP_STDSPI = 1<<4, // standard SPI
|
||||
S_CAP_TISSP = 1<<5, // synchronous serial protocol from TI
|
||||
S_CAP_MICROW = 1<<6, // microwire
|
||||
S_CAP_MSBFST = 1<<7,
|
||||
S_CAP_LSBFST = 1<<8,
|
||||
S_CAP_CSACHI = 1<<9,
|
||||
S_CAP_3WIRE = 1<<10,
|
||||
};
|
||||
|
||||
#define SERPROG_IFACE_VERSION 0x0001
|
||||
|
@ -51,9 +74,15 @@ enum serprog_flags {
|
|||
#ifdef DBOARD_HAS_SPI
|
||||
/* functions to be implemented by the BSP */
|
||||
uint32_t /*freq_applied*/ sp_spi_set_freq(uint32_t freq_wanted);
|
||||
enum serprog_flags sp_spi_set_flags(enum serprog_flags flags);
|
||||
uint8_t sp_spi_set_bpw(uint8_t bpw);
|
||||
|
||||
void sp_spi_set_flags(enum serprog_flags flags);
|
||||
__attribute__((__const__)) int sp_spi_get_num_cs(void);
|
||||
struct sp_spi_caps {
|
||||
uint32_t freq_min, freq_max;
|
||||
uint16_t caps;
|
||||
uint8_t num_cs, min_bpw, max_bpw;
|
||||
};
|
||||
__attribute__((__const__)) const struct sp_spi_caps* sp_spi_get_caps(void);
|
||||
|
||||
void sp_spi_init(void);
|
||||
void sp_spi_deinit(void);
|
||||
|
|
Loading…
Reference in New Issue