2009-05-30 07:55:50 +00:00
/*
* Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
*
* Copyright ( C ) 2008 - 2009 Wolfgang Grandegger < wg @ grandegger . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2013-12-06 06:28:45 -08:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2009-05-30 07:55:50 +00:00
*/
/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
* bus found on embedded PowerPC systems . You need a SJA1000 CAN node
* definition in your flattened device tree source ( DTS ) file similar to :
*
* can @ 3 , 100 {
* compatible = " nxp,sja1000 " ;
* reg = < 3 0x100 0x80 > ;
* interrupts = < 2 0 > ;
* interrupt - parent = < & mpic > ;
* nxp , external - clock - frequency = < 16000000 > ;
* } ;
*
2011-08-15 02:02:26 +02:00
* See " Documentation/devicetree/bindings/net/can/sja1000.txt " for further
2009-05-30 07:55:50 +00:00
* information .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/netdevice.h>
# include <linux/delay.h>
2011-06-29 02:55:28 -07:00
# include <linux/io.h>
2009-05-30 07:55:50 +00:00
# include <linux/can/dev.h>
# include <linux/of_platform.h>
2012-10-04 15:59:10 +02:00
# include <linux/of_address.h>
# include <linux/of_irq.h>
2009-05-30 07:55:50 +00:00
# include "sja1000.h"
# define DRV_NAME "sja1000_of_platform"
MODULE_AUTHOR ( " Wolfgang Grandegger <wg@grandegger.com> " ) ;
MODULE_DESCRIPTION ( " Socket-CAN driver for SJA1000 on the OF platform bus " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
# define SJA1000_OFP_CAN_CLOCK (16000000 / 2)
# define SJA1000_OFP_OCR OCR_TX0_PULLDOWN
# define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF)
static u8 sja1000_ofp_read_reg ( const struct sja1000_priv * priv , int reg )
{
2012-10-04 15:59:10 +02:00
return ioread8 ( priv - > reg_base + reg ) ;
2009-05-30 07:55:50 +00:00
}
static void sja1000_ofp_write_reg ( const struct sja1000_priv * priv ,
int reg , u8 val )
{
2012-10-04 15:59:10 +02:00
iowrite8 ( val , priv - > reg_base + reg ) ;
2009-05-30 07:55:50 +00:00
}
2012-12-03 09:22:44 -05:00
static int sja1000_ofp_remove ( struct platform_device * ofdev )
2009-05-30 07:55:50 +00:00
{
2013-05-23 19:47:58 +09:00
struct net_device * dev = platform_get_drvdata ( ofdev ) ;
2009-05-30 07:55:50 +00:00
struct sja1000_priv * priv = netdev_priv ( dev ) ;
2010-04-13 16:12:29 -07:00
struct device_node * np = ofdev - > dev . of_node ;
2009-05-30 07:55:50 +00:00
struct resource res ;
unregister_sja1000dev ( dev ) ;
free_sja1000dev ( dev ) ;
iounmap ( priv - > reg_base ) ;
irq_dispose_mapping ( dev - > irq ) ;
of_address_to_resource ( np , 0 , & res ) ;
release_mem_region ( res . start , resource_size ( & res ) ) ;
return 0 ;
}
2012-12-03 09:22:44 -05:00
static int sja1000_ofp_probe ( struct platform_device * ofdev )
2009-05-30 07:55:50 +00:00
{
2010-04-13 16:12:29 -07:00
struct device_node * np = ofdev - > dev . of_node ;
2009-05-30 07:55:50 +00:00
struct net_device * dev ;
struct sja1000_priv * priv ;
struct resource res ;
2013-04-11 21:32:57 +02:00
u32 prop ;
int err , irq , res_size ;
2009-05-30 07:55:50 +00:00
void __iomem * base ;
err = of_address_to_resource ( np , 0 , & res ) ;
if ( err ) {
dev_err ( & ofdev - > dev , " invalid address \n " ) ;
return err ;
}
res_size = resource_size ( & res ) ;
if ( ! request_mem_region ( res . start , res_size , DRV_NAME ) ) {
2010-11-12 11:37:59 +00:00
dev_err ( & ofdev - > dev , " couldn't request %pR \n " , & res ) ;
2009-05-30 07:55:50 +00:00
return - EBUSY ;
}
base = ioremap_nocache ( res . start , res_size ) ;
if ( ! base ) {
2010-11-12 11:37:59 +00:00
dev_err ( & ofdev - > dev , " couldn't ioremap %pR \n " , & res ) ;
2009-05-30 07:55:50 +00:00
err = - ENOMEM ;
goto exit_release_mem ;
}
irq = irq_of_parse_and_map ( np , 0 ) ;
2012-12-14 12:25:12 +00:00
if ( irq = = 0 ) {
2009-05-30 07:55:50 +00:00
dev_err ( & ofdev - > dev , " no irq found \n " ) ;
err = - ENODEV ;
goto exit_unmap_mem ;
}
dev = alloc_sja1000dev ( 0 ) ;
if ( ! dev ) {
err = - ENOMEM ;
goto exit_dispose_irq ;
}
priv = netdev_priv ( dev ) ;
priv - > read_reg = sja1000_ofp_read_reg ;
priv - > write_reg = sja1000_ofp_write_reg ;
2013-04-11 21:32:57 +02:00
err = of_property_read_u32 ( np , " nxp,external-clock-frequency " , & prop ) ;
if ( ! err )
priv - > can . clock . freq = prop / 2 ;
2009-05-30 07:55:50 +00:00
else
priv - > can . clock . freq = SJA1000_OFP_CAN_CLOCK ; /* default */
2013-04-11 21:32:57 +02:00
err = of_property_read_u32 ( np , " nxp,tx-output-mode " , & prop ) ;
if ( ! err )
priv - > ocr | = prop & OCR_MODE_MASK ;
2009-05-30 07:55:50 +00:00
else
priv - > ocr | = OCR_MODE_NORMAL ; /* default */
2013-04-11 21:32:57 +02:00
err = of_property_read_u32 ( np , " nxp,tx-output-config " , & prop ) ;
if ( ! err )
priv - > ocr | = ( prop < < OCR_TX_SHIFT ) & OCR_TX_MASK ;
2009-05-30 07:55:50 +00:00
else
priv - > ocr | = OCR_TX0_PULLDOWN ; /* default */
2013-04-11 21:32:57 +02:00
err = of_property_read_u32 ( np , " nxp,clock-out-frequency " , & prop ) ;
if ( ! err & & prop ) {
u32 divider = priv - > can . clock . freq * 2 / prop ;
2009-05-30 07:55:50 +00:00
if ( divider > 1 )
priv - > cdr | = divider / 2 - 1 ;
else
priv - > cdr | = CDR_CLKOUT_MASK ;
} else {
priv - > cdr | = CDR_CLK_OFF ; /* default */
}
2013-04-11 21:32:57 +02:00
if ( ! of_property_read_bool ( np , " nxp,no-comparator-bypass " ) )
2009-05-30 07:55:50 +00:00
priv - > cdr | = CDR_CBP ; /* default */
priv - > irq_flags = IRQF_SHARED ;
priv - > reg_base = base ;
dev - > irq = irq ;
dev_info ( & ofdev - > dev ,
" reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x \n " ,
priv - > reg_base , dev - > irq , priv - > can . clock . freq ,
priv - > ocr , priv - > cdr ) ;
2013-05-23 19:47:58 +09:00
platform_set_drvdata ( ofdev , dev ) ;
2009-05-30 07:55:50 +00:00
SET_NETDEV_DEV ( dev , & ofdev - > dev ) ;
err = register_sja1000dev ( dev ) ;
if ( err ) {
dev_err ( & ofdev - > dev , " registering %s failed (err=%d) \n " ,
DRV_NAME , err ) ;
goto exit_free_sja1000 ;
}
return 0 ;
exit_free_sja1000 :
free_sja1000dev ( dev ) ;
exit_dispose_irq :
irq_dispose_mapping ( irq ) ;
exit_unmap_mem :
iounmap ( base ) ;
exit_release_mem :
release_mem_region ( res . start , res_size ) ;
return err ;
}
2012-12-03 09:22:44 -05:00
static struct of_device_id sja1000_ofp_table [ ] = {
2009-05-30 07:55:50 +00:00
{ . compatible = " nxp,sja1000 " } ,
{ } ,
} ;
2009-10-14 14:54:52 -07:00
MODULE_DEVICE_TABLE ( of , sja1000_ofp_table ) ;
2009-05-30 07:55:50 +00:00
2011-02-22 21:05:51 -07:00
static struct platform_driver sja1000_ofp_driver = {
2010-04-13 16:13:02 -07:00
. driver = {
. owner = THIS_MODULE ,
. name = DRV_NAME ,
. of_match_table = sja1000_ofp_table ,
} ,
2009-05-30 07:55:50 +00:00
. probe = sja1000_ofp_probe ,
2012-12-03 09:22:44 -05:00
. remove = sja1000_ofp_remove ,
2009-05-30 07:55:50 +00:00
} ;
2011-11-27 15:42:31 +00:00
module_platform_driver ( sja1000_ofp_driver ) ;