@ -18,22 +18,129 @@
# include <linux/of.h>
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
# include <dt-bindings/soc/qcom,gsbi.h>
# define GSBI_CTRL_REG 0x0000
# define GSBI_CTRL_REG 0x0000
# define GSBI_PROTOCOL_SHIFT 4
# define GSBI_PROTOCOL_SHIFT 4
# define MAX_GSBI 12
# define TCSR_ADM_CRCI_BASE 0x70
struct crci_config {
u32 num_rows ;
const u32 ( * array ) [ MAX_GSBI ] ;
} ;
static const u32 crci_ipq8064 [ ] [ MAX_GSBI ] = {
{
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000c00 , 0x003000 , 0x00c000 ,
0x030000 , 0x0c0000 , 0x300000 , 0xc00000
} ,
{
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000c00 , 0x003000 , 0x00c000 ,
0x030000 , 0x0c0000 , 0x300000 , 0xc00000
} ,
} ;
static const struct crci_config config_ipq8064 = {
. num_rows = ARRAY_SIZE ( crci_ipq8064 ) ,
. array = crci_ipq8064 ,
} ;
static const unsigned int crci_apq8064 [ ] [ MAX_GSBI ] = {
{
0x001800 , 0x006000 , 0x000030 , 0x0000c0 ,
0x000300 , 0x000400 , 0x000000 , 0x000000 ,
0x000000 , 0x000000 , 0x000000 , 0x000000
} ,
{
0x000000 , 0x000000 , 0x000000 , 0x000000 ,
0x000000 , 0x000020 , 0x0000c0 , 0x000000 ,
0x000000 , 0x000000 , 0x000000 , 0x000000
} ,
} ;
static const struct crci_config config_apq8064 = {
. num_rows = ARRAY_SIZE ( crci_apq8064 ) ,
. array = crci_apq8064 ,
} ;
static const unsigned int crci_msm8960 [ ] [ MAX_GSBI ] = {
{
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000400 , 0x000000 , 0x000000 ,
0x000000 , 0x000000 , 0x000000 , 0x000000
} ,
{
0x000000 , 0x000000 , 0x000000 , 0x000000 ,
0x000000 , 0x000020 , 0x0000c0 , 0x000300 ,
0x001800 , 0x006000 , 0x000000 , 0x000000
} ,
} ;
static const struct crci_config config_msm8960 = {
. num_rows = ARRAY_SIZE ( crci_msm8960 ) ,
. array = crci_msm8960 ,
} ;
static const unsigned int crci_msm8660 [ ] [ MAX_GSBI ] = {
{ /* ADM 0 - B */
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000c00 , 0x003000 , 0x00c000 ,
0x030000 , 0x0c0000 , 0x300000 , 0xc00000
} ,
{ /* ADM 0 - B */
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000c00 , 0x003000 , 0x00c000 ,
0x030000 , 0x0c0000 , 0x300000 , 0xc00000
} ,
{ /* ADM 1 - A */
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000c00 , 0x003000 , 0x00c000 ,
0x030000 , 0x0c0000 , 0x300000 , 0xc00000
} ,
{ /* ADM 1 - B */
0x000003 , 0x00000c , 0x000030 , 0x0000c0 ,
0x000300 , 0x000c00 , 0x003000 , 0x00c000 ,
0x030000 , 0x0c0000 , 0x300000 , 0xc00000
} ,
} ;
static const struct crci_config config_msm8660 = {
. num_rows = ARRAY_SIZE ( crci_msm8660 ) ,
. array = crci_msm8660 ,
} ;
struct gsbi_info {
struct gsbi_info {
struct clk * hclk ;
struct clk * hclk ;
u32 mode ;
u32 mode ;
u32 crci ;
u32 crci ;
struct regmap * tcsr ;
} ;
static const struct of_device_id tcsr_dt_match [ ] = {
{ . compatible = " qcom,tcsr-ipq8064 " , . data = & config_ipq8064 } ,
{ . compatible = " qcom,tcsr-apq8064 " , . data = & config_apq8064 } ,
{ . compatible = " qcom,tcsr-msm8960 " , . data = & config_msm8960 } ,
{ . compatible = " qcom,tcsr-msm8660 " , . data = & config_msm8660 } ,
{ } ,
} ;
} ;
static int gsbi_probe ( struct platform_device * pdev )
static int gsbi_probe ( struct platform_device * pdev )
{
{
struct device_node * node = pdev - > dev . of_node ;
struct device_node * node = pdev - > dev . of_node ;
struct device_node * tcsr_node ;
const struct of_device_id * match ;
struct resource * res ;
struct resource * res ;
void __iomem * base ;
void __iomem * base ;
struct gsbi_info * gsbi ;
struct gsbi_info * gsbi ;
int i ;
u32 mask , gsbi_num ;
const struct crci_config * config = NULL ;
gsbi = devm_kzalloc ( & pdev - > dev , sizeof ( * gsbi ) , GFP_KERNEL ) ;
gsbi = devm_kzalloc ( & pdev - > dev , sizeof ( * gsbi ) , GFP_KERNEL ) ;
@ -45,6 +152,32 @@ static int gsbi_probe(struct platform_device *pdev)
if ( IS_ERR ( base ) )
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
return PTR_ERR ( base ) ;
/* get the tcsr node and setup the config and regmap */
gsbi - > tcsr = syscon_regmap_lookup_by_phandle ( node , " syscon-tcsr " ) ;
if ( ! IS_ERR ( gsbi - > tcsr ) ) {
tcsr_node = of_parse_phandle ( node , " syscon-tcsr " , 0 ) ;
if ( tcsr_node ) {
match = of_match_node ( tcsr_dt_match , tcsr_node ) ;
if ( match )
config = match - > data ;
else
dev_warn ( & pdev - > dev , " no matching TCSR \n " ) ;
of_node_put ( tcsr_node ) ;
}
}
if ( of_property_read_u32 ( node , " cell-index " , & gsbi_num ) ) {
dev_err ( & pdev - > dev , " missing cell-index \n " ) ;
return - EINVAL ;
}
if ( gsbi_num < 1 | | gsbi_num > MAX_GSBI ) {
dev_err ( & pdev - > dev , " invalid cell-index \n " ) ;
return - EINVAL ;
}
if ( of_property_read_u32 ( node , " qcom,mode " , & gsbi - > mode ) ) {
if ( of_property_read_u32 ( node , " qcom,mode " , & gsbi - > mode ) ) {
dev_err ( & pdev - > dev , " missing mode configuration \n " ) ;
dev_err ( & pdev - > dev , " missing mode configuration \n " ) ;
return - EINVAL ;
return - EINVAL ;
@ -64,6 +197,25 @@ static int gsbi_probe(struct platform_device *pdev)
writel_relaxed ( ( gsbi - > mode < < GSBI_PROTOCOL_SHIFT ) | gsbi - > crci ,
writel_relaxed ( ( gsbi - > mode < < GSBI_PROTOCOL_SHIFT ) | gsbi - > crci ,
base + GSBI_CTRL_REG ) ;
base + GSBI_CTRL_REG ) ;
/*
* modify tcsr to reflect mode and ADM CRCI mux
* Each gsbi contains a pair of bits , one for RX and one for TX
* SPI mode requires both bits cleared , otherwise they are set
*/
if ( config ) {
for ( i = 0 ; i < config - > num_rows ; i + + ) {
mask = config - > array [ i ] [ gsbi_num - 1 ] ;
if ( gsbi - > mode = = GSBI_PROT_SPI )
regmap_update_bits ( gsbi - > tcsr ,
TCSR_ADM_CRCI_BASE + 4 * i , mask , 0 ) ;
else
regmap_update_bits ( gsbi - > tcsr ,
TCSR_ADM_CRCI_BASE + 4 * i , mask , mask ) ;
}
}
/* make sure the gsbi control write is not reordered */
/* make sure the gsbi control write is not reordered */
wmb ( ) ;
wmb ( ) ;