2018-08-22 01:02:23 +03:00
// SPDX-License-Identifier: GPL-2.0
2012-03-02 05:10:17 +04:00
/*
* SuperH HSPI bus driver
*
* Copyright ( C ) 2011 Kuninori Morimoto
*
* Based on spi - sh . c :
* Based on pxa2xx_spi . c :
* Copyright ( C ) 2011 Renesas Solutions Corp .
* Copyright ( C ) 2005 Stephen Street / StreetFire Sound Labs
*/
2012-03-14 13:48:05 +04:00
# include <linux/clk.h>
2012-03-02 05:10:17 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/timer.h>
# include <linux/delay.h>
# include <linux/list.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
# include <linux/io.h>
# include <linux/spi/spi.h>
# include <linux/spi/sh_hspi.h>
# define SPCR 0x00
# define SPSR 0x04
# define SPSCR 0x08
# define SPTBR 0x0C
# define SPRBR 0x10
# define SPCR2 0x14
/* SPSR */
# define RXFL (1 << 2)
struct hspi_priv {
void __iomem * addr ;
2019-02-08 12:09:08 +03:00
struct spi_controller * ctlr ;
2012-03-02 05:10:17 +04:00
struct device * dev ;
2012-03-14 13:48:05 +04:00
struct clk * clk ;
2012-03-02 05:10:17 +04:00
} ;
/*
* basic function
*/
static void hspi_write ( struct hspi_priv * hspi , int reg , u32 val )
{
iowrite32 ( val , hspi - > addr + reg ) ;
}
static u32 hspi_read ( struct hspi_priv * hspi , int reg )
{
return ioread32 ( hspi - > addr + reg ) ;
}
2012-11-22 18:37:27 +04:00
static void hspi_bit_set ( struct hspi_priv * hspi , int reg , u32 mask , u32 set )
{
u32 val = hspi_read ( hspi , reg ) ;
val & = ~ mask ;
val | = set & mask ;
hspi_write ( hspi , reg , val ) ;
}
2012-03-02 05:10:17 +04:00
/*
* transfer function
*/
static int hspi_status_check_timeout ( struct hspi_priv * hspi , u32 mask , u32 val )
{
int t = 256 ;
while ( t - - ) {
if ( ( mask & hspi_read ( hspi , SPSR ) ) = = val )
return 0 ;
2013-05-27 04:59:20 +04:00
udelay ( 10 ) ;
2012-03-02 05:10:17 +04:00
}
dev_err ( hspi - > dev , " timeout \n " ) ;
return - ETIMEDOUT ;
}
2012-03-14 13:47:40 +04:00
/*
* spi master function
*/
2012-03-02 05:10:17 +04:00
2012-11-22 18:37:27 +04:00
# define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
# define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1)
static void hspi_hw_cs_ctrl ( struct hspi_priv * hspi , int hi )
{
hspi_bit_set ( hspi , SPSCR , ( 1 < < 6 ) , ( hi ) < < 6 ) ;
}
2012-03-14 13:48:05 +04:00
static void hspi_hw_setup ( struct hspi_priv * hspi ,
struct spi_message * msg ,
struct spi_transfer * t )
{
struct spi_device * spi = msg - > spi ;
struct device * dev = hspi - > dev ;
u32 spcr , idiv_clk ;
u32 rate , best_rate , min , tmp ;
/*
* find best IDIV / CLKCx settings
*/
min = ~ 0 ;
best_rate = 0 ;
spcr = 0 ;
for ( idiv_clk = 0x00 ; idiv_clk < = 0x3F ; idiv_clk + + ) {
rate = clk_get_rate ( hspi - > clk ) ;
/* IDIV calculation */
if ( idiv_clk & ( 1 < < 5 ) )
rate / = 128 ;
else
rate / = 16 ;
/* CLKCx calculation */
2013-10-14 05:35:42 +04:00
rate / = ( ( ( idiv_clk & 0x1F ) + 1 ) * 2 ) ;
2012-03-14 13:48:05 +04:00
/* save best settings */
2014-03-02 19:01:50 +04:00
tmp = abs ( t - > speed_hz - rate ) ;
2012-03-14 13:48:05 +04:00
if ( tmp < min ) {
min = tmp ;
spcr = idiv_clk ;
best_rate = rate ;
}
}
if ( spi - > mode & SPI_CPHA )
spcr | = 1 < < 7 ;
if ( spi - > mode & SPI_CPOL )
spcr | = 1 < < 6 ;
2014-03-02 19:01:50 +04:00
dev_dbg ( dev , " speed %d/%d \n " , t - > speed_hz , best_rate ) ;
2012-03-14 13:48:05 +04:00
hspi_write ( hspi , SPCR , spcr ) ;
hspi_write ( hspi , SPSR , 0x0 ) ;
2012-11-22 18:37:27 +04:00
hspi_write ( hspi , SPSCR , 0x21 ) ; /* master mode / CS control */
2012-03-14 13:48:05 +04:00
}
2019-02-08 12:09:08 +03:00
static int hspi_transfer_one_message ( struct spi_controller * ctlr ,
2012-03-14 13:47:40 +04:00
struct spi_message * msg )
{
2019-02-08 12:09:08 +03:00
struct hspi_priv * hspi = spi_controller_get_devdata ( ctlr ) ;
2012-03-14 13:47:40 +04:00
struct spi_transfer * t ;
2012-03-14 13:48:25 +04:00
u32 tx ;
u32 rx ;
int ret , i ;
2012-11-22 18:37:27 +04:00
unsigned int cs_change ;
const int nsecs = 50 ;
2012-03-02 05:10:17 +04:00
2012-03-14 13:47:40 +04:00
dev_dbg ( hspi - > dev , " %s \n " , __func__ ) ;
2012-03-02 05:10:17 +04:00
2012-11-22 18:37:27 +04:00
cs_change = 1 ;
2012-03-14 13:47:40 +04:00
ret = 0 ;
list_for_each_entry ( t , & msg - > transfers , transfer_list ) {
2012-11-22 18:37:27 +04:00
if ( cs_change ) {
hspi_hw_setup ( hspi , msg , t ) ;
hspi_hw_cs_enable ( hspi ) ;
ndelay ( nsecs ) ;
}
cs_change = t - > cs_change ;
2012-03-14 13:48:05 +04:00
2012-03-14 13:48:25 +04:00
for ( i = 0 ; i < t - > len ; i + + ) {
/* wait remains */
ret = hspi_status_check_timeout ( hspi , 0x1 , 0 ) ;
2012-03-14 13:47:40 +04:00
if ( ret < 0 )
2012-03-14 13:48:25 +04:00
break ;
tx = 0 ;
if ( t - > tx_buf )
tx = ( u32 ) ( ( u8 * ) t - > tx_buf ) [ i ] ;
hspi_write ( hspi , SPTBR , tx ) ;
2014-01-12 17:03:38 +04:00
/* wait receive */
2012-03-14 13:48:25 +04:00
ret = hspi_status_check_timeout ( hspi , 0x4 , 0x4 ) ;
2012-03-14 13:47:40 +04:00
if ( ret < 0 )
2012-03-14 13:48:25 +04:00
break ;
rx = hspi_read ( hspi , SPRBR ) ;
if ( t - > rx_buf )
( ( u8 * ) t - > rx_buf ) [ i ] = ( u8 ) rx ;
2012-03-02 05:10:17 +04:00
}
2012-03-14 13:48:25 +04:00
2012-03-14 13:47:40 +04:00
msg - > actual_length + = t - > len ;
2012-11-22 18:37:27 +04:00
2019-09-26 13:51:37 +03:00
spi_transfer_delay_exec ( t ) ;
2012-11-22 18:37:27 +04:00
if ( cs_change ) {
ndelay ( nsecs ) ;
hspi_hw_cs_disable ( hspi ) ;
ndelay ( nsecs ) ;
}
2012-03-02 05:10:17 +04:00
}
2012-03-14 13:47:40 +04:00
msg - > status = ret ;
2012-11-22 18:37:27 +04:00
if ( ! cs_change ) {
ndelay ( nsecs ) ;
hspi_hw_cs_disable ( hspi ) ;
}
2019-02-08 12:09:08 +03:00
spi_finalize_current_message ( ctlr ) ;
2012-03-02 05:10:17 +04:00
2012-03-14 13:47:40 +04:00
return ret ;
2012-03-02 05:10:17 +04:00
}
2012-12-07 20:57:14 +04:00
static int hspi_probe ( struct platform_device * pdev )
2012-03-02 05:10:17 +04:00
{
struct resource * res ;
2019-02-08 12:09:08 +03:00
struct spi_controller * ctlr ;
2012-03-02 05:10:17 +04:00
struct hspi_priv * hspi ;
2012-03-14 13:48:05 +04:00
struct clk * clk ;
2012-03-02 05:10:17 +04:00
int ret ;
/* get base addr */
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " invalid resource \n " ) ;
return - EINVAL ;
}
2019-02-08 12:09:08 +03:00
ctlr = spi_alloc_master ( & pdev - > dev , sizeof ( * hspi ) ) ;
if ( ! ctlr )
2012-03-02 05:10:17 +04:00
return - ENOMEM ;
2014-04-14 05:41:38 +04:00
clk = clk_get ( & pdev - > dev , NULL ) ;
2012-12-12 04:24:54 +04:00
if ( IS_ERR ( clk ) ) {
2014-04-14 05:41:38 +04:00
dev_err ( & pdev - > dev , " couldn't get clock \n " ) ;
2012-03-14 13:48:05 +04:00
ret = - EINVAL ;
goto error0 ;
}
2019-02-08 12:09:08 +03:00
hspi = spi_controller_get_devdata ( ctlr ) ;
2013-05-23 14:20:40 +04:00
platform_set_drvdata ( pdev , hspi ) ;
2012-03-02 05:10:17 +04:00
/* init hspi */
2019-02-08 12:09:08 +03:00
hspi - > ctlr = ctlr ;
2012-03-02 05:10:17 +04:00
hspi - > dev = & pdev - > dev ;
2012-03-14 13:48:05 +04:00
hspi - > clk = clk ;
2012-03-02 05:10:17 +04:00
hspi - > addr = devm_ioremap ( hspi - > dev ,
res - > start , resource_size ( res ) ) ;
if ( ! hspi - > addr ) {
ret = - ENOMEM ;
goto error1 ;
}
2013-10-03 13:15:50 +04:00
pm_runtime_enable ( & pdev - > dev ) ;
2019-02-08 12:09:08 +03:00
ctlr - > bus_num = pdev - > id ;
ctlr - > mode_bits = SPI_CPOL | SPI_CPHA ;
ctlr - > dev . of_node = pdev - > dev . of_node ;
ctlr - > auto_runtime_pm = true ;
ctlr - > transfer_one_message = hspi_transfer_one_message ;
ctlr - > bits_per_word_mask = SPI_BPW_MASK ( 8 ) ;
2014-02-12 18:09:52 +04:00
2019-02-08 12:09:08 +03:00
ret = devm_spi_register_controller ( & pdev - > dev , ctlr ) ;
2012-03-02 05:10:17 +04:00
if ( ret < 0 ) {
2019-02-08 12:09:08 +03:00
dev_err ( & pdev - > dev , " devm_spi_register_controller error. \n " ) ;
2014-03-11 13:59:10 +04:00
goto error2 ;
2012-03-02 05:10:17 +04:00
}
return 0 ;
2014-03-11 13:59:10 +04:00
error2 :
pm_runtime_disable ( & pdev - > dev ) ;
2012-03-02 05:10:17 +04:00
error1 :
2012-03-14 13:48:05 +04:00
clk_put ( clk ) ;
error0 :
2019-02-08 12:09:08 +03:00
spi_controller_put ( ctlr ) ;
2012-03-02 05:10:17 +04:00
return ret ;
}
2012-12-07 20:57:14 +04:00
static int hspi_remove ( struct platform_device * pdev )
2012-03-02 05:10:17 +04:00
{
2013-05-23 14:20:40 +04:00
struct hspi_priv * hspi = platform_get_drvdata ( pdev ) ;
2012-03-02 05:10:17 +04:00
pm_runtime_disable ( & pdev - > dev ) ;
2012-03-14 13:48:05 +04:00
clk_put ( hspi - > clk ) ;
2012-03-02 05:10:17 +04:00
return 0 ;
}
2014-06-03 16:04:59 +04:00
static const struct of_device_id hspi_of_match [ ] = {
2013-10-25 08:53:29 +04:00
{ . compatible = " renesas,hspi " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , hspi_of_match ) ;
2012-03-02 05:10:17 +04:00
static struct platform_driver hspi_driver = {
. probe = hspi_probe ,
2012-12-07 20:57:14 +04:00
. remove = hspi_remove ,
2012-03-02 05:10:17 +04:00
. driver = {
. name = " sh-hspi " ,
2013-10-25 08:53:29 +04:00
. of_match_table = hspi_of_match ,
2012-03-02 05:10:17 +04:00
} ,
} ;
module_platform_driver ( hspi_driver ) ;
MODULE_DESCRIPTION ( " SuperH HSPI bus driver " ) ;
2018-08-22 01:02:23 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2012-03-02 05:10:17 +04:00
MODULE_AUTHOR ( " Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> " ) ;
2014-01-08 14:52:40 +04:00
MODULE_ALIAS ( " platform:sh-hspi " ) ;