@ -22,14 +22,13 @@
*/
# include <common.h>
# include <malloc .h>
# include <d m.h>
# include <asm/io.h>
# include <asm/gpio.h>
# include <asm/arch/clock.h>
# include <asm/arch-tegra/clk_rst.h>
# include <asm/arch-tegra114/tegra114_spi.h>
# include <spi.h>
# include <fdtdec.h>
# include "tegra_spi.h"
DECLARE_GLOBAL_DATA_PTR ;
@ -104,130 +103,63 @@ struct spi_regs {
u32 spare_ctl ; /* 18c:SPI_SPARE_CTRL register */
} ;
struct tegra_spi_ctrl {
struct tegra114_spi_priv {
struct spi_regs * regs ;
unsigned int freq ;
unsigned int mode ;
int periph_id ;
int valid ;
int last_transaction_us ;
} ;
struct tegra_spi_slave {
struct spi_slave slave ;
struct tegra_spi_ctrl * ctrl ;
} ;
static struct tegra_spi_ctrl spi_ctrls [ CONFIG_TEGRA114_SPI_CTRLS ] ;
static inline struct tegra_spi_slave * to_tegra_spi ( struct spi_slave * slave )
static int tegra114_spi_ofdata_to_platdata ( struct udevice * bus )
{
return container_of ( slave , struct tegra_spi_slave , slave ) ;
}
struct tegra_spi_platdata * plat = bus - > platdata ;
const void * blob = gd - > fdt_blob ;
int node = bus - > of_offset ;
int tegra114_spi_cs_is_valid ( unsigned int bus , unsigned int cs )
{
if ( bus > = CONFIG_TEGRA114_SPI_CTRLS | | cs > 3 | | ! spi_ctrls [ bus ] . valid )
return 0 ;
else
return 1 ;
}
plat - > base = fdtdec_get_addr ( blob , node , " reg " ) ;
plat - > periph_id = clock_decode_periph_id ( blob , node ) ;
struct spi_slave * tegra114_spi_setup_slave ( unsigned int bus , unsigned int cs ,
unsigned int max_hz , unsigned int mode )
{
struct tegra_spi_slave * spi ;
debug ( " %s: bus: %u, cs: %u, max_hz: %u, mode: %u \n " , __func__ ,
bus , cs , max_hz , mode ) ;
if ( ! spi_cs_is_valid ( bus , cs ) ) {
printf ( " SPI error: unsupported bus %d / chip select %d \n " ,
bus , cs ) ;
return NULL ;
}
if ( max_hz > TEGRA_SPI_MAX_FREQ ) {
printf ( " SPI error: unsupported frequency %d Hz. Max frequency "
" is %d Hz \n " , max_hz , TEGRA_SPI_MAX_FREQ ) ;
return NULL ;
if ( plat - > periph_id = = PERIPH_ID_NONE ) {
debug ( " %s: could not decode periph id %d \n " , __func__ ,
plat - > periph_id ) ;
return - FDT_ERR_NOTFOUND ;
}
spi = spi_alloc_slave ( struct tegra_spi_slave , bus , cs ) ;
if ( ! spi ) {
printf ( " SPI error: malloc of SPI structure failed \n " ) ;
return NULL ;
}
spi - > ctrl = & spi_ctrls [ bus ] ;
if ( ! spi - > ctrl ) {
printf ( " SPI error: could not find controller for bus %d \n " ,
bus ) ;
return NULL ;
}
/* Use 500KHz as a suitable default */
plat - > frequency = fdtdec_get_int ( blob , node , " spi-max-frequency " ,
500000 ) ;
plat - > deactivate_delay_us = fdtdec_get_int ( blob , node ,
" spi-deactivate-delay " , 0 ) ;
debug ( " %s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d \n " ,
__func__ , plat - > base , plat - > periph_id , plat - > frequency ,
plat - > deactivate_delay_us ) ;
if ( max_hz < spi - > ctrl - > freq ) {
debug ( " %s: limiting frequency from %u to %u \n " , __func__ ,
spi - > ctrl - > freq , max_hz ) ;
spi - > ctrl - > freq = max_hz ;
}
spi - > ctrl - > mode = mode ;
return & spi - > slave ;
}
void tegra114_spi_free_slave ( struct spi_slave * slave )
{
struct tegra_spi_slave * spi = to_tegra_spi ( slave ) ;
free ( spi ) ;
return 0 ;
}
int tegra114_spi_init ( int * node_list , int count )
static int tegra114_spi_probe ( struct udevice * bus )
{
struct tegra_spi_ctrl * ctrl ;
int i ;
int node = 0 ;
int found = 0 ;
for ( i = 0 ; i < count ; i + + ) {
ctrl = & spi_ctrls [ i ] ;
node = node_list [ i ] ;
ctrl - > regs = ( struct spi_regs * ) fdtdec_get_addr ( gd - > fdt_blob ,
node , " reg " ) ;
if ( ( fdt_addr_t ) ctrl - > regs = = FDT_ADDR_T_NONE ) {
debug ( " %s: no spi register found \n " , __func__ ) ;
continue ;
}
ctrl - > freq = fdtdec_get_int ( gd - > fdt_blob , node ,
" spi-max-frequency " , 0 ) ;
if ( ! ctrl - > freq ) {
debug ( " %s: no spi max frequency found \n " , __func__ ) ;
continue ;
}
struct tegra_spi_platdata * plat = dev_get_platdata ( bus ) ;
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
ctrl - > periph_id = clock_decode_periph_id ( gd - > fdt_blob , node ) ;
if ( ctrl - > periph_id = = PERIPH_ID_NONE ) {
debug ( " %s: could not decode periph id \n " , __func__ ) ;
continue ;
}
ctrl - > valid = 1 ;
found = 1 ;
priv - > regs = ( struct spi_regs * ) plat - > base ;
debug ( " %s: found controller at %p, freq = %u, periph_id = %d \n " ,
__func__ , ctrl - > regs , ctrl - > freq , ctrl - > periph_id ) ;
}
priv - > last_transaction_us = timer_get_us ( ) ;
priv - > freq = plat - > frequency ;
priv - > periph_id = plat - > periph_id ;
return ! found ;
return 0 ;
}
int tegra114_spi_claim_bus ( struct spi_slave * slave )
static int tegra114_spi_claim_bus ( struct udevice * bus )
{
struct tegra_spi_slave * spi = to_tegra_spi ( slave ) ;
struct spi_regs * regs = spi - > ctrl - > regs ;
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
struct spi_regs * regs = priv - > regs ;
/* Change SPI clock to correct frequency, PLLP_OUT0 source */
clock_start_periph_pll ( spi - > ctrl - > periph_id , CLOCK_ID_PERIPH ,
spi - > ctrl - > freq ) ;
clock_start_periph_pll ( priv - > periph_id , CLOCK_ID_PERIPH , priv - > freq ) ;
/* Clear stale status here */
setbits_le32 ( & regs - > fifo_status ,
@ -244,33 +176,64 @@ int tegra114_spi_claim_bus(struct spi_slave *slave)
/* Set master mode and sw controlled CS */
setbits_le32 ( & regs - > command1 , SPI_CMD1_M_S | SPI_CMD1_CS_SW_HW |
( spi - > ctrl - > mode < < SPI_CMD1_MODE_SHIFT ) ) ;
( priv - > mode < < SPI_CMD1_MODE_SHIFT ) ) ;
debug ( " %s: COMMAND1 = %08x \n " , __func__ , readl ( & regs - > command1 ) ) ;
return 0 ;
}
void tegra114_spi_cs_activate ( struct spi_slave * slave )
/**
* Activate the CS by driving it LOW
*
* @ param slave Pointer to spi_slave to which controller has to
* communicate with
*/
static void spi_cs_activate ( struct udevice * dev )
{
struct tegra_spi_slave * spi = to_tegra_spi ( slave ) ;
struct spi_regs * regs = spi - > ctrl - > regs ;
struct udevice * bus = dev - > parent ;
struct tegra_spi_platdata * pdata = dev_get_platdata ( bus ) ;
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
/* If it's too soon to do another transaction, wait */
if ( pdata - > deactivate_delay_us & &
priv - > last_transaction_us ) {
ulong delay_us ; /* The delay completed so far */
delay_us = timer_get_us ( ) - priv - > last_transaction_us ;
if ( delay_us < pdata - > deactivate_delay_us )
udelay ( pdata - > deactivate_delay_us - delay_us ) ;
}
clrbits_le32 ( & regs - > command1 , SPI_CMD1_CS_SW_VAL ) ;
clrbits_le32 ( & priv - > regs - > command1 , SPI_CMD1_CS_SW_VAL ) ;
}
void tegra114_spi_cs_deactivate ( struct spi_slave * slave )
/**
* Deactivate the CS by driving it HIGH
*
* @ param slave Pointer to spi_slave to which controller has to
* communicate with
*/
static void spi_cs_deactivate ( struct udevice * dev )
{
struct tegra_spi_slave * spi = to_tegra_spi ( slave ) ;
struct spi_regs * regs = spi - > ctrl - > regs ;
struct udevice * bus = dev - > parent ;
struct tegra_spi_platdata * pdata = dev_get_platdata ( bus ) ;
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
setbits_le32 ( & priv - > regs - > command1 , SPI_CMD1_CS_SW_VAL ) ;
setbits_le32 ( & regs - > command1 , SPI_CMD1_CS_SW_VAL ) ;
/* Remember time of this transaction so we can honour the bus delay */
if ( pdata - > deactivate_delay_us )
priv - > last_transaction_us = timer_get_us ( ) ;
debug ( " Deactivate CS, bus '%s' \n " , bus - > name ) ;
}
int tegra114_spi_xfer ( struct spi_slave * slave , unsigned int bitlen ,
const void * data_out , void * data_in , unsigned long flags )
static int tegra114_spi_xfer ( struct udevice * dev , unsigned int bitlen ,
const void * data_out , void * data_in ,
unsigned long flags )
{
struct tegra_spi_slave * spi = to_tegra_spi ( slave ) ;
struct spi_regs * regs = spi - > ctrl - > regs ;
struct udevice * bus = dev - > parent ;
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
struct spi_regs * regs = priv - > regs ;
u32 reg , tmpdout , tmpdin = 0 ;
const u8 * dout = data_out ;
u8 * din = data_in ;
@ -278,7 +241,7 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
int ret ;
debug ( " %s: slave %u:%u dout %p din %p bitlen %u \n " ,
__func__ , slave - > bus , slave - > cs , dout , din , bitlen ) ;
__func__ , bu s- > seq , spi_chip_select ( dev ) , dout , din , bitlen ) ;
if ( bitlen % 8 )
return - 1 ;
num_bytes = bitlen / 8 ;
@ -291,13 +254,13 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
clrsetbits_le32 ( & regs - > command1 , SPI_CMD1_CS_SW_VAL ,
SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE |
( slave - > cs < < SPI_CMD1_CS_SEL_SHIFT ) ) ;
( spi_chip_select ( dev ) < < SPI_CMD1_CS_SEL_SHIFT ) ) ;
/* set xfer size to 1 block (32 bits) */
writel ( 0 , & regs - > dma_blk ) ;
if ( flags & SPI_XFER_BEGIN )
spi_cs_activate ( slave ) ;
spi_cs_activate ( dev ) ;
/* handle data in 32-bit chunks */
while ( num_bytes > 0 ) {
@ -383,7 +346,7 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
}
if ( flags & SPI_XFER_END )
spi_cs_deactivate ( slave ) ;
spi_cs_deactivate ( dev ) ;
debug ( " %s: transfer ended. Value=%08x, fifo_status = %08x \n " ,
__func__ , tmpdin , readl ( & regs - > fifo_status ) ) ;
@ -394,5 +357,56 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
return - 1 ;
}
return ret ;
}
static int tegra114_spi_set_speed ( struct udevice * bus , uint speed )
{
struct tegra_spi_platdata * plat = bus - > platdata ;
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
if ( speed > plat - > frequency )
speed = plat - > frequency ;
priv - > freq = speed ;
debug ( " %s: regs=%p, speed=%d \n " , __func__ , priv - > regs , priv - > freq ) ;
return 0 ;
}
static int tegra114_spi_set_mode ( struct udevice * bus , uint mode )
{
struct tegra114_spi_priv * priv = dev_get_priv ( bus ) ;
priv - > mode = mode ;
debug ( " %s: regs=%p, mode=%d \n " , __func__ , priv - > regs , priv - > mode ) ;
return 0 ;
}
static const struct dm_spi_ops tegra114_spi_ops = {
. claim_bus = tegra114_spi_claim_bus ,
. xfer = tegra114_spi_xfer ,
. set_speed = tegra114_spi_set_speed ,
. set_mode = tegra114_spi_set_mode ,
/*
* cs_info is not needed , since we require all chip selects to be
* in the device tree explicitly
*/
} ;
static const struct udevice_id tegra114_spi_ids [ ] = {
{ . compatible = " nvidia,tegra114-spi " } ,
{ }
} ;
U_BOOT_DRIVER ( tegra114_spi ) = {
. name = " tegra114_spi " ,
. id = UCLASS_SPI ,
. of_match = tegra114_spi_ids ,
. ops = & tegra114_spi_ops ,
. ofdata_to_platdata = tegra114_spi_ofdata_to_platdata ,
. platdata_auto_alloc_size = sizeof ( struct tegra_spi_platdata ) ,
. priv_auto_alloc_size = sizeof ( struct tegra114_spi_priv ) ,
. per_child_auto_alloc_size = sizeof ( struct spi_slave ) ,
. probe = tegra114_spi_probe ,
} ;