2021-01-20 14:59:28 +01:00
// SPDX-License-Identifier: GPL-2.0-only
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/mod_devicetable.h>
# include <linux/spi/spi.h>
struct rtspi {
void __iomem * base ;
} ;
/* SPI Flash Configuration Register */
# define RTL_SPI_SFCR 0x00
# define RTL_SPI_SFCR_RBO BIT(28)
# define RTL_SPI_SFCR_WBO BIT(27)
/* SPI Flash Control and Status Register */
# define RTL_SPI_SFCSR 0x08
# define RTL_SPI_SFCSR_CSB0 BIT(31)
# define RTL_SPI_SFCSR_CSB1 BIT(30)
# define RTL_SPI_SFCSR_RDY BIT(27)
# define RTL_SPI_SFCSR_CS BIT(24)
# define RTL_SPI_SFCSR_LEN_MASK ~(0x03 << 28)
# define RTL_SPI_SFCSR_LEN1 (0x00 << 28)
# define RTL_SPI_SFCSR_LEN4 (0x03 << 28)
/* SPI Flash Data Register */
# define RTL_SPI_SFDR 0x0c
# define REG(x) (rtspi->base + x)
static void rt_set_cs ( struct spi_device * spi , bool active )
{
struct rtspi * rtspi = spi_controller_get_devdata ( spi - > controller ) ;
u32 value ;
/* CS0 bit is active low */
value = readl ( REG ( RTL_SPI_SFCSR ) ) ;
if ( active )
value | = RTL_SPI_SFCSR_CSB0 ;
else
value & = ~ RTL_SPI_SFCSR_CSB0 ;
writel ( value , REG ( RTL_SPI_SFCSR ) ) ;
}
static void set_size ( struct rtspi * rtspi , int size )
{
u32 value ;
value = readl ( REG ( RTL_SPI_SFCSR ) ) ;
value & = RTL_SPI_SFCSR_LEN_MASK ;
if ( size = = 4 )
value | = RTL_SPI_SFCSR_LEN4 ;
else if ( size = = 1 )
value | = RTL_SPI_SFCSR_LEN1 ;
writel ( value , REG ( RTL_SPI_SFCSR ) ) ;
}
static inline void wait_ready ( struct rtspi * rtspi )
{
while ( ! ( readl ( REG ( RTL_SPI_SFCSR ) ) & RTL_SPI_SFCSR_RDY ) )
cpu_relax ( ) ;
}
static void send4 ( struct rtspi * rtspi , const u32 * buf )
{
wait_ready ( rtspi ) ;
set_size ( rtspi , 4 ) ;
writel ( * buf , REG ( RTL_SPI_SFDR ) ) ;
}
static void send1 ( struct rtspi * rtspi , const u8 * buf )
{
wait_ready ( rtspi ) ;
set_size ( rtspi , 1 ) ;
writel ( buf [ 0 ] < < 24 , REG ( RTL_SPI_SFDR ) ) ;
}
static void rcv4 ( struct rtspi * rtspi , u32 * buf )
{
wait_ready ( rtspi ) ;
set_size ( rtspi , 4 ) ;
* buf = readl ( REG ( RTL_SPI_SFDR ) ) ;
}
static void rcv1 ( struct rtspi * rtspi , u8 * buf )
{
wait_ready ( rtspi ) ;
set_size ( rtspi , 1 ) ;
* buf = readl ( REG ( RTL_SPI_SFDR ) ) > > 24 ;
}
static int transfer_one ( struct spi_controller * ctrl , struct spi_device * spi ,
struct spi_transfer * xfer )
{
struct rtspi * rtspi = spi_controller_get_devdata ( ctrl ) ;
void * rx_buf ;
const void * tx_buf ;
int cnt ;
tx_buf = xfer - > tx_buf ;
rx_buf = xfer - > rx_buf ;
cnt = xfer - > len ;
if ( tx_buf ) {
while ( cnt > = 4 ) {
send4 ( rtspi , tx_buf ) ;
tx_buf + = 4 ;
cnt - = 4 ;
}
while ( cnt ) {
send1 ( rtspi , tx_buf ) ;
tx_buf + + ;
cnt - - ;
}
} else if ( rx_buf ) {
while ( cnt > = 4 ) {
rcv4 ( rtspi , rx_buf ) ;
rx_buf + = 4 ;
cnt - = 4 ;
}
while ( cnt ) {
rcv1 ( rtspi , rx_buf ) ;
rx_buf + + ;
cnt - - ;
}
}
spi_finalize_current_transfer ( ctrl ) ;
return 0 ;
}
static void init_hw ( struct rtspi * rtspi )
{
u32 value ;
/* Turn on big-endian byte ordering */
value = readl ( REG ( RTL_SPI_SFCR ) ) ;
value | = RTL_SPI_SFCR_RBO | RTL_SPI_SFCR_WBO ;
writel ( value , REG ( RTL_SPI_SFCR ) ) ;
value = readl ( REG ( RTL_SPI_SFCSR ) ) ;
/* Permanently disable CS1, since it's never used */
value | = RTL_SPI_SFCSR_CSB1 ;
/* Select CS0 for use */
value & = RTL_SPI_SFCSR_CS ;
writel ( value , REG ( RTL_SPI_SFCSR ) ) ;
}
static int realtek_rtl_spi_probe ( struct platform_device * pdev )
{
struct spi_controller * ctrl ;
struct rtspi * rtspi ;
int err ;
2023-08-18 17:31:42 +08:00
ctrl = devm_spi_alloc_host ( & pdev - > dev , sizeof ( * rtspi ) ) ;
2021-01-20 14:59:28 +01:00
if ( ! ctrl ) {
dev_err ( & pdev - > dev , " Error allocating SPI controller \n " ) ;
return - ENOMEM ;
}
platform_set_drvdata ( pdev , ctrl ) ;
rtspi = spi_controller_get_devdata ( ctrl ) ;
rtspi - > base = devm_platform_get_and_ioremap_resource ( pdev , 0 , NULL ) ;
if ( IS_ERR ( rtspi - > base ) ) {
dev_err ( & pdev - > dev , " Could not map SPI register address " ) ;
return - ENOMEM ;
}
init_hw ( rtspi ) ;
ctrl - > dev . of_node = pdev - > dev . of_node ;
ctrl - > flags = SPI_CONTROLLER_HALF_DUPLEX ;
ctrl - > set_cs = rt_set_cs ;
ctrl - > transfer_one = transfer_one ;
err = devm_spi_register_controller ( & pdev - > dev , ctrl ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Could not register SPI controller \n " ) ;
return - ENODEV ;
}
return 0 ;
}
static const struct of_device_id realtek_rtl_spi_of_ids [ ] = {
{ . compatible = " realtek,rtl8380-spi " } ,
{ . compatible = " realtek,rtl8382-spi " } ,
{ . compatible = " realtek,rtl8391-spi " } ,
{ . compatible = " realtek,rtl8392-spi " } ,
{ . compatible = " realtek,rtl8393-spi " } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , realtek_rtl_spi_of_ids ) ;
static struct platform_driver realtek_rtl_spi_driver = {
. probe = realtek_rtl_spi_probe ,
. driver = {
. name = " realtek-rtl-spi " ,
. of_match_table = realtek_rtl_spi_of_ids ,
} ,
} ;
module_platform_driver ( realtek_rtl_spi_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Bert Vermeulen <bert@biot.com> " ) ;
MODULE_DESCRIPTION ( " Realtek RTL SPI driver " ) ;