2021-03-27 12:10:00 +03:00
// SPDX-License-Identifier: GPL-2.0-only
//
// HiSilicon SPI Controller Driver for Kunpeng SoCs
//
// Copyright (c) 2021 HiSilicon Technologies Co., Ltd.
// Author: Jay Fang <f.fangjian@huawei.com>
//
// This code is based on spi-dw-core.c.
# include <linux/acpi.h>
# include <linux/bitfield.h>
2021-06-04 09:55:18 +03:00
# include <linux/debugfs.h>
2021-03-27 12:10:00 +03:00
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <linux/property.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/spi/spi.h>
/* Register offsets */
# define HISI_SPI_CSCR 0x00 /* cs control register */
# define HISI_SPI_CR 0x04 /* spi common control register */
# define HISI_SPI_ENR 0x08 /* spi enable register */
# define HISI_SPI_FIFOC 0x0c /* fifo level control register */
# define HISI_SPI_IMR 0x10 /* interrupt mask register */
# define HISI_SPI_DIN 0x14 /* data in register */
# define HISI_SPI_DOUT 0x18 /* data out register */
# define HISI_SPI_SR 0x1c /* status register */
# define HISI_SPI_RISR 0x20 /* raw interrupt status register */
# define HISI_SPI_ISR 0x24 /* interrupt status register */
# define HISI_SPI_ICR 0x28 /* interrupt clear register */
# define HISI_SPI_VERSION 0xe0 /* version register */
/* Bit fields in HISI_SPI_CR */
# define CR_LOOP_MASK GENMASK(1, 1)
# define CR_CPOL_MASK GENMASK(2, 2)
# define CR_CPHA_MASK GENMASK(3, 3)
# define CR_DIV_PRE_MASK GENMASK(11, 4)
# define CR_DIV_POST_MASK GENMASK(19, 12)
# define CR_BPW_MASK GENMASK(24, 20)
# define CR_SPD_MODE_MASK GENMASK(25, 25)
/* Bit fields in HISI_SPI_FIFOC */
# define FIFOC_TX_MASK GENMASK(5, 3)
# define FIFOC_RX_MASK GENMASK(11, 9)
/* Bit fields in HISI_SPI_IMR, 4 bits */
# define IMR_RXOF BIT(0) /* Receive Overflow */
# define IMR_RXTO BIT(1) /* Receive Timeout */
# define IMR_RX BIT(2) /* Receive */
# define IMR_TX BIT(3) /* Transmit */
# define IMR_MASK (IMR_RXOF | IMR_RXTO | IMR_RX | IMR_TX)
/* Bit fields in HISI_SPI_SR, 5 bits */
# define SR_TXE BIT(0) /* Transmit FIFO empty */
# define SR_TXNF BIT(1) /* Transmit FIFO not full */
# define SR_RXNE BIT(2) /* Receive FIFO not empty */
# define SR_RXF BIT(3) /* Receive FIFO full */
# define SR_BUSY BIT(4) /* Busy Flag */
/* Bit fields in HISI_SPI_ISR, 4 bits */
# define ISR_RXOF BIT(0) /* Receive Overflow */
# define ISR_RXTO BIT(1) /* Receive Timeout */
# define ISR_RX BIT(2) /* Receive */
# define ISR_TX BIT(3) /* Transmit */
# define ISR_MASK (ISR_RXOF | ISR_RXTO | ISR_RX | ISR_TX)
/* Bit fields in HISI_SPI_ICR, 2 bits */
# define ICR_RXOF BIT(0) /* Receive Overflow */
# define ICR_RXTO BIT(1) /* Receive Timeout */
# define ICR_MASK (ICR_RXOF | ICR_RXTO)
# define DIV_POST_MAX 0xFF
# define DIV_POST_MIN 0x00
# define DIV_PRE_MAX 0xFE
# define DIV_PRE_MIN 0x02
# define CLK_DIV_MAX ((1 + DIV_POST_MAX) * DIV_PRE_MAX)
# define CLK_DIV_MIN ((1 + DIV_POST_MIN) * DIV_PRE_MIN)
# define DEFAULT_NUM_CS 1
# define HISI_SPI_WAIT_TIMEOUT_MS 10UL
enum hisi_spi_rx_level_trig {
HISI_SPI_RX_1 ,
HISI_SPI_RX_4 ,
HISI_SPI_RX_8 ,
HISI_SPI_RX_16 ,
HISI_SPI_RX_32 ,
HISI_SPI_RX_64 ,
HISI_SPI_RX_128
} ;
enum hisi_spi_tx_level_trig {
HISI_SPI_TX_1_OR_LESS ,
HISI_SPI_TX_4_OR_LESS ,
HISI_SPI_TX_8_OR_LESS ,
HISI_SPI_TX_16_OR_LESS ,
HISI_SPI_TX_32_OR_LESS ,
HISI_SPI_TX_64_OR_LESS ,
HISI_SPI_TX_128_OR_LESS
} ;
enum hisi_spi_frame_n_bytes {
HISI_SPI_N_BYTES_NULL ,
HISI_SPI_N_BYTES_U8 ,
HISI_SPI_N_BYTES_U16 ,
HISI_SPI_N_BYTES_U32 = 4
} ;
/* Slave spi_dev related */
struct hisi_chip_data {
u32 cr ;
u32 speed_hz ; /* baud rate */
u16 clk_div ; /* baud rate divider */
/* clk_div = (1 + div_post) * div_pre */
u8 div_post ; /* value from 0 to 255 */
u8 div_pre ; /* value from 2 to 254 (even only!) */
} ;
struct hisi_spi {
struct device * dev ;
void __iomem * regs ;
int irq ;
u32 fifo_len ; /* depth of the FIFO buffer */
/* Current message transfer state info */
const void * tx ;
unsigned int tx_len ;
void * rx ;
unsigned int rx_len ;
u8 n_bytes ; /* current is a 1/2/4 bytes op */
2021-06-04 09:55:18 +03:00
struct dentry * debugfs ;
struct debugfs_regset32 regset ;
} ;
# define HISI_SPI_DBGFS_REG(_name, _off) \
{ \
. name = _name , \
. offset = _off , \
}
static const struct debugfs_reg32 hisi_spi_regs [ ] = {
HISI_SPI_DBGFS_REG ( " CSCR " , HISI_SPI_CSCR ) ,
HISI_SPI_DBGFS_REG ( " CR " , HISI_SPI_CR ) ,
HISI_SPI_DBGFS_REG ( " ENR " , HISI_SPI_ENR ) ,
HISI_SPI_DBGFS_REG ( " FIFOC " , HISI_SPI_FIFOC ) ,
HISI_SPI_DBGFS_REG ( " IMR " , HISI_SPI_IMR ) ,
HISI_SPI_DBGFS_REG ( " DIN " , HISI_SPI_DIN ) ,
HISI_SPI_DBGFS_REG ( " DOUT " , HISI_SPI_DOUT ) ,
HISI_SPI_DBGFS_REG ( " SR " , HISI_SPI_SR ) ,
HISI_SPI_DBGFS_REG ( " RISR " , HISI_SPI_RISR ) ,
HISI_SPI_DBGFS_REG ( " ISR " , HISI_SPI_ISR ) ,
HISI_SPI_DBGFS_REG ( " ICR " , HISI_SPI_ICR ) ,
HISI_SPI_DBGFS_REG ( " VERSION " , HISI_SPI_VERSION ) ,
2021-03-27 12:10:00 +03:00
} ;
2021-06-04 09:55:18 +03:00
static int hisi_spi_debugfs_init ( struct hisi_spi * hs )
{
char name [ 32 ] ;
2021-11-17 04:21:19 +03:00
struct spi_controller * master ;
master = container_of ( hs - > dev , struct spi_controller , dev ) ;
snprintf ( name , 32 , " hisi_spi%d " , master - > bus_num ) ;
2021-06-04 09:55:18 +03:00
hs - > debugfs = debugfs_create_dir ( name , NULL ) ;
if ( ! hs - > debugfs )
return - ENOMEM ;
hs - > regset . regs = hisi_spi_regs ;
hs - > regset . nregs = ARRAY_SIZE ( hisi_spi_regs ) ;
hs - > regset . base = hs - > regs ;
debugfs_create_regset32 ( " registers " , 0400 , hs - > debugfs , & hs - > regset ) ;
return 0 ;
}
2021-03-27 12:10:00 +03:00
static u32 hisi_spi_busy ( struct hisi_spi * hs )
{
return readl ( hs - > regs + HISI_SPI_SR ) & SR_BUSY ;
}
static u32 hisi_spi_rx_not_empty ( struct hisi_spi * hs )
{
return readl ( hs - > regs + HISI_SPI_SR ) & SR_RXNE ;
}
static u32 hisi_spi_tx_not_full ( struct hisi_spi * hs )
{
return readl ( hs - > regs + HISI_SPI_SR ) & SR_TXNF ;
}
static void hisi_spi_flush_fifo ( struct hisi_spi * hs )
{
unsigned long limit = loops_per_jiffy < < 1 ;
do {
while ( hisi_spi_rx_not_empty ( hs ) )
readl ( hs - > regs + HISI_SPI_DOUT ) ;
} while ( hisi_spi_busy ( hs ) & & limit - - ) ;
}
/* Disable the controller and all interrupts */
static void hisi_spi_disable ( struct hisi_spi * hs )
{
writel ( 0 , hs - > regs + HISI_SPI_ENR ) ;
writel ( IMR_MASK , hs - > regs + HISI_SPI_IMR ) ;
writel ( ICR_MASK , hs - > regs + HISI_SPI_ICR ) ;
}
static u8 hisi_spi_n_bytes ( struct spi_transfer * transfer )
{
if ( transfer - > bits_per_word < = 8 )
return HISI_SPI_N_BYTES_U8 ;
else if ( transfer - > bits_per_word < = 16 )
return HISI_SPI_N_BYTES_U16 ;
else
return HISI_SPI_N_BYTES_U32 ;
}
static void hisi_spi_reader ( struct hisi_spi * hs )
{
u32 max = min_t ( u32 , hs - > rx_len , hs - > fifo_len ) ;
u32 rxw ;
while ( hisi_spi_rx_not_empty ( hs ) & & max - - ) {
rxw = readl ( hs - > regs + HISI_SPI_DOUT ) ;
/* Check the transfer's original "rx" is not null */
if ( hs - > rx ) {
switch ( hs - > n_bytes ) {
case HISI_SPI_N_BYTES_U8 :
* ( u8 * ) ( hs - > rx ) = rxw ;
break ;
case HISI_SPI_N_BYTES_U16 :
* ( u16 * ) ( hs - > rx ) = rxw ;
break ;
case HISI_SPI_N_BYTES_U32 :
* ( u32 * ) ( hs - > rx ) = rxw ;
break ;
}
hs - > rx + = hs - > n_bytes ;
}
- - hs - > rx_len ;
}
}
static void hisi_spi_writer ( struct hisi_spi * hs )
{
u32 max = min_t ( u32 , hs - > tx_len , hs - > fifo_len ) ;
u32 txw = 0 ;
while ( hisi_spi_tx_not_full ( hs ) & & max - - ) {
/* Check the transfer's original "tx" is not null */
if ( hs - > tx ) {
switch ( hs - > n_bytes ) {
case HISI_SPI_N_BYTES_U8 :
txw = * ( u8 * ) ( hs - > tx ) ;
break ;
case HISI_SPI_N_BYTES_U16 :
txw = * ( u16 * ) ( hs - > tx ) ;
break ;
case HISI_SPI_N_BYTES_U32 :
txw = * ( u32 * ) ( hs - > tx ) ;
break ;
}
hs - > tx + = hs - > n_bytes ;
}
writel ( txw , hs - > regs + HISI_SPI_DIN ) ;
- - hs - > tx_len ;
}
}
static void __hisi_calc_div_reg ( struct hisi_chip_data * chip )
{
chip - > div_pre = DIV_PRE_MAX ;
while ( chip - > div_pre > = DIV_PRE_MIN ) {
if ( chip - > clk_div % chip - > div_pre = = 0 )
break ;
chip - > div_pre - = 2 ;
}
if ( chip - > div_pre > chip - > clk_div )
chip - > div_pre = chip - > clk_div ;
chip - > div_post = ( chip - > clk_div / chip - > div_pre ) - 1 ;
}
static u32 hisi_calc_effective_speed ( struct spi_controller * master ,
struct hisi_chip_data * chip , u32 speed_hz )
{
u32 effective_speed ;
/* Note clock divider doesn't support odd numbers */
chip - > clk_div = DIV_ROUND_UP ( master - > max_speed_hz , speed_hz ) + 1 ;
chip - > clk_div & = 0xfffe ;
if ( chip - > clk_div > CLK_DIV_MAX )
chip - > clk_div = CLK_DIV_MAX ;
effective_speed = master - > max_speed_hz / chip - > clk_div ;
if ( chip - > speed_hz ! = effective_speed ) {
__hisi_calc_div_reg ( chip ) ;
chip - > speed_hz = effective_speed ;
}
return effective_speed ;
}
static u32 hisi_spi_prepare_cr ( struct spi_device * spi )
{
u32 cr = FIELD_PREP ( CR_SPD_MODE_MASK , 1 ) ;
cr | = FIELD_PREP ( CR_CPHA_MASK , ( spi - > mode & SPI_CPHA ) ? 1 : 0 ) ;
cr | = FIELD_PREP ( CR_CPOL_MASK , ( spi - > mode & SPI_CPOL ) ? 1 : 0 ) ;
cr | = FIELD_PREP ( CR_LOOP_MASK , ( spi - > mode & SPI_LOOP ) ? 1 : 0 ) ;
return cr ;
}
static void hisi_spi_hw_init ( struct hisi_spi * hs )
{
hisi_spi_disable ( hs ) ;
/* FIFO default config */
writel ( FIELD_PREP ( FIFOC_TX_MASK , HISI_SPI_TX_64_OR_LESS ) |
FIELD_PREP ( FIFOC_RX_MASK , HISI_SPI_RX_16 ) ,
hs - > regs + HISI_SPI_FIFOC ) ;
hs - > fifo_len = 256 ;
}
static irqreturn_t hisi_spi_irq ( int irq , void * dev_id )
{
struct spi_controller * master = dev_id ;
struct hisi_spi * hs = spi_controller_get_devdata ( master ) ;
u32 irq_status = readl ( hs - > regs + HISI_SPI_ISR ) & ISR_MASK ;
if ( ! irq_status )
return IRQ_NONE ;
if ( ! master - > cur_msg )
return IRQ_HANDLED ;
/* Error handling */
if ( irq_status & ISR_RXOF ) {
dev_err ( hs - > dev , " interrupt_transfer: fifo overflow \n " ) ;
master - > cur_msg - > status = - EIO ;
goto finalize_transfer ;
}
/*
* Read data from the Rx FIFO every time . If there is
* nothing left to receive , finalize the transfer .
*/
hisi_spi_reader ( hs ) ;
if ( ! hs - > rx_len )
goto finalize_transfer ;
/* Send data out when Tx FIFO IRQ triggered */
if ( irq_status & ISR_TX )
hisi_spi_writer ( hs ) ;
return IRQ_HANDLED ;
finalize_transfer :
hisi_spi_disable ( hs ) ;
spi_finalize_current_transfer ( master ) ;
return IRQ_HANDLED ;
}
static int hisi_spi_transfer_one ( struct spi_controller * master ,
struct spi_device * spi , struct spi_transfer * transfer )
{
struct hisi_spi * hs = spi_controller_get_devdata ( master ) ;
struct hisi_chip_data * chip = spi_get_ctldata ( spi ) ;
u32 cr = chip - > cr ;
/* Update per transfer options for speed and bpw */
transfer - > effective_speed_hz =
hisi_calc_effective_speed ( master , chip , transfer - > speed_hz ) ;
cr | = FIELD_PREP ( CR_DIV_PRE_MASK , chip - > div_pre ) ;
cr | = FIELD_PREP ( CR_DIV_POST_MASK , chip - > div_post ) ;
cr | = FIELD_PREP ( CR_BPW_MASK , transfer - > bits_per_word - 1 ) ;
writel ( cr , hs - > regs + HISI_SPI_CR ) ;
hisi_spi_flush_fifo ( hs ) ;
hs - > n_bytes = hisi_spi_n_bytes ( transfer ) ;
hs - > tx = transfer - > tx_buf ;
hs - > tx_len = transfer - > len / hs - > n_bytes ;
hs - > rx = transfer - > rx_buf ;
hs - > rx_len = hs - > tx_len ;
/*
* Ensure that the transfer data above has been updated
* before the interrupt to start .
*/
smp_mb ( ) ;
/* Enable all interrupts and the controller */
2021-04-07 05:31:00 +03:00
writel ( ~ ( u32 ) IMR_MASK , hs - > regs + HISI_SPI_IMR ) ;
2021-03-27 12:10:00 +03:00
writel ( 1 , hs - > regs + HISI_SPI_ENR ) ;
return 1 ;
}
static void hisi_spi_handle_err ( struct spi_controller * master ,
struct spi_message * msg )
{
struct hisi_spi * hs = spi_controller_get_devdata ( master ) ;
hisi_spi_disable ( hs ) ;
/*
* Wait for interrupt handler that is
* already in timeout to complete .
*/
msleep ( HISI_SPI_WAIT_TIMEOUT_MS ) ;
}
static int hisi_spi_setup ( struct spi_device * spi )
{
struct hisi_chip_data * chip ;
/* Only alloc on first setup */
chip = spi_get_ctldata ( spi ) ;
if ( ! chip ) {
chip = kzalloc ( sizeof ( * chip ) , GFP_KERNEL ) ;
if ( ! chip )
return - ENOMEM ;
spi_set_ctldata ( spi , chip ) ;
}
chip - > cr = hisi_spi_prepare_cr ( spi ) ;
return 0 ;
}
static void hisi_spi_cleanup ( struct spi_device * spi )
{
struct hisi_chip_data * chip = spi_get_ctldata ( spi ) ;
kfree ( chip ) ;
spi_set_ctldata ( spi , NULL ) ;
}
static int hisi_spi_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct spi_controller * master ;
struct hisi_spi * hs ;
int ret , irq ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return irq ;
master = devm_spi_alloc_master ( dev , sizeof ( * hs ) ) ;
if ( ! master )
return - ENOMEM ;
platform_set_drvdata ( pdev , master ) ;
hs = spi_controller_get_devdata ( master ) ;
hs - > dev = dev ;
hs - > irq = irq ;
hs - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( hs - > regs ) )
return PTR_ERR ( hs - > regs ) ;
/* Specify maximum SPI clocking speed (master only) by firmware */
ret = device_property_read_u32 ( dev , " spi-max-frequency " ,
& master - > max_speed_hz ) ;
if ( ret ) {
dev_err ( dev , " failed to get max SPI clocking speed, ret=%d \n " ,
ret ) ;
return - EINVAL ;
}
ret = device_property_read_u16 ( dev , " num-cs " ,
& master - > num_chipselect ) ;
if ( ret )
master - > num_chipselect = DEFAULT_NUM_CS ;
master - > use_gpio_descriptors = true ;
master - > mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP ;
master - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 4 , 32 ) ;
2021-11-17 04:21:19 +03:00
master - > bus_num = pdev - > id ;
2021-03-27 12:10:00 +03:00
master - > setup = hisi_spi_setup ;
master - > cleanup = hisi_spi_cleanup ;
master - > transfer_one = hisi_spi_transfer_one ;
master - > handle_err = hisi_spi_handle_err ;
master - > dev . fwnode = dev - > fwnode ;
hisi_spi_hw_init ( hs ) ;
ret = devm_request_irq ( dev , hs - > irq , hisi_spi_irq , 0 , dev_name ( dev ) ,
master ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to get IRQ=%d, ret=%d \n " , hs - > irq , ret ) ;
return ret ;
}
ret = spi_register_controller ( master ) ;
if ( ret ) {
dev_err ( dev , " failed to register spi master, ret=%d \n " , ret ) ;
return ret ;
}
2021-11-17 04:21:19 +03:00
if ( hisi_spi_debugfs_init ( hs ) )
dev_info ( dev , " failed to create debugfs dir \n " ) ;
2021-03-27 12:10:00 +03:00
dev_info ( dev , " hw version:0x%x max-freq:%u kHz \n " ,
readl ( hs - > regs + HISI_SPI_VERSION ) ,
master - > max_speed_hz / 1000 ) ;
return 0 ;
}
static int hisi_spi_remove ( struct platform_device * pdev )
{
struct spi_controller * master = platform_get_drvdata ( pdev ) ;
2021-06-04 09:55:18 +03:00
struct hisi_spi * hs = spi_controller_get_devdata ( master ) ;
2021-03-27 12:10:00 +03:00
2021-06-04 09:55:18 +03:00
debugfs_remove_recursive ( hs - > debugfs ) ;
2021-03-27 12:10:00 +03:00
spi_unregister_controller ( master ) ;
return 0 ;
}
static const struct acpi_device_id hisi_spi_acpi_match [ ] = {
{ " HISI03E1 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , hisi_spi_acpi_match ) ;
static struct platform_driver hisi_spi_driver = {
. probe = hisi_spi_probe ,
. remove = hisi_spi_remove ,
. driver = {
. name = " hisi-kunpeng-spi " ,
. acpi_match_table = hisi_spi_acpi_match ,
} ,
} ;
module_platform_driver ( hisi_spi_driver ) ;
MODULE_AUTHOR ( " Jay Fang <f.fangjian@huawei.com> " ) ;
MODULE_DESCRIPTION ( " HiSilicon SPI Controller Driver for Kunpeng SoCs " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;