2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2012-11-07 21:30:29 +04:00
/*
* CLPS711X SPI bus driver
*
2016-07-06 17:53:12 +03:00
* Copyright ( C ) 2012 - 2016 Alexander Shiyan < shc_work @ mail . ru >
2012-11-07 21:30:29 +04:00
*/
# include <linux/io.h>
# include <linux/clk.h>
2019-01-07 18:51:54 +03:00
# include <linux/gpio/consumer.h>
2012-11-07 21:30:29 +04:00
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
2014-03-22 10:57:35 +04:00
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
# include <linux/mfd/syscon/clps711x.h>
2012-11-07 21:30:29 +04:00
# include <linux/spi/spi.h>
2016-07-06 17:53:12 +03:00
# define DRIVER_NAME "clps711x-spi"
2012-11-07 21:30:29 +04:00
2014-03-22 10:57:35 +04:00
# define SYNCIO_FRMLEN(x) ((x) << 8)
# define SYNCIO_TXFRMEN (1 << 14)
2012-11-07 21:30:29 +04:00
struct spi_clps711x_data {
2014-03-22 10:57:35 +04:00
void __iomem * syncio ;
struct regmap * syscon ;
2012-11-07 21:30:29 +04:00
struct clk * spi_clk ;
u8 * tx_buf ;
u8 * rx_buf ;
2014-02-02 10:59:49 +04:00
unsigned int bpw ;
2012-11-07 21:30:29 +04:00
int len ;
} ;
2014-02-18 13:15:54 +04:00
static int spi_clps711x_prepare_message ( struct spi_master * master ,
struct spi_message * msg )
2012-11-07 21:30:29 +04:00
{
2014-03-22 10:57:35 +04:00
struct spi_clps711x_data * hw = spi_master_get_devdata ( master ) ;
2014-02-02 10:59:49 +04:00
struct spi_device * spi = msg - > spi ;
2012-11-07 21:30:29 +04:00
2014-03-22 10:57:35 +04:00
/* Setup mode for transfer */
return regmap_update_bits ( hw - > syscon , SYSCON_OFFSET , SYSCON3_ADCCKNSEN ,
( spi - > mode & SPI_CPHA ) ?
SYSCON3_ADCCKNSEN : 0 ) ;
2014-02-18 13:15:54 +04:00
}
2012-11-07 21:30:29 +04:00
2014-02-18 13:15:54 +04:00
static int spi_clps711x_transfer_one ( struct spi_master * master ,
struct spi_device * spi ,
struct spi_transfer * xfer )
{
struct spi_clps711x_data * hw = spi_master_get_devdata ( master ) ;
u8 data ;
2012-11-07 21:30:29 +04:00
2014-09-20 11:05:09 +04:00
clk_set_rate ( hw - > spi_clk , xfer - > speed_hz ? : spi - > max_speed_hz ) ;
2012-11-07 21:30:29 +04:00
2014-02-18 13:15:54 +04:00
hw - > len = xfer - > len ;
2014-03-02 19:24:18 +04:00
hw - > bpw = xfer - > bits_per_word ;
2014-02-18 13:15:54 +04:00
hw - > tx_buf = ( u8 * ) xfer - > tx_buf ;
hw - > rx_buf = ( u8 * ) xfer - > rx_buf ;
2012-11-07 21:30:29 +04:00
2014-02-18 13:15:54 +04:00
/* Initiate transfer */
data = hw - > tx_buf ? * hw - > tx_buf + + : 0 ;
2014-03-22 10:57:35 +04:00
writel ( data | SYNCIO_FRMLEN ( hw - > bpw ) | SYNCIO_TXFRMEN , hw - > syncio ) ;
2014-02-18 13:15:54 +04:00
return 1 ;
2012-11-07 21:30:29 +04:00
}
static irqreturn_t spi_clps711x_isr ( int irq , void * dev_id )
{
2014-02-18 13:15:54 +04:00
struct spi_master * master = dev_id ;
struct spi_clps711x_data * hw = spi_master_get_devdata ( master ) ;
2014-02-02 10:59:48 +04:00
u8 data ;
2012-11-07 21:30:29 +04:00
/* Handle RX */
2014-03-22 10:57:35 +04:00
data = readb ( hw - > syncio ) ;
2012-11-07 21:30:29 +04:00
if ( hw - > rx_buf )
2014-02-02 10:59:48 +04:00
* hw - > rx_buf + + = data ;
2012-11-07 21:30:29 +04:00
/* Handle TX */
2014-02-02 10:59:48 +04:00
if ( - - hw - > len > 0 ) {
data = hw - > tx_buf ? * hw - > tx_buf + + : 0 ;
2014-03-22 10:57:35 +04:00
writel ( data | SYNCIO_FRMLEN ( hw - > bpw ) | SYNCIO_TXFRMEN ,
hw - > syncio ) ;
2012-11-07 21:30:29 +04:00
} else
2014-02-18 13:15:54 +04:00
spi_finalize_current_transfer ( master ) ;
2012-11-07 21:30:29 +04:00
return IRQ_HANDLED ;
}
2012-12-07 20:57:14 +04:00
static int spi_clps711x_probe ( struct platform_device * pdev )
2012-11-07 21:30:29 +04:00
{
struct spi_clps711x_data * hw ;
2014-03-22 10:57:35 +04:00
struct spi_master * master ;
2016-07-06 17:53:12 +03:00
int irq , ret ;
2012-11-07 21:30:29 +04:00
2014-03-22 10:57:35 +04:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return irq ;
2014-02-02 10:59:50 +04:00
master = spi_alloc_master ( & pdev - > dev , sizeof ( * hw ) ) ;
if ( ! master )
2012-11-07 21:30:29 +04:00
return - ENOMEM ;
2014-02-02 10:59:50 +04:00
2019-01-07 18:51:54 +03:00
master - > use_gpio_descriptors = true ;
2016-07-06 17:53:12 +03:00
master - > bus_num = - 1 ;
2012-11-07 21:30:29 +04:00
master - > mode_bits = SPI_CPHA | SPI_CS_HIGH ;
2021-02-04 14:08:06 +03:00
master - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 1 , 8 ) ;
2016-07-06 17:53:12 +03:00
master - > dev . of_node = pdev - > dev . of_node ;
2014-02-18 13:15:54 +04:00
master - > prepare_message = spi_clps711x_prepare_message ;
master - > transfer_one = spi_clps711x_transfer_one ;
2012-11-07 21:30:29 +04:00
hw = spi_master_get_devdata ( master ) ;
2014-09-20 11:05:09 +04:00
hw - > spi_clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2012-11-07 21:30:29 +04:00
if ( IS_ERR ( hw - > spi_clk ) ) {
ret = PTR_ERR ( hw - > spi_clk ) ;
goto err_out ;
}
2016-07-06 17:53:12 +03:00
hw - > syscon =
syscon_regmap_lookup_by_compatible ( " cirrus,ep7209-syscon3 " ) ;
2014-03-22 10:57:35 +04:00
if ( IS_ERR ( hw - > syscon ) ) {
ret = PTR_ERR ( hw - > syscon ) ;
goto err_out ;
}
2019-09-04 16:58:52 +03:00
hw - > syncio = devm_platform_ioremap_resource ( pdev , 0 ) ;
2014-03-22 10:57:35 +04:00
if ( IS_ERR ( hw - > syncio ) ) {
ret = PTR_ERR ( hw - > syncio ) ;
goto err_out ;
}
2012-11-07 21:30:29 +04:00
/* Disable extended mode due hardware problems */
2014-03-22 10:57:35 +04:00
regmap_update_bits ( hw - > syscon , SYSCON_OFFSET , SYSCON3_ADCCON , 0 ) ;
2012-11-07 21:30:29 +04:00
/* Clear possible pending interrupt */
2014-03-22 10:57:35 +04:00
readl ( hw - > syncio ) ;
2012-11-07 21:30:29 +04:00
2014-03-22 10:57:35 +04:00
ret = devm_request_irq ( & pdev - > dev , irq , spi_clps711x_isr , 0 ,
2014-02-18 13:15:54 +04:00
dev_name ( & pdev - > dev ) , master ) ;
2014-03-22 10:57:35 +04:00
if ( ret )
2013-09-27 14:02:53 +04:00
goto err_out ;
2012-11-07 21:30:29 +04:00
2013-09-24 08:27:48 +04:00
ret = devm_spi_register_master ( & pdev - > dev , master ) ;
2016-07-06 17:53:12 +03:00
if ( ! ret )
2012-11-07 21:30:29 +04:00
return 0 ;
err_out :
spi_master_put ( master ) ;
return ret ;
}
2016-07-06 17:53:12 +03:00
static const struct of_device_id clps711x_spi_dt_ids [ ] = {
{ . compatible = " cirrus,ep7209-spi " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , clps711x_spi_dt_ids ) ;
2012-11-07 21:30:29 +04:00
static struct platform_driver clps711x_spi_driver = {
. driver = {
. name = DRIVER_NAME ,
2016-07-06 17:53:12 +03:00
. of_match_table = clps711x_spi_dt_ids ,
2012-11-07 21:30:29 +04:00
} ,
. probe = spi_clps711x_probe ,
} ;
module_platform_driver ( clps711x_spi_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Alexander Shiyan <shc_work@mail.ru> " ) ;
MODULE_DESCRIPTION ( " CLPS711X SPI bus driver " ) ;
2014-01-14 13:01:54 +04:00
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;