2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2014-08-26 15:06:33 +08:00
/*
* Copyright 2014 Freescale Semiconductor , Inc .
*/
# include <linux/clk-provider.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/slab.h>
# include "clk.h"
/**
* struct clk_gate_exclusive - i . MX specific gate clock which is mutually
* exclusive with other gate clocks
*
* @ gate : the parent class
* @ exclusive_mask : mask of gate bits which are mutually exclusive to this
* gate clock
*
* The imx exclusive gate clock is a subclass of basic clk_gate
* with an addtional mask to indicate which other gate bits in the same
* register is mutually exclusive to this gate clock .
*/
struct clk_gate_exclusive {
struct clk_gate gate ;
u32 exclusive_mask ;
} ;
static int clk_gate_exclusive_enable ( struct clk_hw * hw )
{
2016-01-08 23:51:46 +08:00
struct clk_gate * gate = to_clk_gate ( hw ) ;
2014-08-26 15:06:33 +08:00
struct clk_gate_exclusive * exgate = container_of ( gate ,
struct clk_gate_exclusive , gate ) ;
u32 val = readl ( gate - > reg ) ;
if ( val & exgate - > exclusive_mask )
return - EBUSY ;
return clk_gate_ops . enable ( hw ) ;
}
static void clk_gate_exclusive_disable ( struct clk_hw * hw )
{
clk_gate_ops . disable ( hw ) ;
}
static int clk_gate_exclusive_is_enabled ( struct clk_hw * hw )
{
return clk_gate_ops . is_enabled ( hw ) ;
}
static const struct clk_ops clk_gate_exclusive_ops = {
. enable = clk_gate_exclusive_enable ,
. disable = clk_gate_exclusive_disable ,
. is_enabled = clk_gate_exclusive_is_enabled ,
} ;
2019-05-29 12:26:43 +00:00
struct clk_hw * imx_clk_hw_gate_exclusive ( const char * name , const char * parent ,
2014-08-26 15:06:33 +08:00
void __iomem * reg , u8 shift , u32 exclusive_mask )
{
struct clk_gate_exclusive * exgate ;
struct clk_gate * gate ;
2019-05-29 12:26:43 +00:00
struct clk_hw * hw ;
2014-08-26 15:06:33 +08:00
struct clk_init_data init ;
2019-05-29 12:26:43 +00:00
int ret ;
2014-08-26 15:06:33 +08:00
if ( exclusive_mask = = 0 )
return ERR_PTR ( - EINVAL ) ;
exgate = kzalloc ( sizeof ( * exgate ) , GFP_KERNEL ) ;
if ( ! exgate )
return ERR_PTR ( - ENOMEM ) ;
gate = & exgate - > gate ;
init . name = name ;
init . ops = & clk_gate_exclusive_ops ;
init . flags = CLK_SET_RATE_PARENT ;
init . parent_names = parent ? & parent : NULL ;
init . num_parents = parent ? 1 : 0 ;
gate - > reg = reg ;
gate - > bit_idx = shift ;
gate - > lock = & imx_ccm_lock ;
gate - > hw . init = & init ;
exgate - > exclusive_mask = exclusive_mask ;
2019-05-29 12:26:43 +00:00
hw = & gate - > hw ;
2014-08-26 15:06:33 +08:00
2019-05-29 12:26:43 +00:00
ret = clk_hw_register ( NULL , hw ) ;
if ( ret ) {
kfree ( gate ) ;
return ERR_PTR ( ret ) ;
}
return hw ;
2014-08-26 15:06:33 +08:00
}