src: Rename source folders for atsam and atsamd architectures
Signed-off-by: Florian Heilmann <Florian.Heilmann@gmx.net>
This commit is contained in:
committed by
KevinOConnor
parent
432e6c490a
commit
6256599a6d
285
src/atsam/spi.c
Normal file
285
src/atsam/spi.c
Normal file
@@ -0,0 +1,285 @@
|
||||
// SPI transmissions on sam3
|
||||
//
|
||||
// Copyright (C) 2018 Petri Honkala <cruwaller@gmail.com>
|
||||
// Copyright (C) 2018 Florian Heilmann <Florian.Heilmann@gmx.net>
|
||||
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "command.h" // shutdown
|
||||
#include "gpio.h" // spi_setup
|
||||
#include "internal.h" // gpio_peripheral
|
||||
#include "sched.h" // sched_shutdown
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* SPI/USART buses and pins
|
||||
****************************************************************/
|
||||
|
||||
struct spi_info {
|
||||
void *dev;
|
||||
uint32_t dev_id;
|
||||
uint8_t miso_pin, mosi_pin, sck_pin, rxtx_periph, sck_periph;
|
||||
};
|
||||
|
||||
static const struct spi_info spi_bus[] = {
|
||||
#if CONFIG_MACH_SAM3X8E
|
||||
{ SPI0, ID_SPI0, GPIO('A', 25), GPIO('A', 26), GPIO('A', 27), 'A', 'A' },
|
||||
{ USART0, ID_USART0, GPIO('A', 10), GPIO('A', 11), GPIO('A', 17), 'A', 'B'},
|
||||
{ USART1, ID_USART1, GPIO('A', 12), GPIO('A', 13), GPIO('A', 16), 'A', 'A'},
|
||||
{ USART2, ID_USART2, GPIO('B', 21), GPIO('B', 20), GPIO('B', 24), 'A', 'A'},
|
||||
#elif CONFIG_MACH_SAM4S8C
|
||||
{ SPI, ID_SPI, GPIO('A', 12), GPIO('A', 13), GPIO('A', 14), 'A', 'A' },
|
||||
{ USART0, ID_USART0, GPIO('A', 5), GPIO('A', 6), GPIO('A', 2), 'A', 'B' },
|
||||
{ USART1, ID_USART1, GPIO('A', 21), GPIO('A', 22), GPIO('A', 23), 'A', 'A'},
|
||||
#elif CONFIG_MACH_SAM4E8E
|
||||
{ USART0, ID_USART0, GPIO('B', 0), GPIO('B', 1), GPIO('B', 13), 'C', 'C' },
|
||||
{ USART1, ID_USART1, GPIO('A', 21), GPIO('A', 22), GPIO('A', 23), 'A', 'A'},
|
||||
{ SPI, ID_SPI, GPIO('A', 12), GPIO('A', 13), GPIO('A', 14), 'A', 'A' },
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
is_spihw(void *dev)
|
||||
{
|
||||
#if CONFIG_MACH_SAM3X8E
|
||||
return dev == SPI0;
|
||||
#else
|
||||
return dev == SPI;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
init_pins(uint32_t bus)
|
||||
{
|
||||
const struct spi_info *si = &spi_bus[bus];
|
||||
gpio_peripheral(si->sck_pin, si->sck_periph, 0);
|
||||
gpio_peripheral(si->miso_pin, si->rxtx_periph, 1);
|
||||
gpio_peripheral(si->mosi_pin, si->rxtx_periph, 0);
|
||||
enable_pclock(si->dev_id);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* SPI hardware
|
||||
****************************************************************/
|
||||
|
||||
#define CHANNEL 0 // Use same channel for all
|
||||
|
||||
static void
|
||||
spihw_init(uint32_t bus)
|
||||
{
|
||||
init_pins(bus);
|
||||
Spi *pSpi = spi_bus[bus].dev;
|
||||
|
||||
/* Disable SPI */
|
||||
pSpi->SPI_CR = SPI_CR_SPIDIS;
|
||||
/* Execute a software reset of the SPI twice */
|
||||
pSpi->SPI_CR = SPI_CR_SWRST;
|
||||
pSpi->SPI_CR = SPI_CR_SWRST;
|
||||
|
||||
pSpi->SPI_MR = ( SPI_MR_MSTR | // Set master mode
|
||||
SPI_MR_MODFDIS | // Disable fault detection
|
||||
SPI_MR_PCS(CHANNEL) // Fixes peripheral select
|
||||
);
|
||||
pSpi->SPI_IDR = 0xffffffff; // Disable ISRs
|
||||
|
||||
/* Clear Chip Select Registers */
|
||||
pSpi->SPI_CSR[0] = 0;
|
||||
pSpi->SPI_CSR[1] = 0;
|
||||
pSpi->SPI_CSR[2] = 0;
|
||||
pSpi->SPI_CSR[3] = 0;
|
||||
|
||||
/* Set basic channel config */
|
||||
pSpi->SPI_CSR[CHANNEL] = 0;
|
||||
/* Enable SPI */
|
||||
pSpi->SPI_CR = SPI_CR_SPIEN;
|
||||
}
|
||||
|
||||
static struct spi_config
|
||||
spihw_setup(uint32_t bus, uint8_t mode, uint32_t rate)
|
||||
{
|
||||
// Make sure bus is enabled
|
||||
spihw_init(bus);
|
||||
|
||||
uint32_t config = 0;
|
||||
uint32_t clockDiv;
|
||||
if (rate < (CHIP_FREQ_CPU_MAX / 255)) {
|
||||
clockDiv = 255;
|
||||
} else if (rate >= (CHIP_FREQ_CPU_MAX / 2)) {
|
||||
clockDiv = 2;
|
||||
} else {
|
||||
clockDiv = (CHIP_FREQ_CPU_MAX / (rate + 1)) + 1;
|
||||
}
|
||||
|
||||
/****** Will be written to SPI_CSRx register ******/
|
||||
// CSAAT : Chip Select Active After Transfer
|
||||
config = SPI_CSR_CSAAT;
|
||||
config |= SPI_CSR_BITS_8_BIT; // TODO: support for SPI_CSR_BITS_16_BIT
|
||||
// NOTE: NCPHA is inverted, CPHA normal!!
|
||||
switch(mode) {
|
||||
case 0:
|
||||
config |= SPI_CSR_NCPHA;
|
||||
break;
|
||||
case 1:
|
||||
config |= 0;
|
||||
break;
|
||||
case 2:
|
||||
config |= SPI_CSR_NCPHA;
|
||||
config |= SPI_CSR_CPOL;
|
||||
break;
|
||||
case 3:
|
||||
config |= SPI_CSR_CPOL;
|
||||
break;
|
||||
};
|
||||
|
||||
config |= ((clockDiv & 0xffu) << SPI_CSR_SCBR_Pos);
|
||||
return (struct spi_config){ .spidev = spi_bus[bus].dev, .cfg = config };
|
||||
}
|
||||
|
||||
static void
|
||||
spihw_prepare(struct spi_config config)
|
||||
{
|
||||
Spi *pSpi = config.spidev;
|
||||
pSpi->SPI_CSR[CHANNEL] = config.cfg;
|
||||
}
|
||||
|
||||
static void
|
||||
spihw_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data)
|
||||
{
|
||||
Spi *pSpi = config.spidev;
|
||||
if (receive_data) {
|
||||
while (len--) {
|
||||
pSpi->SPI_TDR = *data;
|
||||
// wait for receive register
|
||||
while (!(pSpi->SPI_SR & SPI_SR_RDRF))
|
||||
;
|
||||
// get data
|
||||
*data++ = pSpi->SPI_RDR;
|
||||
}
|
||||
} else {
|
||||
while (len--) {
|
||||
pSpi->SPI_TDR = *data++;
|
||||
// wait for receive register
|
||||
while (!(pSpi->SPI_SR & SPI_SR_RDRF))
|
||||
;
|
||||
// read data (to clear RDRF)
|
||||
pSpi->SPI_RDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* USART hardware
|
||||
****************************************************************/
|
||||
|
||||
static struct spi_config
|
||||
usart_setup(uint32_t bus, uint8_t mode, uint32_t rate)
|
||||
{
|
||||
init_pins(bus);
|
||||
Usart *p_usart = spi_bus[bus].dev;
|
||||
|
||||
p_usart->US_MR = 0;
|
||||
p_usart->US_RTOR = 0;
|
||||
p_usart->US_TTGR = 0;
|
||||
|
||||
p_usart->US_CR = US_CR_RSTTX | US_CR_RSTRX | US_CR_TXDIS | US_CR_RXDIS;
|
||||
|
||||
uint32_t br = DIV_ROUND_UP(CHIP_FREQ_CPU_MAX, rate);
|
||||
p_usart->US_BRGR = br << US_BRGR_CD_Pos;
|
||||
|
||||
uint32_t reg = US_MR_CHRL_8_BIT |
|
||||
US_MR_USART_MODE_SPI_MASTER |
|
||||
US_MR_CLKO |
|
||||
US_MR_CHMODE_NORMAL;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
reg |= US_MR_CPHA;
|
||||
reg &= ~US_MR_CPOL;
|
||||
break;
|
||||
case 1:
|
||||
reg &= ~US_MR_CPHA;
|
||||
reg &= ~US_MR_CPOL;
|
||||
break;
|
||||
case 2:
|
||||
reg |= US_MR_CPHA;
|
||||
reg |= US_MR_CPOL;
|
||||
break;
|
||||
case 3:
|
||||
reg &= ~US_MR_CPHA;
|
||||
reg |= US_MR_CPOL;
|
||||
break;
|
||||
}
|
||||
|
||||
p_usart->US_MR |= reg;
|
||||
p_usart->US_CR = US_CR_RXEN | US_CR_TXEN;
|
||||
return (struct spi_config){ .spidev=p_usart, .cfg=p_usart->US_MR };
|
||||
}
|
||||
|
||||
static void
|
||||
usart_prepare(struct spi_config config)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
usart_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data)
|
||||
{
|
||||
Usart *p_usart = config.spidev;
|
||||
if (receive_data) {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
uint32_t co = (uint32_t)*data & 0x000000FF;
|
||||
while(!(p_usart->US_CSR & US_CSR_TXRDY)) {}
|
||||
p_usart->US_THR = US_THR_TXCHR(co);
|
||||
uint32_t ci = 0;
|
||||
while(!(p_usart->US_CSR & US_CSR_RXRDY)) {}
|
||||
ci = p_usart->US_RHR & US_RHR_RXCHR_Msk;
|
||||
*data++ = (uint8_t)ci;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
uint32_t co = (uint32_t)*data & 0x000000FF;
|
||||
while(!(p_usart->US_CSR & US_CSR_TXRDY)) {}
|
||||
p_usart->US_THR = US_THR_TXCHR(co);
|
||||
while(!(p_usart->US_CSR & US_CSR_RXRDY)) {}
|
||||
(void)(p_usart->US_RHR & US_RHR_RXCHR_Msk);
|
||||
(void)*data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Interface
|
||||
****************************************************************/
|
||||
|
||||
struct spi_config
|
||||
spi_setup(uint32_t bus, uint8_t mode, uint32_t rate)
|
||||
{
|
||||
if (bus >= ARRAY_SIZE(spi_bus))
|
||||
shutdown("Invalid spi bus");
|
||||
if (is_spihw(spi_bus[bus].dev))
|
||||
return spihw_setup(bus, mode, rate);
|
||||
return usart_setup(bus, mode, rate);
|
||||
}
|
||||
|
||||
void
|
||||
spi_prepare(struct spi_config config)
|
||||
{
|
||||
if (is_spihw(config.spidev))
|
||||
spihw_prepare(config);
|
||||
else
|
||||
usart_prepare(config);
|
||||
}
|
||||
|
||||
void
|
||||
spi_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data)
|
||||
{
|
||||
if (is_spihw(config.spidev))
|
||||
spihw_transfer(config, receive_data, len, data);
|
||||
else
|
||||
usart_transfer(config, receive_data, len, data);
|
||||
}
|
||||
Reference in New Issue
Block a user