2012-06-14 13:43:42 +02:00
/*
* PCI bus driver for Bosch C_CAN / D_CAN controller
*
* Copyright ( C ) 2012 Federico Vaga < federico . vaga @ gmail . com >
*
* Borrowed from c_can_platform . c
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/pci.h>
# include <linux/can/dev.h>
# include "c_can.h"
2014-04-07 08:52:03 +02:00
# define PCI_DEVICE_ID_PCH_CAN 0x8818
# define PCH_PCI_SOFT_RESET 0x01fc
2012-06-14 13:43:42 +02:00
enum c_can_pci_reg_align {
C_CAN_REG_ALIGN_16 ,
C_CAN_REG_ALIGN_32 ,
2014-04-07 08:52:03 +02:00
C_CAN_REG_32 ,
2012-06-14 13:43:42 +02:00
} ;
struct c_can_pci_data {
/* Specify if is C_CAN or D_CAN */
enum c_can_dev_id type ;
/* Set the register alignment in the memory */
enum c_can_pci_reg_align reg_align ;
2012-06-20 06:04:26 +00:00
/* Set the frequency */
2012-06-14 13:43:42 +02:00
unsigned int freq ;
2014-04-07 08:52:03 +02:00
/* PCI bar number */
int bar ;
/* Callback for reset */
void ( * init ) ( const struct c_can_priv * priv , bool enable ) ;
2012-06-14 13:43:42 +02:00
} ;
/*
* 16 - bit c_can registers can be arranged differently in the memory
* architecture of different implementations . For example : 16 - bit
* registers can be aligned to a 16 - bit boundary or 32 - bit boundary etc .
* Handle the same by providing a common read / write interface .
*/
2014-05-13 15:09:14 +02:00
static u16 c_can_pci_read_reg_aligned_to_16bit ( const struct c_can_priv * priv ,
2012-06-14 13:43:42 +02:00
enum reg index )
{
return readw ( priv - > base + priv - > regs [ index ] ) ;
}
2014-05-13 15:09:14 +02:00
static void c_can_pci_write_reg_aligned_to_16bit ( const struct c_can_priv * priv ,
2012-06-14 13:43:42 +02:00
enum reg index , u16 val )
{
writew ( val , priv - > base + priv - > regs [ index ] ) ;
}
2014-05-13 15:09:14 +02:00
static u16 c_can_pci_read_reg_aligned_to_32bit ( const struct c_can_priv * priv ,
2012-06-14 13:43:42 +02:00
enum reg index )
{
return readw ( priv - > base + 2 * priv - > regs [ index ] ) ;
}
2014-05-13 15:09:14 +02:00
static void c_can_pci_write_reg_aligned_to_32bit ( const struct c_can_priv * priv ,
2012-06-14 13:43:42 +02:00
enum reg index , u16 val )
{
writew ( val , priv - > base + 2 * priv - > regs [ index ] ) ;
}
2014-05-13 15:09:14 +02:00
static u16 c_can_pci_read_reg_32bit ( const struct c_can_priv * priv ,
2014-04-07 08:52:03 +02:00
enum reg index )
{
return ( u16 ) ioread32 ( priv - > base + 2 * priv - > regs [ index ] ) ;
}
2014-05-13 15:09:14 +02:00
static void c_can_pci_write_reg_32bit ( const struct c_can_priv * priv ,
2014-04-07 08:52:03 +02:00
enum reg index , u16 val )
{
iowrite32 ( ( u32 ) val , priv - > base + 2 * priv - > regs [ index ] ) ;
}
2014-05-06 15:57:02 +02:00
static u32 c_can_pci_read_reg32 ( const struct c_can_priv * priv , enum reg index )
{
u32 val ;
val = priv - > read_reg ( priv , index ) ;
val | = ( ( u32 ) priv - > read_reg ( priv , index + 1 ) ) < < 16 ;
return val ;
}
static void c_can_pci_write_reg32 ( const struct c_can_priv * priv , enum reg index ,
u32 val )
{
priv - > write_reg ( priv , index + 1 , val > > 16 ) ;
priv - > write_reg ( priv , index , val ) ;
}
2014-04-07 08:52:03 +02:00
static void c_can_pci_reset_pch ( const struct c_can_priv * priv , bool enable )
{
if ( enable ) {
u32 __iomem * addr = priv - > base + PCH_PCI_SOFT_RESET ;
/* write to sw reset register */
iowrite32 ( 1 , addr ) ;
iowrite32 ( 0 , addr ) ;
}
}
2012-12-03 09:22:44 -05:00
static int c_can_pci_probe ( struct pci_dev * pdev ,
2012-12-06 14:30:56 +00:00
const struct pci_device_id * ent )
2012-06-14 13:43:42 +02:00
{
struct c_can_pci_data * c_can_pci_data = ( void * ) ent - > driver_data ;
struct c_can_priv * priv ;
struct net_device * dev ;
void __iomem * addr ;
int ret ;
ret = pci_enable_device ( pdev ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " pci_enable_device FAILED \n " ) ;
goto out ;
}
ret = pci_request_regions ( pdev , KBUILD_MODNAME ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " pci_request_regions FAILED \n " ) ;
goto out_disable_device ;
}
2014-04-03 20:41:24 +02:00
ret = pci_enable_msi ( pdev ) ;
if ( ! ret ) {
dev_info ( & pdev - > dev , " MSI enabled \n " ) ;
pci_set_master ( pdev ) ;
}
2012-06-14 13:43:42 +02:00
2014-04-07 08:52:03 +02:00
addr = pci_iomap ( pdev , c_can_pci_data - > bar ,
pci_resource_len ( pdev , c_can_pci_data - > bar ) ) ;
2012-06-14 13:43:42 +02:00
if ( ! addr ) {
dev_err ( & pdev - > dev ,
" device has no PCI memory resources, "
" failing adapter \n " ) ;
ret = - ENOMEM ;
goto out_release_regions ;
}
/* allocate the c_can device */
dev = alloc_c_can_dev ( ) ;
if ( ! dev ) {
ret = - ENOMEM ;
goto out_iounmap ;
}
priv = netdev_priv ( dev ) ;
pci_set_drvdata ( pdev , dev ) ;
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
dev - > irq = pdev - > irq ;
priv - > base = addr ;
2016-08-12 13:50:41 +02:00
priv - > device = & pdev - > dev ;
2012-06-14 13:43:42 +02:00
if ( ! c_can_pci_data - > freq ) {
2012-06-20 06:04:26 +00:00
dev_err ( & pdev - > dev , " no clock frequency defined \n " ) ;
ret = - ENODEV ;
goto out_free_c_can ;
2012-06-14 13:43:42 +02:00
} else {
priv - > can . clock . freq = c_can_pci_data - > freq ;
}
/* Configure CAN type */
switch ( c_can_pci_data - > type ) {
2012-08-02 18:43:09 +05:30
case BOSCH_C_CAN :
2012-06-14 13:43:42 +02:00
priv - > regs = reg_map_c_can ;
break ;
2012-08-02 18:43:09 +05:30
case BOSCH_D_CAN :
2012-06-14 13:43:42 +02:00
priv - > regs = reg_map_d_can ;
break ;
default :
ret = - EINVAL ;
2012-06-20 06:04:26 +00:00
goto out_free_c_can ;
2012-06-14 13:43:42 +02:00
}
2014-04-11 08:13:10 +00:00
priv - > type = c_can_pci_data - > type ;
2012-06-14 13:43:42 +02:00
/* Configure access to registers */
switch ( c_can_pci_data - > reg_align ) {
case C_CAN_REG_ALIGN_32 :
priv - > read_reg = c_can_pci_read_reg_aligned_to_32bit ;
priv - > write_reg = c_can_pci_write_reg_aligned_to_32bit ;
break ;
case C_CAN_REG_ALIGN_16 :
priv - > read_reg = c_can_pci_read_reg_aligned_to_16bit ;
priv - > write_reg = c_can_pci_write_reg_aligned_to_16bit ;
break ;
2014-04-07 08:52:03 +02:00
case C_CAN_REG_32 :
priv - > read_reg = c_can_pci_read_reg_32bit ;
priv - > write_reg = c_can_pci_write_reg_32bit ;
break ;
2012-06-14 13:43:42 +02:00
default :
ret = - EINVAL ;
2012-06-20 06:04:26 +00:00
goto out_free_c_can ;
2012-06-14 13:43:42 +02:00
}
2014-05-06 15:57:02 +02:00
priv - > read_reg32 = c_can_pci_read_reg32 ;
priv - > write_reg32 = c_can_pci_write_reg32 ;
2012-06-14 13:43:42 +02:00
2014-04-07 08:52:03 +02:00
priv - > raminit = c_can_pci_data - > init ;
2012-06-14 13:43:42 +02:00
ret = register_c_can_dev ( dev ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " registering %s failed (err=%d) \n " ,
KBUILD_MODNAME , ret ) ;
2012-06-20 06:04:26 +00:00
goto out_free_c_can ;
2012-06-14 13:43:42 +02:00
}
dev_dbg ( & pdev - > dev , " %s device registered (regs=%p, irq=%d) \n " ,
KBUILD_MODNAME , priv - > regs , dev - > irq ) ;
return 0 ;
out_free_c_can :
free_c_can_dev ( dev ) ;
out_iounmap :
pci_iounmap ( pdev , addr ) ;
out_release_regions :
pci_disable_msi ( pdev ) ;
pci_clear_master ( pdev ) ;
pci_release_regions ( pdev ) ;
out_disable_device :
pci_disable_device ( pdev ) ;
out :
return ret ;
}
2012-12-03 09:22:44 -05:00
static void c_can_pci_remove ( struct pci_dev * pdev )
2012-06-14 13:43:42 +02:00
{
struct net_device * dev = pci_get_drvdata ( pdev ) ;
struct c_can_priv * priv = netdev_priv ( dev ) ;
unregister_c_can_dev ( dev ) ;
free_c_can_dev ( dev ) ;
pci_iounmap ( pdev , priv - > base ) ;
pci_disable_msi ( pdev ) ;
pci_clear_master ( pdev ) ;
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
}
2017-08-06 12:18:31 +05:30
static const struct c_can_pci_data c_can_sta2x11 = {
2012-08-02 18:43:09 +05:30
. type = BOSCH_C_CAN ,
2012-06-14 13:43:42 +02:00
. reg_align = C_CAN_REG_ALIGN_32 ,
. freq = 52000000 , /* 52 Mhz */
2014-04-07 08:52:03 +02:00
. bar = 0 ,
} ;
2017-08-06 12:18:31 +05:30
static const struct c_can_pci_data c_can_pch = {
2014-04-07 08:52:03 +02:00
. type = BOSCH_C_CAN ,
. reg_align = C_CAN_REG_32 ,
. freq = 50000000 , /* 50 MHz */
. init = c_can_pci_reset_pch ,
. bar = 1 ,
2012-06-14 13:43:42 +02:00
} ;
# define C_CAN_ID(_vend, _dev, _driverdata) { \
PCI_DEVICE ( _vend , _dev ) , \
. driver_data = ( unsigned long ) & _driverdata , \
}
2014-08-08 15:56:03 +02:00
static const struct pci_device_id c_can_pci_tbl [ ] = {
2012-06-14 13:43:42 +02:00
C_CAN_ID ( PCI_VENDOR_ID_STMICRO , PCI_DEVICE_ID_STMICRO_CAN ,
c_can_sta2x11 ) ,
2014-04-07 08:52:03 +02:00
C_CAN_ID ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_PCH_CAN ,
c_can_pch ) ,
2012-06-14 13:43:42 +02:00
{ } ,
} ;
static struct pci_driver c_can_pci_driver = {
. name = KBUILD_MODNAME ,
. id_table = c_can_pci_tbl ,
. probe = c_can_pci_probe ,
2012-12-03 09:22:44 -05:00
. remove = c_can_pci_remove ,
2012-06-14 13:43:42 +02:00
} ;
module_pci_driver ( c_can_pci_driver ) ;
MODULE_AUTHOR ( " Federico Vaga <federico.vaga@gmail.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " PCI CAN bus driver for Bosch C_CAN/D_CAN controller " ) ;
MODULE_DEVICE_TABLE ( pci , c_can_pci_tbl ) ;