2021-04-16 19:57:19 +03:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Altera SPI driver
*
* Copyright ( C ) 2008 Thomas Chou < thomas @ wytron . com . tw >
*
* Based on spi_s3c24xx . c , which is :
* Copyright ( c ) 2006 Ben Dooks
* Copyright ( c ) 2006 Simtec Electronics
* Ben Dooks < ben @ simtec . co . uk >
*/
# include <linux/interrupt.h>
# include <linux/errno.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/spi/altera.h>
# include <linux/spi/spi.h>
# include <linux/io.h>
# include <linux/of.h>
# define DRV_NAME "spi_altera"
enum altera_spi_type {
ALTERA_SPI_TYPE_UNKNOWN ,
ALTERA_SPI_TYPE_SUBDEV ,
} ;
static const struct regmap_config spi_altera_config = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
. fast_io = true ,
} ;
static int altera_spi_probe ( struct platform_device * pdev )
{
const struct platform_device_id * platid = platform_get_device_id ( pdev ) ;
struct altera_spi_platform_data * pdata = dev_get_platdata ( & pdev - > dev ) ;
enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN ;
struct altera_spi * hw ;
struct spi_master * master ;
int err = - ENODEV ;
u16 i ;
master = spi_alloc_master ( & pdev - > dev , sizeof ( struct altera_spi ) ) ;
if ( ! master )
return err ;
/* setup the master state. */
2021-10-19 03:24:01 +03:00
master - > bus_num = - 1 ;
2021-04-16 19:57:19 +03:00
if ( pdata ) {
if ( pdata - > num_chipselect > ALTERA_SPI_MAX_CS ) {
dev_err ( & pdev - > dev ,
" Invalid number of chipselect: %u \n " ,
pdata - > num_chipselect ) ;
err = - EINVAL ;
goto exit ;
}
master - > num_chipselect = pdata - > num_chipselect ;
master - > mode_bits = pdata - > mode_bits ;
master - > bits_per_word_mask = pdata - > bits_per_word_mask ;
} else {
master - > num_chipselect = 16 ;
master - > mode_bits = SPI_CS_HIGH ;
master - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 1 , 16 ) ;
}
master - > dev . of_node = pdev - > dev . of_node ;
hw = spi_master_get_devdata ( master ) ;
hw - > dev = & pdev - > dev ;
if ( platid )
type = platid - > driver_data ;
/* find and map our resources */
if ( type = = ALTERA_SPI_TYPE_SUBDEV ) {
struct resource * regoff ;
hw - > regmap = dev_get_regmap ( pdev - > dev . parent , NULL ) ;
if ( ! hw - > regmap ) {
dev_err ( & pdev - > dev , " get regmap failed \n " ) ;
goto exit ;
}
regoff = platform_get_resource ( pdev , IORESOURCE_REG , 0 ) ;
if ( regoff )
hw - > regoff = regoff - > start ;
} else {
void __iomem * res ;
res = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( res ) ) {
err = PTR_ERR ( res ) ;
goto exit ;
}
hw - > regmap = devm_regmap_init_mmio ( & pdev - > dev , res ,
& spi_altera_config ) ;
if ( IS_ERR ( hw - > regmap ) ) {
dev_err ( & pdev - > dev , " regmap mmio init failed \n " ) ;
err = PTR_ERR ( hw - > regmap ) ;
goto exit ;
}
}
altera_spi_init_master ( master ) ;
/* irq is optional */
hw - > irq = platform_get_irq ( pdev , 0 ) ;
if ( hw - > irq > = 0 ) {
err = devm_request_irq ( & pdev - > dev , hw - > irq , altera_spi_irq , 0 ,
pdev - > name , master ) ;
if ( err )
goto exit ;
}
err = devm_spi_register_master ( & pdev - > dev , master ) ;
if ( err )
goto exit ;
if ( pdata ) {
for ( i = 0 ; i < pdata - > num_devices ; i + + ) {
if ( ! spi_new_device ( master , pdata - > devices + i ) )
dev_warn ( & pdev - > dev ,
" unable to create SPI device: %s \n " ,
pdata - > devices [ i ] . modalias ) ;
}
}
dev_info ( & pdev - > dev , " regoff %u, irq %d \n " , hw - > regoff , hw - > irq ) ;
return 0 ;
exit :
spi_master_put ( master ) ;
return err ;
}
# ifdef CONFIG_OF
static const struct of_device_id altera_spi_match [ ] = {
{ . compatible = " ALTR,spi-1.0 " , } ,
{ . compatible = " altr,spi-1.0 " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , altera_spi_match ) ;
# endif /* CONFIG_OF */
static const struct platform_device_id altera_spi_ids [ ] = {
{ DRV_NAME , ALTERA_SPI_TYPE_UNKNOWN } ,
{ " subdev_spi_altera " , ALTERA_SPI_TYPE_SUBDEV } ,
{ }
} ;
MODULE_DEVICE_TABLE ( platform , altera_spi_ids ) ;
static struct platform_driver altera_spi_driver = {
. probe = altera_spi_probe ,
. driver = {
. name = DRV_NAME ,
. pm = NULL ,
. of_match_table = of_match_ptr ( altera_spi_match ) ,
} ,
. id_table = altera_spi_ids ,
} ;
module_platform_driver ( altera_spi_driver ) ;
MODULE_DESCRIPTION ( " Altera SPI driver " ) ;
MODULE_AUTHOR ( " Thomas Chou <thomas@wytron.com.tw> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform: " DRV_NAME ) ;