2016-06-10 04:23:53 +03:00
/*
* B53 register access through Switch Register Access Bridge Registers
*
* Copyright ( C ) 2013 Hauke Mehrtens < hauke @ hauke - m . de >
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
# include <linux/platform_data/b53.h>
2016-07-08 21:39:12 +03:00
# include <linux/of.h>
2016-06-10 04:23:53 +03:00
# include "b53_priv.h"
/* command and status register of the SRAB */
# define B53_SRAB_CMDSTAT 0x2c
# define B53_SRAB_CMDSTAT_RST BIT(2)
# define B53_SRAB_CMDSTAT_WRITE BIT(1)
# define B53_SRAB_CMDSTAT_GORDYN BIT(0)
# define B53_SRAB_CMDSTAT_PAGE 24
# define B53_SRAB_CMDSTAT_REG 16
/* high order word of write data to switch registe */
# define B53_SRAB_WD_H 0x30
/* low order word of write data to switch registe */
# define B53_SRAB_WD_L 0x34
/* high order word of read data from switch register */
# define B53_SRAB_RD_H 0x38
/* low order word of read data from switch register */
# define B53_SRAB_RD_L 0x3c
/* command and status register of the SRAB */
# define B53_SRAB_CTRLS 0x40
# define B53_SRAB_CTRLS_RCAREQ BIT(3)
# define B53_SRAB_CTRLS_RCAGNT BIT(4)
# define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
/* the register captures interrupt pulses from the switch */
# define B53_SRAB_INTR 0x44
# define B53_SRAB_INTR_P(x) BIT(x)
# define B53_SRAB_SWITCH_PHY BIT(8)
# define B53_SRAB_1588_SYNC BIT(9)
# define B53_SRAB_IMP1_SLEEP_TIMER BIT(10)
# define B53_SRAB_P7_SLEEP_TIMER BIT(11)
# define B53_SRAB_IMP0_SLEEP_TIMER BIT(12)
struct b53_srab_priv {
void __iomem * regs ;
} ;
static int b53_srab_request_grant ( struct b53_device * dev )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
u32 ctrls ;
int i ;
ctrls = readl ( regs + B53_SRAB_CTRLS ) ;
ctrls | = B53_SRAB_CTRLS_RCAREQ ;
writel ( ctrls , regs + B53_SRAB_CTRLS ) ;
for ( i = 0 ; i < 20 ; i + + ) {
ctrls = readl ( regs + B53_SRAB_CTRLS ) ;
if ( ctrls & B53_SRAB_CTRLS_RCAGNT )
break ;
usleep_range ( 10 , 100 ) ;
}
if ( WARN_ON ( i = = 5 ) )
return - EIO ;
return 0 ;
}
static void b53_srab_release_grant ( struct b53_device * dev )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
u32 ctrls ;
ctrls = readl ( regs + B53_SRAB_CTRLS ) ;
ctrls & = ~ B53_SRAB_CTRLS_RCAREQ ;
writel ( ctrls , regs + B53_SRAB_CTRLS ) ;
}
static int b53_srab_op ( struct b53_device * dev , u8 page , u8 reg , u32 op )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int i ;
u32 cmdstat ;
/* set register address */
cmdstat = ( page < < B53_SRAB_CMDSTAT_PAGE ) |
( reg < < B53_SRAB_CMDSTAT_REG ) |
B53_SRAB_CMDSTAT_GORDYN |
op ;
writel ( cmdstat , regs + B53_SRAB_CMDSTAT ) ;
/* check if operation completed */
for ( i = 0 ; i < 5 ; + + i ) {
cmdstat = readl ( regs + B53_SRAB_CMDSTAT ) ;
if ( ! ( cmdstat & B53_SRAB_CMDSTAT_GORDYN ) )
break ;
usleep_range ( 10 , 100 ) ;
}
if ( WARN_ON ( i = = 5 ) )
return - EIO ;
return 0 ;
}
static int b53_srab_read8 ( struct b53_device * dev , u8 page , u8 reg , u8 * val )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
ret = b53_srab_op ( dev , page , reg , 0 ) ;
if ( ret )
goto err ;
* val = readl ( regs + B53_SRAB_RD_L ) & 0xff ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_read16 ( struct b53_device * dev , u8 page , u8 reg , u16 * val )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
ret = b53_srab_op ( dev , page , reg , 0 ) ;
if ( ret )
goto err ;
* val = readl ( regs + B53_SRAB_RD_L ) & 0xffff ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_read32 ( struct b53_device * dev , u8 page , u8 reg , u32 * val )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
ret = b53_srab_op ( dev , page , reg , 0 ) ;
if ( ret )
goto err ;
* val = readl ( regs + B53_SRAB_RD_L ) ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_read48 ( struct b53_device * dev , u8 page , u8 reg , u64 * val )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
ret = b53_srab_op ( dev , page , reg , 0 ) ;
if ( ret )
goto err ;
* val = readl ( regs + B53_SRAB_RD_L ) ;
* val + = ( ( u64 ) readl ( regs + B53_SRAB_RD_H ) & 0xffff ) < < 32 ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_read64 ( struct b53_device * dev , u8 page , u8 reg , u64 * val )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
ret = b53_srab_op ( dev , page , reg , 0 ) ;
if ( ret )
goto err ;
* val = readl ( regs + B53_SRAB_RD_L ) ;
* val + = ( u64 ) readl ( regs + B53_SRAB_RD_H ) < < 32 ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_write8 ( struct b53_device * dev , u8 page , u8 reg , u8 value )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
writel ( value , regs + B53_SRAB_WD_L ) ;
ret = b53_srab_op ( dev , page , reg , B53_SRAB_CMDSTAT_WRITE ) ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_write16 ( struct b53_device * dev , u8 page , u8 reg ,
u16 value )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
writel ( value , regs + B53_SRAB_WD_L ) ;
ret = b53_srab_op ( dev , page , reg , B53_SRAB_CMDSTAT_WRITE ) ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_write32 ( struct b53_device * dev , u8 page , u8 reg ,
u32 value )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
writel ( value , regs + B53_SRAB_WD_L ) ;
ret = b53_srab_op ( dev , page , reg , B53_SRAB_CMDSTAT_WRITE ) ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_write48 ( struct b53_device * dev , u8 page , u8 reg ,
u64 value )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
writel ( ( u32 ) value , regs + B53_SRAB_WD_L ) ;
writel ( ( u16 ) ( value > > 32 ) , regs + B53_SRAB_WD_H ) ;
ret = b53_srab_op ( dev , page , reg , B53_SRAB_CMDSTAT_WRITE ) ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
static int b53_srab_write64 ( struct b53_device * dev , u8 page , u8 reg ,
u64 value )
{
struct b53_srab_priv * priv = dev - > priv ;
u8 __iomem * regs = priv - > regs ;
int ret = 0 ;
ret = b53_srab_request_grant ( dev ) ;
if ( ret )
goto err ;
writel ( ( u32 ) value , regs + B53_SRAB_WD_L ) ;
writel ( ( u32 ) ( value > > 32 ) , regs + B53_SRAB_WD_H ) ;
ret = b53_srab_op ( dev , page , reg , B53_SRAB_CMDSTAT_WRITE ) ;
err :
b53_srab_release_grant ( dev ) ;
return ret ;
}
2016-08-09 20:09:45 +03:00
static const struct b53_io_ops b53_srab_ops = {
2016-06-10 04:23:53 +03:00
. read8 = b53_srab_read8 ,
. read16 = b53_srab_read16 ,
. read32 = b53_srab_read32 ,
. read48 = b53_srab_read48 ,
. read64 = b53_srab_read64 ,
. write8 = b53_srab_write8 ,
. write16 = b53_srab_write16 ,
. write32 = b53_srab_write32 ,
. write48 = b53_srab_write48 ,
. write64 = b53_srab_write64 ,
} ;
2016-07-08 21:39:12 +03:00
static const struct of_device_id b53_srab_of_match [ ] = {
{ . compatible = " brcm,bcm53010-srab " } ,
{ . compatible = " brcm,bcm53011-srab " } ,
{ . compatible = " brcm,bcm53012-srab " } ,
{ . compatible = " brcm,bcm53018-srab " } ,
{ . compatible = " brcm,bcm53019-srab " } ,
{ . compatible = " brcm,bcm5301x-srab " } ,
2016-07-08 21:39:13 +03:00
{ . compatible = " brcm,bcm58522-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,bcm58525-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,bcm58535-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,bcm58622-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,bcm58623-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,bcm58625-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,bcm88312-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
{ . compatible = " brcm,nsp-srab " , . data = ( void * ) BCM58XX_DEVICE_ID } ,
2016-07-08 21:39:12 +03:00
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , b53_srab_of_match ) ;
2016-06-10 04:23:53 +03:00
static int b53_srab_probe ( struct platform_device * pdev )
{
2016-07-08 21:39:12 +03:00
struct b53_platform_data * pdata = pdev - > dev . platform_data ;
struct device_node * dn = pdev - > dev . of_node ;
const struct of_device_id * of_id = NULL ;
2016-06-10 04:23:53 +03:00
struct b53_srab_priv * priv ;
struct b53_device * dev ;
struct resource * r ;
2016-07-08 21:39:12 +03:00
if ( dn )
of_id = of_match_node ( b53_srab_of_match , dn ) ;
if ( of_id ) {
pdata = devm_kzalloc ( & pdev - > dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return - ENOMEM ;
2016-07-12 00:30:52 +03:00
pdata - > chip_id = ( u32 ) ( unsigned long ) of_id - > data ;
2016-07-08 21:39:12 +03:00
}
2016-06-10 04:23:53 +03:00
priv = devm_kzalloc ( & pdev - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
priv - > regs = devm_ioremap_resource ( & pdev - > dev , r ) ;
if ( IS_ERR ( priv - > regs ) )
return - ENOMEM ;
dev = b53_switch_alloc ( & pdev - > dev , & b53_srab_ops , priv ) ;
if ( ! dev )
return - ENOMEM ;
2016-07-08 21:39:12 +03:00
if ( pdata )
dev - > pdata = pdata ;
2016-06-10 04:23:53 +03:00
platform_set_drvdata ( pdev , dev ) ;
return b53_switch_register ( dev ) ;
}
static int b53_srab_remove ( struct platform_device * pdev )
{
struct b53_device * dev = platform_get_drvdata ( pdev ) ;
if ( dev )
b53_switch_remove ( dev ) ;
return 0 ;
}
static struct platform_driver b53_srab_driver = {
. probe = b53_srab_probe ,
. remove = b53_srab_remove ,
. driver = {
. name = " b53-srab-switch " ,
. of_match_table = b53_srab_of_match ,
} ,
} ;
module_platform_driver ( b53_srab_driver ) ;
MODULE_AUTHOR ( " Hauke Mehrtens <hauke@hauke-m.de> " ) ;
MODULE_DESCRIPTION ( " B53 Switch Register Access Bridge Registers (SRAB) access driver " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;