|
|
@ -1,63 +1,70 @@ |
|
|
|
/* vim: set fdm=marker sw=4 ts=4 nu: */ |
|
|
|
#include <string.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include "platform_internal.h" |
|
|
|
#include "spi.h" |
|
|
|
|
|
|
|
#define TXBUF_SIZE (1024) |
|
|
|
#define RXBUF_SIZE (1024) |
|
|
|
|
|
|
|
typedef struct __spi_handle *spi_t; |
|
|
|
/* {{{: struct __spi_handle {...} */ |
|
|
|
struct __spi_handle { |
|
|
|
MCBSP_Handle spi; |
|
|
|
int bits; |
|
|
|
int is_i2s; |
|
|
|
|
|
|
|
/* tx */ |
|
|
|
EDMA_Handle xh; |
|
|
|
void (*xnotify)(void *args); |
|
|
|
void *xargs; |
|
|
|
char xbuf[TXBUF_SIZE]; |
|
|
|
|
|
|
|
/* rx */ |
|
|
|
EDMA_Handle rh; |
|
|
|
void (*rnotify)(void *args); |
|
|
|
void *rargs; |
|
|
|
char rbuf[RXBUF_SIZE]; |
|
|
|
}; |
|
|
|
|
|
|
|
static struct __spi_handle __spi_devs[_MCBSP_PORT_CNT]; |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
void spi_lowlevel_init() |
|
|
|
{ |
|
|
|
memset(__spi_devs, 0, sizeof __spi_devs); |
|
|
|
} |
|
|
|
|
|
|
|
static spi_t __find_spi_with_xtcc(int tccNum) |
|
|
|
/* {{{: interrupt handler */ |
|
|
|
static void __tx_notify(int tccNum, void *arg) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
spi_t spi; |
|
|
|
for (i = 0; i < _MCBSP_PORT_CNT; ++i) { |
|
|
|
spi = &__spi_devs[i]; |
|
|
|
if (MCBSP_getXmtEventId(spi->spi) == tccNum) { |
|
|
|
return spi; |
|
|
|
spi_t spi = arg; |
|
|
|
void (*handler)(void *); |
|
|
|
|
|
|
|
if (spi) { |
|
|
|
EDMA_disableChannel(spi->xh); |
|
|
|
handler = spi->xnotify; |
|
|
|
if (handler) { |
|
|
|
spi->xnotify = NULL; |
|
|
|
handler(spi->xargs); |
|
|
|
edma_dettach_tcc_irq(tccNum); |
|
|
|
} |
|
|
|
} |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
static void __tx_notify(int tccNum) |
|
|
|
static void __rx_notify(int tccNum, void *arg) |
|
|
|
{ |
|
|
|
spi_t spi; |
|
|
|
spi_t spi = arg; |
|
|
|
void (*handler)(void *); |
|
|
|
|
|
|
|
EDMA_intClear(tccNum); |
|
|
|
|
|
|
|
spi = __find_spi_with_xtcc(tccNum); |
|
|
|
if (spi) { |
|
|
|
EDMA_disableChannel(spi->xh); |
|
|
|
if (spi->xnotify) |
|
|
|
spi->xnotify(spi->xargs); |
|
|
|
EDMA_disableChannel(spi->rh); |
|
|
|
handler = spi->rnotify; |
|
|
|
if (handler) { |
|
|
|
spi->rnotify = NULL; |
|
|
|
handler(spi->rargs); |
|
|
|
edma_dettach_tcc_irq(tccNum); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
/* {{{: i2s_slave_open(...) */ |
|
|
|
static Uint32 __parse_to_dlen1(int bits) |
|
|
|
{ |
|
|
|
Uint32 dlen1; |
|
|
@ -104,6 +111,8 @@ int i2s_slave_open(int dev_id, int bits) |
|
|
|
return -1; /* busy ? */ |
|
|
|
} |
|
|
|
|
|
|
|
spi->is_i2s = 1; |
|
|
|
|
|
|
|
if ((int)(dlen1 = __parse_to_dlen1(bits)) < 0) { |
|
|
|
return -3; |
|
|
|
} |
|
|
@ -146,7 +155,7 @@ int i2s_slave_open(int dev_id, int bits) |
|
|
|
MCBSP_RCR_RCOMPAND_MSB, // Transmit companding mode(XCOMPAND)
|
|
|
|
MCBSP_RCR_RFIG_YES, // Transmit frame ignore(XFIG)
|
|
|
|
MCBSP_RCR_RDATDLY_1BIT, // Transmit data delay(XDATDLY)
|
|
|
|
MCBSP_RCR_RFRLEN1_OF(0), // Transmit frame length
|
|
|
|
MCBSP_RCR_RFRLEN1_OF(1), // Transmit frame length
|
|
|
|
// in phase 1(XFRLEN1)
|
|
|
|
dlen1, // Transmit element length
|
|
|
|
// in phase 1(XWDLEN1)
|
|
|
@ -163,7 +172,7 @@ int i2s_slave_open(int dev_id, int bits) |
|
|
|
MCBSP_XCR_XCOMPAND_MSB, // Transmit companding mode(XCOMPAND)
|
|
|
|
MCBSP_XCR_XFIG_NO, // Transmit frame ignore(XFIG)
|
|
|
|
MCBSP_XCR_XDATDLY_1BIT, // Transmit data delay(XDATDLY)
|
|
|
|
MCBSP_XCR_XFRLEN1_OF(0), // Transmit frame length
|
|
|
|
MCBSP_XCR_XFRLEN1_OF(1), // Transmit frame length
|
|
|
|
// in phase 1(XFRLEN1)
|
|
|
|
dlen1, // Transmit element length
|
|
|
|
// in phase 1(XWDLEN1)
|
|
|
@ -206,7 +215,9 @@ int i2s_slave_open(int dev_id, int bits) |
|
|
|
MCBSP_SRGR_DEFAULT_DELAY); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
/* {{{: spi_open(int dev_id, int mode, int freq, int bits) */ |
|
|
|
int spi_open(int dev_id, int mode, int freq, int bits) |
|
|
|
{ |
|
|
|
MCBSP_Config mbconf; |
|
|
@ -224,6 +235,9 @@ int spi_open(int dev_id, int mode, int freq, int bits) |
|
|
|
if (spi->spi) { |
|
|
|
return -1; /* busy ? */ |
|
|
|
} |
|
|
|
|
|
|
|
spi->is_i2s = 0; |
|
|
|
|
|
|
|
if ((int)(dlen1 = __parse_to_dlen1(bits)) < 0) { |
|
|
|
return -3; |
|
|
|
} |
|
|
@ -355,45 +369,9 @@ int spi_open(int dev_id, int mode, int freq, int bits) |
|
|
|
spi->spi = handle; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
static int __write_u8(spi_t spi, const Uint8 *buf, int len) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_xrdy(spi->spi)) |
|
|
|
; |
|
|
|
MCBSP_write(spi->spi, buf[i]); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
} |
|
|
|
|
|
|
|
static int __write_u16(spi_t spi, const Uint16 *buf, int len) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
len >>= 1; |
|
|
|
|
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_xrdy(spi->spi)) |
|
|
|
; |
|
|
|
MCBSP_write(spi->spi, buf[i]); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
} |
|
|
|
|
|
|
|
static int __write_u32(spi_t spi, const Uint32 *buf, int len) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
len >>= 2; |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_xrdy(spi->spi)) |
|
|
|
; |
|
|
|
MCBSP_write(spi->spi, buf[i]); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
} |
|
|
|
|
|
|
|
/* {{{: int spi_write(int dev_id, const void *buf, int len) */ |
|
|
|
static spi_t __get_active_device(int dev_id) |
|
|
|
{ |
|
|
|
spi_t spi; |
|
|
@ -406,11 +384,12 @@ static spi_t __get_active_device(int dev_id) |
|
|
|
return spi->spi ? spi : NULL; |
|
|
|
} |
|
|
|
|
|
|
|
int spi_write(int dev_id, const void *buf, int len) |
|
|
|
int spi_write(int dev_id, const void *buf, int _len) |
|
|
|
{ |
|
|
|
const Uint8 *u8; |
|
|
|
const Uint16 *u16; |
|
|
|
const Uint32 *u32; |
|
|
|
int i, len = _len; |
|
|
|
spi_t spi; |
|
|
|
|
|
|
|
if ((spi = __get_active_device(dev_id)) == NULL) { |
|
|
@ -422,65 +401,62 @@ int spi_write(int dev_id, const void *buf, int len) |
|
|
|
switch (spi->bits) { |
|
|
|
case 8: |
|
|
|
u8 = buf; |
|
|
|
__write_u8(spi, u8, len); |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_xrdy(spi->spi)) |
|
|
|
; |
|
|
|
MCBSP_write(spi->spi, u8[i]); |
|
|
|
} |
|
|
|
break; |
|
|
|
case 12: |
|
|
|
case 16: |
|
|
|
len >>= 1; |
|
|
|
u16 = buf; |
|
|
|
__write_u16(spi, u16, len); |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_xrdy(spi->spi)) |
|
|
|
; |
|
|
|
MCBSP_write(spi->spi, u16[i]); |
|
|
|
} |
|
|
|
break; |
|
|
|
case 20: |
|
|
|
case 24: |
|
|
|
case 32: |
|
|
|
len >>= 2; |
|
|
|
u32 = buf; |
|
|
|
__write_u32(spi, u32, len); |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_xrdy(spi->spi)) |
|
|
|
; |
|
|
|
MCBSP_write(spi->spi, u32[i]); |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
return (_len); |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
int spi_edma_write(int dev_id, const void *buf, int len, void (*notify)(void *args), void *args) |
|
|
|
static int __do_spi_edma_write(spi_t spi, int bits, const void *buf, int len, void (*notify)(void *args), void *args) |
|
|
|
{ |
|
|
|
spi_t spi; |
|
|
|
Uint32 esize; |
|
|
|
EDMA_Config edma_conf; |
|
|
|
int slen, xevent; |
|
|
|
static EDMA_Config edma_conf; |
|
|
|
int frmlen = 0, xevent, slen = len; |
|
|
|
|
|
|
|
if ((spi = __get_active_device(dev_id)) == NULL) { |
|
|
|
return -2; |
|
|
|
} |
|
|
|
|
|
|
|
spi = &__spi_devs[dev_id]; |
|
|
|
if (len > TXBUF_SIZE) { |
|
|
|
len = TXBUF_SIZE; |
|
|
|
} |
|
|
|
|
|
|
|
slen = len; |
|
|
|
memcpy(spi->xbuf, buf, len); |
|
|
|
|
|
|
|
switch (spi->bits) { |
|
|
|
switch (bits) { |
|
|
|
case 8: |
|
|
|
esize = EDMA_OPT_ESIZE_8BIT; |
|
|
|
break; |
|
|
|
case 12: |
|
|
|
case 16: |
|
|
|
esize = EDMA_OPT_ESIZE_16BIT; |
|
|
|
len /= 2; |
|
|
|
len >>= 1; |
|
|
|
break; |
|
|
|
case 20: |
|
|
|
case 24: |
|
|
|
case 32: |
|
|
|
esize = EDMA_OPT_ESIZE_32BIT; |
|
|
|
len /= 4; |
|
|
|
len >>= 2; |
|
|
|
break; |
|
|
|
default: |
|
|
|
return (-2); |
|
|
|
} |
|
|
|
|
|
|
|
CACHE_wbL2(spi->xbuf, len, CACHE_WAIT); |
|
|
|
|
|
|
|
xevent = MCBSP_getXmtEventId(spi->spi); |
|
|
|
|
|
|
|
edma_conf.opt = EDMA_OPT_RMK( |
|
|
@ -492,7 +468,7 @@ int spi_edma_write(int dev_id, const void *buf, int len, void (*notify)(void *ar |
|
|
|
EDMA_OPT_DUM_NONE, |
|
|
|
EDMA_OPT_TCINT_YES, |
|
|
|
EDMA_OPT_TCC_OF(xevent), |
|
|
|
EDMA_OPT_TCCM_OF(xevent >> 4), |
|
|
|
EDMA_OPT_TCCM_OF((xevent >> 4)), |
|
|
|
EDMA_OPT_ATCINT_NO, |
|
|
|
EDMA_OPT_ATCC_OF(0), |
|
|
|
EDMA_OPT_PDTS_DEFAULT, |
|
|
@ -500,11 +476,22 @@ int spi_edma_write(int dev_id, const void *buf, int len, void (*notify)(void *ar |
|
|
|
EDMA_OPT_LINK_NO, |
|
|
|
EDMA_OPT_FS_NO |
|
|
|
); |
|
|
|
edma_conf.src = EDMA_SRC_RMK((Uint32)(spi->xbuf)); |
|
|
|
edma_conf.cnt = EDMA_CNT_RMK(0, len); |
|
|
|
|
|
|
|
if (len > 65535) { |
|
|
|
frmlen = len / 65535 - 1; |
|
|
|
|
|
|
|
if (frmlen > 65535) |
|
|
|
frmlen = 65535; |
|
|
|
|
|
|
|
len = 65535; |
|
|
|
slen = (frmlen + 1) * 65535 * (bits / 8); |
|
|
|
} |
|
|
|
|
|
|
|
edma_conf.src = EDMA_SRC_RMK((Uint32)(buf)); |
|
|
|
edma_conf.cnt = EDMA_CNT_RMK(frmlen, len); |
|
|
|
edma_conf.dst = EDMA_DST_OF(MCBSP_getXmtAddr(spi->spi)); |
|
|
|
edma_conf.idx = EDMA_IDX_RMK(0, 0); |
|
|
|
edma_conf.rld = EDMA_RLD_RMK(0, 0); |
|
|
|
edma_conf.rld = EDMA_RLD_RMK(len, 0); |
|
|
|
|
|
|
|
spi->xnotify = notify; |
|
|
|
spi->xargs = args; |
|
|
@ -512,58 +499,38 @@ int spi_edma_write(int dev_id, const void *buf, int len, void (*notify)(void *ar |
|
|
|
if (spi->xh == NULL) |
|
|
|
spi->xh = EDMA_open(xevent, 0); |
|
|
|
|
|
|
|
edma_attach_tcc_irq(xevent, __tx_notify); |
|
|
|
|
|
|
|
EDMA_config(spi->xh, &edma_conf); |
|
|
|
|
|
|
|
edma_attach_tcc_irq(xevent, __tx_notify, spi); |
|
|
|
|
|
|
|
EDMA_enableChannel(spi->xh); |
|
|
|
|
|
|
|
return (slen); |
|
|
|
} |
|
|
|
|
|
|
|
static int __read_u8(spi_t spi, Uint8 *buf, int len) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_rrdy(spi->spi)) |
|
|
|
; |
|
|
|
buf[i] = MCBSP_read(spi->spi); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
} |
|
|
|
|
|
|
|
static int __read_u16(spi_t spi, Uint16 *buf, int len) |
|
|
|
int spi_edma_write(int dev_id, const void *buf, int len, void (*notify)(void *args), void *args) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
spi_t spi; |
|
|
|
int bits; |
|
|
|
|
|
|
|
len >>= 1; |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_rrdy(spi->spi)) |
|
|
|
; |
|
|
|
buf[i] = MCBSP_read(spi->spi); |
|
|
|
if ((spi = __get_active_device(dev_id)) == NULL) { |
|
|
|
return -2; |
|
|
|
} |
|
|
|
return (len); |
|
|
|
} |
|
|
|
|
|
|
|
static int __read_u32(spi_t spi, Uint32 *buf, int len) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
spi = &__spi_devs[dev_id]; |
|
|
|
|
|
|
|
len >>= 2; |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_rrdy(spi->spi)) |
|
|
|
; |
|
|
|
buf[i] = MCBSP_read(spi->spi); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
bits = spi->bits; /* i2s: 2 channels ? */ |
|
|
|
return __do_spi_edma_write(spi, bits, buf, len, notify, args); |
|
|
|
} |
|
|
|
|
|
|
|
int spi_read(int dev_id, void *buf, int len) |
|
|
|
/* {{{: int spi_read(int dev_id, void *buf, int _len) */ |
|
|
|
int spi_read(int dev_id, void *buf, int _len) |
|
|
|
{ |
|
|
|
Uint8 *u8; |
|
|
|
Uint16 *u16; |
|
|
|
Uint32 *u32; |
|
|
|
spi_t spi; |
|
|
|
int i, len = _len; |
|
|
|
|
|
|
|
if ((spi = __get_active_device(dev_id)) == NULL) { |
|
|
|
return -1; |
|
|
@ -572,25 +539,113 @@ int spi_read(int dev_id, void *buf, int len) |
|
|
|
switch (spi->bits) { |
|
|
|
case 8: |
|
|
|
u8 = buf; |
|
|
|
__read_u8(spi, u8, len); |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_rrdy(spi->spi)) |
|
|
|
; |
|
|
|
u8[i] = MCBSP_read(spi->spi); |
|
|
|
} |
|
|
|
break; |
|
|
|
case 12: |
|
|
|
case 16: |
|
|
|
len >>= 1; |
|
|
|
u16 = buf; |
|
|
|
__read_u16(spi, u16, len); |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_rrdy(spi->spi)) |
|
|
|
; |
|
|
|
u16[i] = MCBSP_read(spi->spi); |
|
|
|
} |
|
|
|
break; |
|
|
|
case 20: |
|
|
|
case 24: |
|
|
|
case 32: |
|
|
|
len >>= 2; |
|
|
|
u32 = buf; |
|
|
|
__read_u32(spi, u32, len); |
|
|
|
for (i = 0; i < len; ++i) { |
|
|
|
while (!MCBSP_rrdy(spi->spi)) |
|
|
|
; |
|
|
|
u32[i] = MCBSP_read(spi->spi); |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
return (len); |
|
|
|
return (_len); |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
int spi_edma_read(int dev_id, void *buf, int len, void (*on_complete)(void *args), void *args) |
|
|
|
{ |
|
|
|
spi_t spi; |
|
|
|
Uint32 esize; |
|
|
|
EDMA_Config edma_conf; |
|
|
|
int xevent, slen = len; |
|
|
|
|
|
|
|
if ((spi = __get_active_device(dev_id)) == NULL) { |
|
|
|
return -2; |
|
|
|
} |
|
|
|
|
|
|
|
spi = &__spi_devs[dev_id]; |
|
|
|
|
|
|
|
switch (spi->bits) { |
|
|
|
case 8: |
|
|
|
esize = EDMA_OPT_ESIZE_8BIT; |
|
|
|
break; |
|
|
|
case 12: |
|
|
|
case 16: |
|
|
|
esize = EDMA_OPT_ESIZE_16BIT; |
|
|
|
len /= 2; |
|
|
|
break; |
|
|
|
case 20: |
|
|
|
case 24: |
|
|
|
case 32: |
|
|
|
esize = EDMA_OPT_ESIZE_32BIT; |
|
|
|
len /= 4; |
|
|
|
break; |
|
|
|
default: |
|
|
|
return (-2); |
|
|
|
} |
|
|
|
|
|
|
|
xevent = MCBSP_getRcvEventId(spi->spi); |
|
|
|
|
|
|
|
edma_conf.opt = EDMA_OPT_RMK( |
|
|
|
EDMA_OPT_PRI_MEDIUM, |
|
|
|
esize, |
|
|
|
EDMA_OPT_2DS_NO, |
|
|
|
EDMA_OPT_SUM_NONE, |
|
|
|
EDMA_OPT_2DD_NO, |
|
|
|
EDMA_OPT_DUM_INC, |
|
|
|
EDMA_OPT_TCINT_YES, |
|
|
|
EDMA_OPT_TCC_OF(xevent), |
|
|
|
EDMA_OPT_TCCM_OF(xevent >> 4), |
|
|
|
EDMA_OPT_ATCINT_NO, |
|
|
|
EDMA_OPT_ATCC_OF(0), |
|
|
|
EDMA_OPT_PDTS_DEFAULT, |
|
|
|
EDMA_OPT_PDTS_DEFAULT, |
|
|
|
EDMA_OPT_LINK_NO, |
|
|
|
EDMA_OPT_FS_NO); |
|
|
|
|
|
|
|
edma_conf.src = EDMA_SRC_OF(MCBSP_getRcvAddr(spi->spi)); |
|
|
|
edma_conf.cnt = EDMA_CNT_RMK(0, len); |
|
|
|
edma_conf.dst = EDMA_DST_RMK((Uint32)(buf)); |
|
|
|
edma_conf.idx = EDMA_IDX_RMK(0, 0); |
|
|
|
edma_conf.rld = EDMA_RLD_RMK(0, 0); |
|
|
|
|
|
|
|
spi->rnotify = on_complete; |
|
|
|
spi->rargs = args; |
|
|
|
|
|
|
|
if (spi->rh == NULL) |
|
|
|
spi->rh = EDMA_open(xevent, 0); |
|
|
|
|
|
|
|
edma_attach_tcc_irq(xevent, __rx_notify, spi); |
|
|
|
|
|
|
|
EDMA_config(spi->rh, &edma_conf); |
|
|
|
|
|
|
|
EDMA_enableChannel(spi->rh); |
|
|
|
|
|
|
|
return (slen); |
|
|
|
} |
|
|
|
|
|
|
|
/* {{{ void spi_close(int dev_id) */ |
|
|
|
void spi_close(int dev_id) |
|
|
|
{ |
|
|
|
spi_t spi; |
|
|
@ -603,4 +658,5 @@ void spi_close(int dev_id) |
|
|
|
spi->spi = NULL; |
|
|
|
spi->bits = 0; |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|