2019-02-01 13:17:07 +03:00
// SPDX-License-Identifier: GPL-2.0
2019-03-25 11:29:25 +03:00
//
// spi-mt7621.c -- MediaTek MT7621 SPI controller driver
//
// Copyright (C) 2011 Sergiy <piratfm@gmail.com>
// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
//
// Some parts are based on spi-orion.c:
// Author: Shadi Ammouri <shadi@marvell.com>
// Copyright (C) 2007-2008 Marvell Ltd.
2018-03-14 23:22:35 +03:00
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/io.h>
2019-02-01 13:17:08 +03:00
# include <linux/module.h>
# include <linux/of_device.h>
2018-03-14 23:22:35 +03:00
# include <linux/reset.h>
# include <linux/spi/spi.h>
2019-02-01 13:17:11 +03:00
# define DRIVER_NAME "spi-mt7621"
2018-03-14 23:22:35 +03:00
/* in usec */
2019-02-01 13:17:11 +03:00
# define RALINK_SPI_WAIT_MAX_LOOP 2000
2018-03-14 23:22:35 +03:00
/* SPISTAT register bit field */
2019-02-01 13:17:11 +03:00
# define SPISTAT_BUSY BIT(0)
2018-03-14 23:22:35 +03:00
# define MT7621_SPI_TRANS 0x00
# define SPITRANS_BUSY BIT(16)
# define MT7621_SPI_OPCODE 0x04
# define MT7621_SPI_DATA0 0x08
# define MT7621_SPI_DATA4 0x18
# define SPI_CTL_TX_RX_CNT_MASK 0xff
# define SPI_CTL_START BIT(8)
# define MT7621_SPI_MASTER 0x28
2019-02-01 13:17:14 +03:00
# define MASTER_MORE_BUFMODE BIT(2)
# define MASTER_FULL_DUPLEX BIT(10)
# define MASTER_RS_CLK_SEL GENMASK(27, 16)
# define MASTER_RS_CLK_SEL_SHIFT 16
# define MASTER_RS_SLAVE_SEL GENMASK(31, 29)
2018-03-14 23:22:35 +03:00
# define MT7621_SPI_MOREBUF 0x2c
2019-02-01 13:17:13 +03:00
# define MT7621_SPI_POLAR 0x38
2018-03-14 23:22:35 +03:00
# define MT7621_SPI_SPACE 0x3c
# define MT7621_CPHA BIT(5)
# define MT7621_CPOL BIT(4)
# define MT7621_LSB_FIRST BIT(3)
struct mt7621_spi {
2019-03-25 11:29:25 +03:00
struct spi_controller * master ;
2018-03-14 23:22:35 +03:00
void __iomem * base ;
unsigned int sys_freq ;
unsigned int speed ;
2018-06-07 01:04:21 +03:00
int pending_write ;
2018-03-14 23:22:35 +03:00
} ;
static inline struct mt7621_spi * spidev_to_mt7621_spi ( struct spi_device * spi )
{
2019-03-25 11:29:25 +03:00
return spi_controller_get_devdata ( spi - > master ) ;
2018-03-14 23:22:35 +03:00
}
static inline u32 mt7621_spi_read ( struct mt7621_spi * rs , u32 reg )
{
return ioread32 ( rs - > base + reg ) ;
}
static inline void mt7621_spi_write ( struct mt7621_spi * rs , u32 reg , u32 val )
{
iowrite32 ( val , rs - > base + reg ) ;
}
2019-03-25 11:29:25 +03:00
static void mt7621_spi_set_cs ( struct spi_device * spi , int enable )
2018-03-14 23:22:35 +03:00
{
2019-03-25 11:29:25 +03:00
struct mt7621_spi * rs = spidev_to_mt7621_spi ( spi ) ;
int cs = spi - > chip_select ;
u32 polar = 0 ;
u32 master ;
2018-03-14 23:22:35 +03:00
2019-02-01 13:17:14 +03:00
/*
* Select SPI device 7 , enable " more buffer mode " and disable
* full - duplex ( only half - duplex really works on this chip
* reliably )
*/
2019-03-25 11:29:25 +03:00
master = mt7621_spi_read ( rs , MT7621_SPI_MASTER ) ;
2019-02-01 13:17:14 +03:00
master | = MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE ;
master & = ~ MASTER_FULL_DUPLEX ;
2018-03-14 23:22:35 +03:00
mt7621_spi_write ( rs , MT7621_SPI_MASTER , master ) ;
2019-03-25 11:29:25 +03:00
rs - > pending_write = 0 ;
2018-03-14 23:22:35 +03:00
if ( enable )
polar = BIT ( cs ) ;
mt7621_spi_write ( rs , MT7621_SPI_POLAR , polar ) ;
}
static int mt7621_spi_prepare ( struct spi_device * spi , unsigned int speed )
{
struct mt7621_spi * rs = spidev_to_mt7621_spi ( spi ) ;
u32 rate ;
u32 reg ;
dev_dbg ( & spi - > dev , " speed:%u \n " , speed ) ;
rate = DIV_ROUND_UP ( rs - > sys_freq , speed ) ;
dev_dbg ( & spi - > dev , " rate-1:%u \n " , rate ) ;
if ( rate > 4097 )
return - EINVAL ;
if ( rate < 2 )
rate = 2 ;
reg = mt7621_spi_read ( rs , MT7621_SPI_MASTER ) ;
2019-02-01 13:17:14 +03:00
reg & = ~ MASTER_RS_CLK_SEL ;
reg | = ( rate - 2 ) < < MASTER_RS_CLK_SEL_SHIFT ;
2018-03-14 23:22:35 +03:00
rs - > speed = speed ;
reg & = ~ MT7621_LSB_FIRST ;
if ( spi - > mode & SPI_LSB_FIRST )
reg | = MT7621_LSB_FIRST ;
2019-02-01 13:17:12 +03:00
/*
* This SPI controller seems to be tested on SPI flash only and some
* bits are swizzled under other SPI modes probably due to incorrect
* wiring inside the silicon . Only mode 0 works correctly .
2018-12-06 16:15:09 +03:00
*/
2018-03-14 23:22:35 +03:00
reg & = ~ ( MT7621_CPHA | MT7621_CPOL ) ;
2018-12-06 16:15:09 +03:00
2018-03-14 23:22:35 +03:00
mt7621_spi_write ( rs , MT7621_SPI_MASTER , reg ) ;
return 0 ;
}
2018-06-07 01:04:21 +03:00
static inline int mt7621_spi_wait_till_ready ( struct mt7621_spi * rs )
2018-03-14 23:22:35 +03:00
{
int i ;
for ( i = 0 ; i < RALINK_SPI_WAIT_MAX_LOOP ; i + + ) {
u32 status ;
status = mt7621_spi_read ( rs , MT7621_SPI_TRANS ) ;
2018-06-02 21:37:31 +03:00
if ( ( status & SPITRANS_BUSY ) = = 0 )
2018-03-14 23:22:35 +03:00
return 0 ;
cpu_relax ( ) ;
udelay ( 1 ) ;
}
return - ETIMEDOUT ;
}
2018-06-07 01:04:21 +03:00
static void mt7621_spi_read_half_duplex ( struct mt7621_spi * rs ,
int rx_len , u8 * buf )
2018-03-14 23:22:35 +03:00
{
2019-03-25 11:29:25 +03:00
int tx_len ;
2019-02-01 13:17:12 +03:00
/*
* Combine with any pending write , and perform one or more half - duplex
* transactions reading ' len ' bytes . Data to be written is already in
* MT7621_SPI_DATA .
2018-06-07 01:04:21 +03:00
*/
2019-03-25 11:29:25 +03:00
tx_len = rs - > pending_write ;
2018-06-07 01:04:21 +03:00
rs - > pending_write = 0 ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
while ( rx_len | | tx_len ) {
int i ;
u32 val = ( min ( tx_len , 4 ) * 8 ) < < 24 ;
int rx = min ( rx_len , 32 ) ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
if ( tx_len > 4 )
val | = ( tx_len - 4 ) * 8 ;
val | = ( rx * 8 ) < < 12 ;
mt7621_spi_write ( rs , MT7621_SPI_MOREBUF , val ) ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
tx_len = 0 ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
val = mt7621_spi_read ( rs , MT7621_SPI_TRANS ) ;
val | = SPI_CTL_START ;
mt7621_spi_write ( rs , MT7621_SPI_TRANS , val ) ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
mt7621_spi_wait_till_ready ( rs ) ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
for ( i = 0 ; i < rx ; i + + ) {
if ( ( i % 4 ) = = 0 )
val = mt7621_spi_read ( rs , MT7621_SPI_DATA0 + i ) ;
* buf + + = val & 0xff ;
val > > = 8 ;
}
2019-02-01 13:17:11 +03:00
2018-06-07 01:04:21 +03:00
rx_len - = i ;
2018-03-14 23:22:35 +03:00
}
2018-06-07 01:04:21 +03:00
}
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
static inline void mt7621_spi_flush ( struct mt7621_spi * rs )
{
mt7621_spi_read_half_duplex ( rs , 0 , NULL ) ;
}
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
static void mt7621_spi_write_half_duplex ( struct mt7621_spi * rs ,
int tx_len , const u8 * buf )
{
int len = rs - > pending_write ;
2019-03-25 11:29:25 +03:00
int val = 0 ;
2018-06-07 01:04:21 +03:00
if ( len & 3 ) {
val = mt7621_spi_read ( rs , MT7621_SPI_OPCODE + ( len & ~ 3 ) ) ;
if ( len < 4 ) {
val < < = ( 4 - len ) * 8 ;
val = swab32 ( val ) ;
}
2018-03-14 23:22:35 +03:00
}
2018-06-07 01:04:21 +03:00
while ( tx_len > 0 ) {
if ( len > = 36 ) {
rs - > pending_write = len ;
mt7621_spi_flush ( rs ) ;
len = 0 ;
}
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
val | = * buf + + < < ( 8 * ( len & 3 ) ) ;
len + + ;
if ( ( len & 3 ) = = 0 ) {
if ( len = = 4 )
/* The byte-order of the opcode is weird! */
val = swab32 ( val ) ;
mt7621_spi_write ( rs , MT7621_SPI_OPCODE + len - 4 , val ) ;
val = 0 ;
}
tx_len - = 1 ;
}
2019-03-25 11:29:25 +03:00
2018-06-07 01:04:21 +03:00
if ( len & 3 ) {
if ( len < 4 ) {
val = swab32 ( val ) ;
val > > = ( 4 - len ) * 8 ;
}
mt7621_spi_write ( rs , MT7621_SPI_OPCODE + ( len & ~ 3 ) , val ) ;
}
2019-03-25 11:29:25 +03:00
2018-06-07 01:04:21 +03:00
rs - > pending_write = len ;
}
2018-03-14 23:22:35 +03:00
2019-03-25 11:29:25 +03:00
static int mt7621_spi_transfer_one_message ( struct spi_controller * master ,
2018-06-07 01:04:21 +03:00
struct spi_message * m )
{
2019-03-25 11:29:25 +03:00
struct mt7621_spi * rs = spi_controller_get_devdata ( master ) ;
2018-06-07 01:04:21 +03:00
struct spi_device * spi = m - > spi ;
unsigned int speed = spi - > max_speed_hz ;
struct spi_transfer * t = NULL ;
int status = 0 ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
mt7621_spi_wait_till_ready ( rs ) ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
list_for_each_entry ( t , & m - > transfers , transfer_list )
if ( t - > speed_hz < speed )
speed = t - > speed_hz ;
2018-03-14 23:22:35 +03:00
2018-06-07 01:04:21 +03:00
if ( mt7621_spi_prepare ( spi , speed ) ) {
status = - EIO ;
goto msg_done ;
}
2018-03-14 23:22:35 +03:00
2019-03-25 11:29:25 +03:00
/* Assert CS */
2018-06-07 01:04:21 +03:00
mt7621_spi_set_cs ( spi , 1 ) ;
2019-03-25 11:29:25 +03:00
2018-06-07 01:04:21 +03:00
m - > actual_length = 0 ;
2018-03-14 23:22:35 +03:00
list_for_each_entry ( t , & m - > transfers , transfer_list ) {
2018-12-06 16:15:08 +03:00
if ( ( t - > rx_buf ) & & ( t - > tx_buf ) ) {
2019-03-25 11:29:25 +03:00
/*
* This controller will shift some extra data out
2018-12-06 16:15:08 +03:00
* of spi_opcode if ( mosi_bit_cnt > 0 ) & &
* ( cmd_bit_cnt = = 0 ) . So the claimed full - duplex
* support is broken since we have no way to read
* the MISO value during that bit .
*/
status = - EIO ;
goto msg_done ;
} else if ( t - > rx_buf ) {
2018-06-07 01:04:21 +03:00
mt7621_spi_read_half_duplex ( rs , t - > len , t - > rx_buf ) ;
2018-12-06 16:15:08 +03:00
} else if ( t - > tx_buf ) {
2018-06-07 01:04:21 +03:00
mt7621_spi_write_half_duplex ( rs , t - > len , t - > tx_buf ) ;
2018-12-06 16:15:08 +03:00
}
2018-06-07 01:04:21 +03:00
m - > actual_length + = t - > len ;
2018-03-14 23:22:35 +03:00
}
2019-03-25 11:29:25 +03:00
/* Flush data and deassert CS */
mt7621_spi_flush ( rs ) ;
2018-06-07 01:04:21 +03:00
mt7621_spi_set_cs ( spi , 0 ) ;
2019-02-01 13:17:11 +03:00
2018-03-14 23:22:35 +03:00
msg_done :
m - > status = status ;
spi_finalize_current_message ( master ) ;
return 0 ;
}
static int mt7621_spi_setup ( struct spi_device * spi )
{
struct mt7621_spi * rs = spidev_to_mt7621_spi ( spi ) ;
if ( ( spi - > max_speed_hz = = 0 ) | |
2019-03-25 11:29:25 +03:00
( spi - > max_speed_hz > ( rs - > sys_freq / 2 ) ) )
2019-04-02 08:11:56 +03:00
spi - > max_speed_hz = rs - > sys_freq / 2 ;
2018-03-14 23:22:35 +03:00
if ( spi - > max_speed_hz < ( rs - > sys_freq / 4097 ) ) {
dev_err ( & spi - > dev , " setup: requested speed is too low %d Hz \n " ,
spi - > max_speed_hz ) ;
return - EINVAL ;
}
return 0 ;
}
static const struct of_device_id mt7621_spi_match [ ] = {
{ . compatible = " ralink,mt7621-spi " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , mt7621_spi_match ) ;
static int mt7621_spi_probe ( struct platform_device * pdev )
{
const struct of_device_id * match ;
2019-03-25 11:29:25 +03:00
struct spi_controller * master ;
2018-03-14 23:22:35 +03:00
struct mt7621_spi * rs ;
void __iomem * base ;
struct clk * clk ;
2019-02-01 13:17:09 +03:00
int ret ;
2018-03-14 23:22:35 +03:00
match = of_match_device ( mt7621_spi_match , & pdev - > dev ) ;
if ( ! match )
return - EINVAL ;
2019-09-04 16:58:59 +03:00
base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2018-03-14 23:22:35 +03:00
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2022-08-27 14:42:19 +03:00
clk = devm_clk_get_enabled ( & pdev - > dev , NULL ) ;
2022-08-27 14:42:07 +03:00
if ( IS_ERR ( clk ) )
return dev_err_probe ( & pdev - > dev , PTR_ERR ( clk ) ,
" unable to get SYS clock \n " ) ;
2018-03-14 23:22:35 +03:00
2020-12-07 11:17:14 +03:00
master = devm_spi_alloc_master ( & pdev - > dev , sizeof ( * rs ) ) ;
2019-02-03 22:44:42 +03:00
if ( ! master ) {
2018-03-14 23:22:35 +03:00
dev_info ( & pdev - > dev , " master allocation failed \n " ) ;
return - ENOMEM ;
}
2018-12-06 16:15:09 +03:00
master - > mode_bits = SPI_LSB_FIRST ;
2019-03-25 11:29:25 +03:00
master - > flags = SPI_CONTROLLER_HALF_DUPLEX ;
2018-03-14 23:22:35 +03:00
master - > setup = mt7621_spi_setup ;
master - > transfer_one_message = mt7621_spi_transfer_one_message ;
master - > bits_per_word_mask = SPI_BPW_MASK ( 8 ) ;
master - > dev . of_node = pdev - > dev . of_node ;
master - > num_chipselect = 2 ;
dev_set_drvdata ( & pdev - > dev , master ) ;
2019-03-25 11:29:25 +03:00
rs = spi_controller_get_devdata ( master ) ;
2018-03-14 23:22:35 +03:00
rs - > base = base ;
rs - > master = master ;
2022-08-27 14:42:40 +03:00
rs - > sys_freq = clk_get_rate ( clk ) ;
2018-06-07 01:04:21 +03:00
rs - > pending_write = 0 ;
2018-03-14 23:22:35 +03:00
dev_info ( & pdev - > dev , " sys_freq: %u \n " , rs - > sys_freq ) ;
2019-02-01 13:17:09 +03:00
ret = device_reset ( & pdev - > dev ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " SPI reset failed! \n " ) ;
return ret ;
}
2018-03-14 23:22:35 +03:00
2022-08-27 14:42:29 +03:00
return devm_spi_register_controller ( & pdev - > dev , master ) ;
2018-03-14 23:22:35 +03:00
}
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;
static struct platform_driver mt7621_spi_driver = {
. driver = {
. name = DRIVER_NAME ,
. of_match_table = mt7621_spi_match ,
} ,
. probe = mt7621_spi_probe ,
} ;
module_platform_driver ( mt7621_spi_driver ) ;
MODULE_DESCRIPTION ( " MT7621 SPI driver " ) ;
MODULE_AUTHOR ( " Felix Fietkau <nbd@nbd.name> " ) ;
MODULE_LICENSE ( " GPL " ) ;