2013-02-25 18:44:26 +04:00
/*
* Copyright 2013 Emilio López
*
* Emilio López < emilio @ elopez . com . ar >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
*/
2015-06-20 01:00:46 +03:00
# include <linux/clk.h>
2013-02-25 18:44:26 +04:00
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
# include <linux/of.h>
# include <linux/of_address.h>
2014-02-07 19:21:49 +04:00
# include <linux/reset-controller.h>
2015-06-20 01:00:46 +03:00
# include <linux/slab.h>
2014-07-05 00:24:52 +04:00
# include <linux/spinlock.h>
2014-11-26 10:16:52 +03:00
# include <linux/log2.h>
2013-02-25 18:44:26 +04:00
# include "clk-factors.h"
static DEFINE_SPINLOCK ( clk_lock ) ;
2013-12-23 07:32:32 +04:00
/* Maximum number of parents our clocks have */
# define SUNXI_MAX_PARENTS 5
2013-02-25 18:44:26 +04:00
/**
2013-07-22 20:21:32 +04:00
* sun4i_get_pll1_factors ( ) - calculates n , k , m , p factors for PLL1
2013-02-25 18:44:26 +04:00
* PLL1 rate is calculated as follows
* rate = ( parent_rate * n * ( k + 1 ) > > p ) / ( m + 1 ) ;
* parent_rate is always 24 Mhz
*/
2016-01-25 16:15:42 +03:00
static void sun4i_get_pll1_factors ( struct factors_request * req )
2013-02-25 18:44:26 +04:00
{
u8 div ;
/* Normalize value to a 6M multiple */
2016-01-25 16:15:42 +03:00
div = req - > rate / 6000000 ;
req - > rate = 6000000 * div ;
2013-02-25 18:44:26 +04:00
/* m is always zero for pll1 */
2016-01-25 16:15:42 +03:00
req - > m = 0 ;
2013-02-25 18:44:26 +04:00
/* k is 1 only on these cases */
2016-01-25 16:15:42 +03:00
if ( req - > rate > = 768000000 | | req - > rate = = 42000000 | |
req - > rate = = 54000000 )
req - > k = 1 ;
2013-02-25 18:44:26 +04:00
else
2016-01-25 16:15:42 +03:00
req - > k = 0 ;
2013-02-25 18:44:26 +04:00
/* p will be 3 for divs under 10 */
if ( div < 10 )
2016-01-25 16:15:42 +03:00
req - > p = 3 ;
2013-02-25 18:44:26 +04:00
/* p will be 2 for divs between 10 - 20 and odd divs under 32 */
else if ( div < 20 | | ( div < 32 & & ( div & 1 ) ) )
2016-01-25 16:15:42 +03:00
req - > p = 2 ;
2013-02-25 18:44:26 +04:00
/* p will be 1 for even divs under 32, divs under 40 and odd pairs
* of divs between 40 - 62 */
else if ( div < 40 | | ( div < 64 & & ( div & 2 ) ) )
2016-01-25 16:15:42 +03:00
req - > p = 1 ;
2013-02-25 18:44:26 +04:00
/* any other entries have p = 0 */
else
2016-01-25 16:15:42 +03:00
req - > p = 0 ;
2013-02-25 18:44:26 +04:00
/* calculate a suitable n based on k and p */
2016-01-25 16:15:42 +03:00
div < < = req - > p ;
div / = ( req - > k + 1 ) ;
req - > n = div / 4 ;
2013-02-25 18:44:26 +04:00
}
2013-07-24 01:34:10 +04:00
/**
* sun6i_a31_get_pll1_factors ( ) - calculates n , k and m factors for PLL1
* PLL1 rate is calculated as follows
* rate = parent_rate * ( n + 1 ) * ( k + 1 ) / ( m + 1 ) ;
* parent_rate should always be 24 MHz
*/
2016-01-25 16:15:42 +03:00
static void sun6i_a31_get_pll1_factors ( struct factors_request * req )
2013-07-24 01:34:10 +04:00
{
/*
* We can operate only on MHz , this will make our life easier
* later .
*/
2016-01-25 16:15:42 +03:00
u32 freq_mhz = req - > rate / 1000000 ;
u32 parent_freq_mhz = req - > parent_rate / 1000000 ;
2013-07-24 01:34:10 +04:00
/*
* Round down the frequency to the closest multiple of either
* 6 or 16
*/
u32 round_freq_6 = round_down ( freq_mhz , 6 ) ;
u32 round_freq_16 = round_down ( freq_mhz , 16 ) ;
if ( round_freq_6 > round_freq_16 )
freq_mhz = round_freq_6 ;
else
freq_mhz = round_freq_16 ;
2013-02-25 18:44:26 +04:00
2016-01-25 16:15:42 +03:00
req - > rate = freq_mhz * 1000000 ;
2013-07-24 01:34:10 +04:00
/* If the frequency is a multiple of 32 MHz, k is always 3 */
if ( ! ( freq_mhz % 32 ) )
2016-01-25 16:15:42 +03:00
req - > k = 3 ;
2013-07-24 01:34:10 +04:00
/* If the frequency is a multiple of 9 MHz, k is always 2 */
else if ( ! ( freq_mhz % 9 ) )
2016-01-25 16:15:42 +03:00
req - > k = 2 ;
2013-07-24 01:34:10 +04:00
/* If the frequency is a multiple of 8 MHz, k is always 1 */
else if ( ! ( freq_mhz % 8 ) )
2016-01-25 16:15:42 +03:00
req - > k = 1 ;
2013-07-24 01:34:10 +04:00
/* Otherwise, we don't use the k factor */
else
2016-01-25 16:15:42 +03:00
req - > k = 0 ;
2013-07-24 01:34:10 +04:00
/*
* If the frequency is a multiple of 2 but not a multiple of
* 3 , m is 3. This is the first time we use 6 here , yet we
* will use it on several other places .
* We use this number because it ' s the lowest frequency we can
* generate ( with n = 0 , k = 0 , m = 3 ) , so every other frequency
* somehow relates to this frequency .
*/
if ( ( freq_mhz % 6 ) = = 2 | | ( freq_mhz % 6 ) = = 4 )
2016-01-25 16:15:42 +03:00
req - > m = 2 ;
2013-07-24 01:34:10 +04:00
/*
* If the frequency is a multiple of 6 MHz , but the factor is
* odd , m will be 3
*/
else if ( ( freq_mhz / 6 ) & 1 )
2016-01-25 16:15:42 +03:00
req - > m = 3 ;
2013-07-24 01:34:10 +04:00
/* Otherwise, we end up with m = 1 */
else
2016-01-25 16:15:42 +03:00
req - > m = 1 ;
2013-07-24 01:34:10 +04:00
/* Calculate n thanks to the above factors we already got */
2016-01-25 16:15:42 +03:00
req - > n = freq_mhz * ( req - > m + 1 ) / ( ( req - > k + 1 ) * parent_freq_mhz )
- 1 ;
2013-07-24 01:34:10 +04:00
/*
* If n end up being outbound , and that we can still decrease
* m , do it .
*/
2016-01-25 16:15:42 +03:00
if ( ( req - > n + 1 ) > 31 & & ( req - > m + 1 ) > 1 ) {
req - > n = ( req - > n + 1 ) / 2 - 1 ;
req - > m = ( req - > m + 1 ) / 2 - 1 ;
2013-07-24 01:34:10 +04:00
}
}
2013-02-25 18:44:26 +04:00
2014-06-26 19:55:43 +04:00
/**
* sun8i_a23_get_pll1_factors ( ) - calculates n , k , m , p factors for PLL1
* PLL1 rate is calculated as follows
* rate = ( parent_rate * ( n + 1 ) * ( k + 1 ) > > p ) / ( m + 1 ) ;
* parent_rate is always 24 Mhz
*/
2016-01-25 16:15:42 +03:00
static void sun8i_a23_get_pll1_factors ( struct factors_request * req )
2014-06-26 19:55:43 +04:00
{
u8 div ;
/* Normalize value to a 6M multiple */
2016-01-25 16:15:42 +03:00
div = req - > rate / 6000000 ;
req - > rate = 6000000 * div ;
2014-06-26 19:55:43 +04:00
/* m is always zero for pll1 */
2016-01-25 16:15:42 +03:00
req - > m = 0 ;
2014-06-26 19:55:43 +04:00
/* k is 1 only on these cases */
2016-01-25 16:15:42 +03:00
if ( req - > rate > = 768000000 | | req - > rate = = 42000000 | |
req - > rate = = 54000000 )
req - > k = 1 ;
2014-06-26 19:55:43 +04:00
else
2016-01-25 16:15:42 +03:00
req - > k = 0 ;
2014-06-26 19:55:43 +04:00
/* p will be 2 for divs under 20 and odd divs under 32 */
if ( div < 20 | | ( div < 32 & & ( div & 1 ) ) )
2016-01-25 16:15:42 +03:00
req - > p = 2 ;
2014-06-26 19:55:43 +04:00
/* p will be 1 for even divs under 32, divs under 40 and odd pairs
* of divs between 40 - 62 */
else if ( div < 40 | | ( div < 64 & & ( div & 2 ) ) )
2016-01-25 16:15:42 +03:00
req - > p = 1 ;
2014-06-26 19:55:43 +04:00
/* any other entries have p = 0 */
else
2016-01-25 16:15:42 +03:00
req - > p = 0 ;
2014-06-26 19:55:43 +04:00
/* calculate a suitable n based on k and p */
2016-01-25 16:15:42 +03:00
div < < = req - > p ;
div / = ( req - > k + 1 ) ;
req - > n = div / 4 - 1 ;
2014-06-26 19:55:43 +04:00
}
2013-12-23 07:32:37 +04:00
/**
* sun4i_get_pll5_factors ( ) - calculates n , k factors for PLL5
* PLL5 rate is calculated as follows
* rate = parent_rate * n * ( k + 1 )
* parent_rate is always 24 Mhz
*/
2016-01-25 16:15:42 +03:00
static void sun4i_get_pll5_factors ( struct factors_request * req )
2013-12-23 07:32:37 +04:00
{
u8 div ;
/* Normalize value to a parent_rate multiple (24M) */
2016-01-25 16:15:42 +03:00
div = req - > rate / req - > parent_rate ;
req - > rate = req - > parent_rate * div ;
2013-12-23 07:32:37 +04:00
if ( div < 31 )
2016-01-25 16:15:42 +03:00
req - > k = 0 ;
2013-12-23 07:32:37 +04:00
else if ( div / 2 < 31 )
2016-01-25 16:15:42 +03:00
req - > k = 1 ;
2013-12-23 07:32:37 +04:00
else if ( div / 3 < 31 )
2016-01-25 16:15:42 +03:00
req - > k = 2 ;
2013-12-23 07:32:37 +04:00
else
2016-01-25 16:15:42 +03:00
req - > k = 3 ;
2013-12-23 07:32:37 +04:00
2016-01-25 16:15:42 +03:00
req - > n = DIV_ROUND_UP ( div , ( req - > k + 1 ) ) ;
2013-12-23 07:32:37 +04:00
}
2014-02-05 17:05:03 +04:00
/**
2014-11-12 21:08:31 +03:00
* sun6i_a31_get_pll6_factors ( ) - calculates n , k factors for A31 PLL6x2
* PLL6x2 rate is calculated as follows
* rate = parent_rate * ( n + 1 ) * ( k + 1 )
2014-02-05 17:05:03 +04:00
* parent_rate is always 24 Mhz
*/
2016-01-25 16:15:42 +03:00
static void sun6i_a31_get_pll6_factors ( struct factors_request * req )
2014-02-05 17:05:03 +04:00
{
u8 div ;
2014-11-12 21:08:31 +03:00
/* Normalize value to a parent_rate multiple (24M) */
2016-01-25 16:15:42 +03:00
div = req - > rate / req - > parent_rate ;
req - > rate = req - > parent_rate * div ;
2014-02-05 17:05:03 +04:00
2016-01-25 16:15:42 +03:00
req - > k = div / 32 ;
if ( req - > k > 3 )
req - > k = 3 ;
2013-12-23 07:32:37 +04:00
2016-01-25 16:15:42 +03:00
req - > n = DIV_ROUND_UP ( div , ( req - > k + 1 ) ) - 1 ;
2014-02-05 17:05:03 +04:00
}
2013-12-23 07:32:37 +04:00
2015-03-19 20:19:03 +03:00
/**
* sun5i_a13_get_ahb_factors ( ) - calculates m , p factors for AHB
* AHB rate is calculated as follows
* rate = parent_rate > > p
*/
2016-01-25 16:15:42 +03:00
static void sun5i_a13_get_ahb_factors ( struct factors_request * req )
2015-03-19 20:19:03 +03:00
{
u32 div ;
/* divide only */
2016-01-25 16:15:42 +03:00
if ( req - > parent_rate < req - > rate )
req - > rate = req - > parent_rate ;
2015-03-19 20:19:03 +03:00
/*
* user manual says valid speed is 8 k ~ 276 M , but tests show it
* can work at speeds up to 300 M , just after reparenting to pll6
*/
2016-01-25 16:15:42 +03:00
if ( req - > rate < 8000 )
req - > rate = 8000 ;
if ( req - > rate > 300000000 )
req - > rate = 300000000 ;
2015-03-19 20:19:03 +03:00
2016-01-25 16:15:42 +03:00
div = order_base_2 ( DIV_ROUND_UP ( req - > parent_rate , req - > rate ) ) ;
2015-03-19 20:19:03 +03:00
/* p = 0 ~ 3 */
if ( div > 3 )
div = 3 ;
2016-01-25 16:15:42 +03:00
req - > rate = req - > parent_rate > > div ;
2015-03-19 20:19:03 +03:00
2016-01-25 16:15:42 +03:00
req - > p = div ;
2015-03-19 20:19:03 +03:00
}
2016-01-25 16:15:45 +03:00
# define SUN6I_AHB1_PARENT_PLL6 3
/**
* sun6i_a31_get_ahb_factors ( ) - calculates m , p factors for AHB
* AHB rate is calculated as follows
* rate = parent_rate > > p
*
* if parent is pll6 , then
* parent_rate = pll6 rate / ( m + 1 )
*/
static void sun6i_get_ahb1_factors ( struct factors_request * req )
{
u8 div , calcp , calcm = 1 ;
/*
* clock can only divide , so we will never be able to achieve
* frequencies higher than the parent frequency
*/
if ( req - > parent_rate & & req - > rate > req - > parent_rate )
req - > rate = req - > parent_rate ;
div = DIV_ROUND_UP ( req - > parent_rate , req - > rate ) ;
/* calculate pre-divider if parent is pll6 */
if ( req - > parent_index = = SUN6I_AHB1_PARENT_PLL6 ) {
if ( div < 4 )
calcp = 0 ;
else if ( div / 2 < 4 )
calcp = 1 ;
else if ( div / 4 < 4 )
calcp = 2 ;
else
calcp = 3 ;
calcm = DIV_ROUND_UP ( div , 1 < < calcp ) ;
} else {
calcp = __roundup_pow_of_two ( div ) ;
calcp = calcp > 3 ? 3 : calcp ;
}
req - > rate = ( req - > parent_rate / calcm ) > > calcp ;
req - > p = calcp ;
req - > m = calcm - 1 ;
}
/**
* sun6i_ahb1_recalc ( ) - calculates AHB clock rate from m , p factors and
* parent index
*/
static void sun6i_ahb1_recalc ( struct factors_request * req )
{
req - > rate = req - > parent_rate ;
/* apply pre-divider first if parent is pll6 */
if ( req - > parent_index = = SUN6I_AHB1_PARENT_PLL6 )
req - > rate / = req - > m + 1 ;
/* clk divider */
req - > rate > > = req - > p ;
}
2013-02-25 18:44:26 +04:00
/**
2013-07-22 20:21:32 +04:00
* sun4i_get_apb1_factors ( ) - calculates m , p factors for APB1
2013-02-25 18:44:26 +04:00
* APB1 rate is calculated as follows
* rate = ( parent_rate > > p ) / ( m + 1 ) ;
*/
2016-01-25 16:15:42 +03:00
static void sun4i_get_apb1_factors ( struct factors_request * req )
2013-02-25 18:44:26 +04:00
{
u8 calcm , calcp ;
2016-01-25 16:15:42 +03:00
int div ;
2013-02-25 18:44:26 +04:00
2016-01-25 16:15:42 +03:00
if ( req - > parent_rate < req - > rate )
req - > rate = req - > parent_rate ;
2013-02-25 18:44:26 +04:00
2016-01-25 16:15:42 +03:00
div = DIV_ROUND_UP ( req - > parent_rate , req - > rate ) ;
2013-02-25 18:44:26 +04:00
/* Invalid rate! */
2016-01-25 16:15:42 +03:00
if ( div > 32 )
2013-02-25 18:44:26 +04:00
return ;
2016-01-25 16:15:42 +03:00
if ( div < = 4 )
2013-02-25 18:44:26 +04:00
calcp = 0 ;
2016-01-25 16:15:42 +03:00
else if ( div < = 8 )
2013-02-25 18:44:26 +04:00
calcp = 1 ;
2016-01-25 16:15:42 +03:00
else if ( div < = 16 )
2013-02-25 18:44:26 +04:00
calcp = 2 ;
else
calcp = 3 ;
2016-01-25 16:15:42 +03:00
calcm = ( req - > parent_rate > > calcp ) - 1 ;
2013-02-25 18:44:26 +04:00
2016-01-25 16:15:42 +03:00
req - > rate = ( req - > parent_rate > > calcp ) / ( calcm + 1 ) ;
req - > m = calcm ;
req - > p = calcp ;
2013-02-25 18:44:26 +04:00
}
2013-12-23 07:32:39 +04:00
2013-12-24 17:26:17 +04:00
/**
* sun7i_a20_get_out_factors ( ) - calculates m , p factors for CLK_OUT_A / B
* CLK_OUT rate is calculated as follows
* rate = ( parent_rate > > p ) / ( m + 1 ) ;
*/
2016-01-25 16:15:42 +03:00
static void sun7i_a20_get_out_factors ( struct factors_request * req )
2013-12-24 17:26:17 +04:00
{
u8 div , calcm , calcp ;
/* These clocks can only divide, so we will never be able to achieve
* frequencies higher than the parent frequency */
2016-01-25 16:15:42 +03:00
if ( req - > rate > req - > parent_rate )
req - > rate = req - > parent_rate ;
2013-12-24 17:26:17 +04:00
2016-01-25 16:15:42 +03:00
div = DIV_ROUND_UP ( req - > parent_rate , req - > rate ) ;
2013-12-24 17:26:17 +04:00
if ( div < 32 )
calcp = 0 ;
else if ( div / 2 < 32 )
calcp = 1 ;
else if ( div / 4 < 32 )
calcp = 2 ;
else
calcp = 3 ;
calcm = DIV_ROUND_UP ( div , 1 < < calcp ) ;
2016-01-25 16:15:42 +03:00
req - > rate = ( req - > parent_rate > > calcp ) / calcm ;
req - > m = calcm - 1 ;
req - > p = calcp ;
2013-12-24 17:26:17 +04:00
}
2013-02-25 18:44:26 +04:00
/**
* sunxi_factors_clk_setup ( ) - Setup function for factor clocks
*/
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun4i_pll1_config = {
2013-02-25 18:44:26 +04:00
. nshift = 8 ,
. nwidth = 5 ,
. kshift = 4 ,
. kwidth = 2 ,
. mshift = 0 ,
. mwidth = 2 ,
. pshift = 16 ,
. pwidth = 2 ,
} ;
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun6i_a31_pll1_config = {
2013-07-24 01:34:10 +04:00
. nshift = 8 ,
. nwidth = 5 ,
. kshift = 4 ,
. kwidth = 2 ,
. mshift = 0 ,
. mwidth = 2 ,
2015-01-24 14:56:32 +03:00
. n_start = 1 ,
2013-07-24 01:34:10 +04:00
} ;
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun8i_a23_pll1_config = {
2014-06-26 19:55:43 +04:00
. nshift = 8 ,
. nwidth = 5 ,
. kshift = 4 ,
. kwidth = 2 ,
. mshift = 0 ,
. mwidth = 2 ,
. pshift = 16 ,
. pwidth = 2 ,
. n_start = 1 ,
} ;
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun4i_pll5_config = {
2013-12-23 07:32:37 +04:00
. nshift = 8 ,
. nwidth = 5 ,
. kshift = 4 ,
. kwidth = 2 ,
} ;
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun6i_a31_pll6_config = {
2014-02-05 17:05:03 +04:00
. nshift = 8 ,
. nwidth = 5 ,
. kshift = 4 ,
. kwidth = 2 ,
2014-11-12 21:08:31 +03:00
. n_start = 1 ,
2014-02-05 17:05:03 +04:00
} ;
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun5i_a13_ahb_config = {
2015-03-19 20:19:03 +03:00
. pshift = 4 ,
. pwidth = 2 ,
} ;
2016-01-25 16:15:45 +03:00
static const struct clk_factors_config sun6i_ahb1_config = {
. mshift = 6 ,
. mwidth = 2 ,
. pshift = 4 ,
. pwidth = 2 ,
} ;
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun4i_apb1_config = {
2013-02-25 18:44:26 +04:00
. mshift = 0 ,
. mwidth = 5 ,
. pshift = 16 ,
. pwidth = 2 ,
} ;
2013-12-24 17:26:17 +04:00
/* user manual says "n" but it's really "p" */
2016-01-25 16:15:38 +03:00
static const struct clk_factors_config sun7i_a20_out_config = {
2013-12-24 17:26:17 +04:00
. mshift = 8 ,
. mwidth = 5 ,
. pshift = 20 ,
. pwidth = 2 ,
} ;
2013-08-12 13:14:06 +04:00
static const struct factors_data sun4i_pll1_data __initconst = {
2013-12-23 07:32:34 +04:00
. enable = 31 ,
2013-07-22 20:21:32 +04:00
. table = & sun4i_pll1_config ,
. getter = sun4i_get_pll1_factors ,
2013-02-25 18:44:26 +04:00
} ;
2013-08-12 13:14:06 +04:00
static const struct factors_data sun6i_a31_pll1_data __initconst = {
2013-12-23 07:32:34 +04:00
. enable = 31 ,
2013-07-24 01:34:10 +04:00
. table = & sun6i_a31_pll1_config ,
. getter = sun6i_a31_get_pll1_factors ,
} ;
2014-06-26 19:55:43 +04:00
static const struct factors_data sun8i_a23_pll1_data __initconst = {
. enable = 31 ,
. table = & sun8i_a23_pll1_config ,
. getter = sun8i_a23_get_pll1_factors ,
} ;
2014-03-19 22:19:30 +04:00
static const struct factors_data sun7i_a20_pll4_data __initconst = {
. enable = 31 ,
. table = & sun4i_pll5_config ,
. getter = sun4i_get_pll5_factors ,
} ;
2013-12-23 07:32:37 +04:00
static const struct factors_data sun4i_pll5_data __initconst = {
. enable = 31 ,
. table = & sun4i_pll5_config ,
. getter = sun4i_get_pll5_factors ,
} ;
2014-02-05 17:05:03 +04:00
static const struct factors_data sun6i_a31_pll6_data __initconst = {
. enable = 31 ,
. table = & sun6i_a31_pll6_config ,
. getter = sun6i_a31_get_pll6_factors ,
} ;
2015-03-19 20:19:03 +03:00
static const struct factors_data sun5i_a13_ahb_data __initconst = {
. mux = 6 ,
. muxmask = BIT ( 1 ) | BIT ( 0 ) ,
. table = & sun5i_a13_ahb_config ,
. getter = sun5i_a13_get_ahb_factors ,
} ;
2016-01-25 16:15:45 +03:00
static const struct factors_data sun6i_ahb1_data __initconst = {
. mux = 12 ,
. muxmask = BIT ( 1 ) | BIT ( 0 ) ,
. table = & sun6i_ahb1_config ,
. getter = sun6i_get_ahb1_factors ,
. recalc = sun6i_ahb1_recalc ,
} ;
2013-08-12 13:14:06 +04:00
static const struct factors_data sun4i_apb1_data __initconst = {
2014-11-06 06:40:29 +03:00
. mux = 24 ,
. muxmask = BIT ( 1 ) | BIT ( 0 ) ,
2013-07-22 20:21:32 +04:00
. table = & sun4i_apb1_config ,
. getter = sun4i_get_apb1_factors ,
2013-02-25 18:44:26 +04:00
} ;
2013-12-24 17:26:17 +04:00
static const struct factors_data sun7i_a20_out_data __initconst = {
. enable = 31 ,
. mux = 24 ,
2014-10-20 18:10:26 +04:00
. muxmask = BIT ( 1 ) | BIT ( 0 ) ,
2013-12-24 17:26:17 +04:00
. table = & sun7i_a20_out_config ,
. getter = sun7i_a20_get_out_factors ,
} ;
2013-12-23 07:32:36 +04:00
static struct clk * __init sunxi_factors_clk_setup ( struct device_node * node ,
2014-07-05 00:24:52 +04:00
const struct factors_data * data )
2013-02-25 18:44:26 +04:00
{
2014-11-23 16:38:07 +03:00
void __iomem * reg ;
reg = of_iomap ( node , 0 ) ;
if ( ! reg ) {
pr_err ( " Could not get registers for factors-clk: %s \n " ,
node - > name ) ;
return NULL ;
}
return sunxi_factors_register ( node , data , & clk_lock , reg ) ;
2013-02-25 18:44:26 +04:00
}
2016-02-02 11:07:22 +03:00
static void __init sun4i_pll1_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun4i_pll1_data ) ;
}
CLK_OF_DECLARE ( sun4i_pll1 , " allwinner,sun4i-a10-pll1-clk " ,
sun4i_pll1_clk_setup ) ;
static void __init sun6i_pll1_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun6i_a31_pll1_data ) ;
}
CLK_OF_DECLARE ( sun6i_pll1 , " allwinner,sun6i-a31-pll1-clk " ,
sun6i_pll1_clk_setup ) ;
static void __init sun8i_pll1_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun8i_a23_pll1_data ) ;
}
CLK_OF_DECLARE ( sun8i_pll1 , " allwinner,sun8i-a23-pll1-clk " ,
sun8i_pll1_clk_setup ) ;
static void __init sun7i_pll4_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun7i_a20_pll4_data ) ;
}
CLK_OF_DECLARE ( sun7i_pll4 , " allwinner,sun7i-a20-pll4-clk " ,
sun7i_pll4_clk_setup ) ;
static void __init sun5i_ahb_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun5i_a13_ahb_data ) ;
}
CLK_OF_DECLARE ( sun5i_ahb , " allwinner,sun5i-a13-ahb-clk " ,
sun5i_ahb_clk_setup ) ;
2016-01-25 16:15:45 +03:00
static void __init sun6i_ahb1_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun6i_ahb1_data ) ;
}
CLK_OF_DECLARE ( sun6i_a31_ahb1 , " allwinner,sun6i-a31-ahb1-clk " ,
sun6i_ahb1_clk_setup ) ;
2013-02-25 18:44:26 +04:00
2016-02-02 11:07:22 +03:00
static void __init sun4i_apb1_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun4i_apb1_data ) ;
}
CLK_OF_DECLARE ( sun4i_apb1 , " allwinner,sun4i-a10-apb1-clk " ,
sun4i_apb1_clk_setup ) ;
static void __init sun7i_out_clk_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun7i_a20_out_data ) ;
}
CLK_OF_DECLARE ( sun7i_out , " allwinner,sun7i-a20-out-clk " ,
sun7i_out_clk_setup ) ;
2013-02-25 18:44:26 +04:00
/**
* sunxi_mux_clk_setup ( ) - Setup function for muxes
*/
# define SUNXI_MUX_GATE_WIDTH 2
struct mux_data {
u8 shift ;
} ;
2013-08-12 13:14:06 +04:00
static const struct mux_data sun4i_cpu_mux_data __initconst = {
2013-02-25 18:44:26 +04:00
. shift = 16 ,
} ;
2013-08-12 13:14:06 +04:00
static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = {
2013-07-24 01:34:10 +04:00
. shift = 12 ,
} ;
2015-12-05 00:24:40 +03:00
static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = {
. shift = 0 ,
} ;
2016-02-02 11:47:10 +03:00
static struct clk * __init sunxi_mux_clk_setup ( struct device_node * node ,
2016-02-02 11:47:11 +03:00
const struct mux_data * data )
2013-02-25 18:44:26 +04:00
{
struct clk * clk ;
const char * clk_name = node - > name ;
2013-12-23 07:32:33 +04:00
const char * parents [ SUNXI_MAX_PARENTS ] ;
2014-07-28 07:49:42 +04:00
void __iomem * reg ;
2015-07-07 06:59:05 +03:00
int i ;
2013-02-25 18:44:26 +04:00
reg = of_iomap ( node , 0 ) ;
2016-02-16 13:46:06 +03:00
if ( ! reg ) {
pr_err ( " Could not map registers for mux-clk: %s \n " ,
of_node_full_name ( node ) ) ;
return NULL ;
}
2013-02-25 18:44:26 +04:00
2015-07-07 06:59:05 +03:00
i = of_clk_parent_fill ( node , parents , SUNXI_MAX_PARENTS ) ;
2016-02-01 20:39:27 +03:00
if ( of_property_read_string ( node , " clock-output-names " , & clk_name ) ) {
2016-02-16 13:46:06 +03:00
pr_err ( " %s: could not read clock-output-names from \" %s \" \n " ,
__func__ , of_node_full_name ( node ) ) ;
2016-02-01 20:39:27 +03:00
goto out_unmap ;
}
2014-02-03 05:51:37 +04:00
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , clk_name , parents , i ,
2015-01-06 05:35:12 +03:00
CLK_SET_RATE_PARENT , reg ,
2013-02-25 18:44:26 +04:00
data - > shift , SUNXI_MUX_GATE_WIDTH ,
0 , & clk_lock ) ;
2016-02-01 20:39:27 +03:00
if ( IS_ERR ( clk ) ) {
2016-02-16 13:46:06 +03:00
pr_err ( " %s: failed to register mux clock %s: %ld \n " , __func__ ,
clk_name , PTR_ERR ( clk ) ) ;
2016-02-01 20:39:27 +03:00
goto out_unmap ;
2013-02-25 18:44:26 +04:00
}
2016-02-01 20:39:27 +03:00
2016-02-16 13:46:06 +03:00
if ( of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ) {
pr_err ( " %s: failed to add clock provider for %s \n " ,
__func__ , clk_name ) ;
clk_unregister_divider ( clk ) ;
goto out_unmap ;
}
2016-02-02 11:47:10 +03:00
return clk ;
2016-02-01 20:39:27 +03:00
out_unmap :
iounmap ( reg ) ;
2016-02-02 11:47:10 +03:00
return NULL ;
2013-02-25 18:44:26 +04:00
}
2016-02-02 11:07:22 +03:00
static void __init sun4i_cpu_clk_setup ( struct device_node * node )
{
struct clk * clk ;
clk = sunxi_mux_clk_setup ( node , & sun4i_cpu_mux_data ) ;
if ( ! clk )
return ;
/* Protect CPU clock */
__clk_get ( clk ) ;
clk_prepare_enable ( clk ) ;
}
CLK_OF_DECLARE ( sun4i_cpu , " allwinner,sun4i-a10-cpu-clk " ,
sun4i_cpu_clk_setup ) ;
static void __init sun6i_ahb1_mux_clk_setup ( struct device_node * node )
{
sunxi_mux_clk_setup ( node , & sun6i_a31_ahb1_mux_data ) ;
}
CLK_OF_DECLARE ( sun6i_ahb1_mux , " allwinner,sun6i-a31-ahb1-mux-clk " ,
sun6i_ahb1_mux_clk_setup ) ;
static void __init sun8i_ahb2_clk_setup ( struct device_node * node )
{
sunxi_mux_clk_setup ( node , & sun8i_h3_ahb2_mux_data ) ;
}
CLK_OF_DECLARE ( sun8i_ahb2 , " allwinner,sun8i-h3-ahb2-clk " ,
sun8i_ahb2_clk_setup ) ;
2013-02-25 18:44:26 +04:00
/**
* sunxi_divider_clk_setup ( ) - Setup function for simple divider clocks
*/
struct div_data {
2013-07-23 11:25:56 +04:00
u8 shift ;
u8 pow ;
u8 width ;
2014-06-26 19:55:42 +04:00
const struct clk_div_table * table ;
2013-02-25 18:44:26 +04:00
} ;
2013-08-12 13:14:06 +04:00
static const struct div_data sun4i_axi_data __initconst = {
2013-07-23 11:25:56 +04:00
. shift = 0 ,
. pow = 0 ,
. width = 2 ,
2013-02-25 18:44:26 +04:00
} ;
2014-06-26 19:55:43 +04:00
static const struct clk_div_table sun8i_a23_axi_table [ ] __initconst = {
{ . val = 0 , . div = 1 } ,
{ . val = 1 , . div = 2 } ,
{ . val = 2 , . div = 3 } ,
{ . val = 3 , . div = 4 } ,
{ . val = 4 , . div = 4 } ,
{ . val = 5 , . div = 4 } ,
{ . val = 6 , . div = 4 } ,
{ . val = 7 , . div = 4 } ,
{ } /* sentinel */
} ;
static const struct div_data sun8i_a23_axi_data __initconst = {
. width = 3 ,
. table = sun8i_a23_axi_table ,
} ;
2013-08-12 13:14:06 +04:00
static const struct div_data sun4i_ahb_data __initconst = {
2013-07-23 11:25:56 +04:00
. shift = 4 ,
. pow = 1 ,
. width = 2 ,
2013-02-25 18:44:26 +04:00
} ;
2014-09-06 10:45:10 +04:00
static const struct clk_div_table sun4i_apb0_table [ ] __initconst = {
{ . val = 0 , . div = 2 } ,
{ . val = 1 , . div = 2 } ,
{ . val = 2 , . div = 4 } ,
{ . val = 3 , . div = 8 } ,
{ } /* sentinel */
} ;
2013-08-12 13:14:06 +04:00
static const struct div_data sun4i_apb0_data __initconst = {
2013-07-23 11:25:56 +04:00
. shift = 8 ,
. pow = 1 ,
. width = 2 ,
2014-09-06 10:45:10 +04:00
. table = sun4i_apb0_table ,
2013-02-25 18:44:26 +04:00
} ;
static void __init sunxi_divider_clk_setup ( struct device_node * node ,
2016-02-02 11:47:11 +03:00
const struct div_data * data )
2013-02-25 18:44:26 +04:00
{
struct clk * clk ;
const char * clk_name = node - > name ;
const char * clk_parent ;
2014-07-28 07:49:42 +04:00
void __iomem * reg ;
2013-02-25 18:44:26 +04:00
reg = of_iomap ( node , 0 ) ;
2016-02-16 13:46:07 +03:00
if ( ! reg ) {
pr_err ( " Could not map registers for mux-clk: %s \n " ,
of_node_full_name ( node ) ) ;
return ;
}
2013-02-25 18:44:26 +04:00
clk_parent = of_clk_get_parent_name ( node , 0 ) ;
2016-02-16 13:46:07 +03:00
if ( of_property_read_string ( node , " clock-output-names " , & clk_name ) ) {
pr_err ( " %s: could not read clock-output-names from \" %s \" \n " ,
__func__ , of_node_full_name ( node ) ) ;
goto out_unmap ;
}
2014-02-03 05:51:37 +04:00
2014-06-26 19:55:42 +04:00
clk = clk_register_divider_table ( NULL , clk_name , clk_parent , 0 ,
reg , data - > shift , data - > width ,
data - > pow ? CLK_DIVIDER_POWER_OF_TWO : 0 ,
data - > table , & clk_lock ) ;
2016-02-16 13:46:07 +03:00
if ( IS_ERR ( clk ) ) {
pr_err ( " %s: failed to register divider clock %s: %ld \n " ,
__func__ , clk_name , PTR_ERR ( clk ) ) ;
goto out_unmap ;
}
if ( of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ) {
pr_err ( " %s: failed to add clock provider for %s \n " ,
__func__ , clk_name ) ;
goto out_unregister ;
}
if ( clk_register_clkdev ( clk , clk_name , NULL ) ) {
of_clk_del_provider ( node ) ;
goto out_unregister ;
}
return ;
out_unregister :
clk_unregister_divider ( clk ) ;
out_unmap :
iounmap ( reg ) ;
2013-02-25 18:44:26 +04:00
}
2016-02-02 11:07:22 +03:00
static void __init sun4i_ahb_clk_setup ( struct device_node * node )
{
sunxi_divider_clk_setup ( node , & sun4i_ahb_data ) ;
}
CLK_OF_DECLARE ( sun4i_ahb , " allwinner,sun4i-a10-ahb-clk " ,
sun4i_ahb_clk_setup ) ;
static void __init sun4i_apb0_clk_setup ( struct device_node * node )
{
sunxi_divider_clk_setup ( node , & sun4i_apb0_data ) ;
}
CLK_OF_DECLARE ( sun4i_apb0 , " allwinner,sun4i-a10-apb0-clk " ,
sun4i_apb0_clk_setup ) ;
static void __init sun4i_axi_clk_setup ( struct device_node * node )
{
sunxi_divider_clk_setup ( node , & sun4i_axi_data ) ;
}
CLK_OF_DECLARE ( sun4i_axi , " allwinner,sun4i-a10-axi-clk " ,
sun4i_axi_clk_setup ) ;
static void __init sun8i_axi_clk_setup ( struct device_node * node )
{
sunxi_divider_clk_setup ( node , & sun8i_a23_axi_data ) ;
}
CLK_OF_DECLARE ( sun8i_axi , " allwinner,sun8i-a23-axi-clk " ,
sun8i_axi_clk_setup ) ;
2013-02-25 18:44:26 +04:00
2013-03-28 01:20:37 +04:00
/**
* sunxi_gates_clk_setup ( ) - Setup function for leaf gates on clocks
*/
# define SUNXI_GATES_MAX_SIZE 64
struct gates_data {
DECLARE_BITMAP ( mask , SUNXI_GATES_MAX_SIZE ) ;
} ;
2013-12-23 07:32:37 +04:00
/**
* sunxi_divs_clk_setup ( ) helper data
*/
2015-03-24 20:22:07 +03:00
# define SUNXI_DIVS_MAX_QTY 4
2013-12-23 07:32:37 +04:00
# define SUNXI_DIVISOR_WIDTH 2
struct divs_data {
const struct factors_data * factors ; /* data for the factor clock */
2015-03-24 20:22:07 +03:00
int ndivs ; /* number of outputs */
/*
* List of outputs . Refer to the diagram for sunxi_divs_clk_setup ( ) :
* self or base factor clock refers to the output from the pll
* itself . The remaining refer to fixed or configurable divider
* outputs .
*/
2013-12-23 07:32:37 +04:00
struct {
2015-03-24 20:22:07 +03:00
u8 self ; /* is it the base factor clock? (only one) */
2013-12-23 07:32:37 +04:00
u8 fixed ; /* is it a fixed divisor? if not... */
struct clk_div_table * table ; /* is it a table based divisor? */
u8 shift ; /* otherwise it's a normal divisor with this shift */
u8 pow ; /* is it power-of-two based? */
u8 gate ; /* is it independently gateable? */
} div [ SUNXI_DIVS_MAX_QTY ] ;
} ;
static struct clk_div_table pll6_sata_tbl [ ] = {
{ . val = 0 , . div = 6 , } ,
{ . val = 1 , . div = 12 , } ,
{ . val = 2 , . div = 18 , } ,
{ . val = 3 , . div = 24 , } ,
{ } /* sentinel */
} ;
static const struct divs_data pll5_divs_data __initconst = {
. factors = & sun4i_pll5_data ,
2014-11-12 21:08:30 +03:00
. ndivs = 2 ,
2013-12-23 07:32:37 +04:00
. div = {
{ . shift = 0 , . pow = 0 , } , /* M, DDR */
{ . shift = 16 , . pow = 1 , } , /* P, other */
2015-03-24 20:22:07 +03:00
/* No output for the base factor clock */
2013-12-23 07:32:37 +04:00
}
} ;
static const struct divs_data pll6_divs_data __initconst = {
2016-03-18 12:44:15 +03:00
. factors = & sun4i_pll5_data ,
2015-03-24 20:22:08 +03:00
. ndivs = 4 ,
2013-12-23 07:32:37 +04:00
. div = {
{ . shift = 0 , . table = pll6_sata_tbl , . gate = 14 } , /* M, SATA */
{ . fixed = 2 } , /* P, other */
2015-03-24 20:22:07 +03:00
{ . self = 1 } , /* base factor clock, 2x */
2015-03-24 20:22:08 +03:00
{ . fixed = 4 } , /* pll6 / 4, used as ahb input */
2013-12-23 07:32:37 +04:00
}
} ;
2014-11-12 21:08:31 +03:00
static const struct divs_data sun6i_a31_pll6_divs_data __initconst = {
. factors = & sun6i_a31_pll6_data ,
2015-03-24 20:22:07 +03:00
. ndivs = 2 ,
2014-11-12 21:08:31 +03:00
. div = {
{ . fixed = 2 } , /* normal output */
2015-03-24 20:22:07 +03:00
{ . self = 1 } , /* base factor clock, 2x */
2014-11-12 21:08:31 +03:00
}
} ;
2013-12-23 07:32:37 +04:00
/**
* sunxi_divs_clk_setup ( ) - Setup function for leaf divisors on clocks
*
* These clocks look something like this
* ________________________
* | ___divisor 1 - - - | - - - - > to consumer
* parent > - - | pll___ / ___divisor 2 - - - | - - - - > to consumer
* | \ _______________ | ____ > to consumer
* | ________________________ |
*/
2016-02-02 11:47:10 +03:00
static struct clk * * __init sunxi_divs_clk_setup ( struct device_node * node ,
2016-02-02 11:47:11 +03:00
const struct divs_data * data )
2013-12-23 07:32:37 +04:00
{
struct clk_onecell_data * clk_data ;
2014-02-03 05:51:40 +04:00
const char * parent ;
2013-12-23 07:32:37 +04:00
const char * clk_name ;
struct clk * * clks , * pclk ;
struct clk_hw * gate_hw , * rate_hw ;
const struct clk_ops * rate_ops ;
struct clk_gate * gate = NULL ;
struct clk_fixed_factor * fix_factor ;
struct clk_divider * divider ;
2016-03-18 12:44:15 +03:00
struct factors_data factors = * data - > factors ;
char * derived_name = NULL ;
2014-07-28 07:49:42 +04:00
void __iomem * reg ;
2014-11-12 21:08:30 +03:00
int ndivs = SUNXI_DIVS_MAX_QTY , i = 0 ;
2013-12-23 07:32:37 +04:00
int flags , clkflags ;
2015-03-24 20:22:07 +03:00
/* if number of children known, use it */
if ( data - > ndivs )
ndivs = data - > ndivs ;
2016-03-18 12:44:15 +03:00
/* Try to find a name for base factor clock */
for ( i = 0 ; i < ndivs ; i + + ) {
if ( data - > div [ i ] . self ) {
of_property_read_string_index ( node , " clock-output-names " ,
i , & factors . name ) ;
break ;
}
}
/* If we don't have a .self clk use the first output-name up to '_' */
if ( factors . name = = NULL ) {
char * endp ;
of_property_read_string_index ( node , " clock-output-names " ,
0 , & clk_name ) ;
endp = strchr ( clk_name , ' _ ' ) ;
if ( endp ) {
derived_name = kstrndup ( clk_name , endp - clk_name ,
GFP_KERNEL ) ;
factors . name = derived_name ;
} else {
factors . name = clk_name ;
}
}
2013-12-23 07:32:37 +04:00
/* Set up factor clock that we will be dividing */
2016-03-18 12:44:15 +03:00
pclk = sunxi_factors_clk_setup ( node , & factors ) ;
2016-02-16 13:46:08 +03:00
if ( ! pclk )
return NULL ;
2016-03-18 12:44:15 +03:00
2014-02-03 05:51:40 +04:00
parent = __clk_get_name ( pclk ) ;
2016-03-18 12:44:15 +03:00
kfree ( derived_name ) ;
2013-12-23 07:32:37 +04:00
reg = of_iomap ( node , 0 ) ;
2016-02-16 13:46:08 +03:00
if ( ! reg ) {
pr_err ( " Could not map registers for divs-clk: %s \n " ,
of_node_full_name ( node ) ) ;
return NULL ;
}
2013-12-23 07:32:37 +04:00
clk_data = kmalloc ( sizeof ( struct clk_onecell_data ) , GFP_KERNEL ) ;
if ( ! clk_data )
2016-02-16 13:46:08 +03:00
goto out_unmap ;
2013-12-23 07:32:37 +04:00
2015-03-24 20:22:07 +03:00
clks = kcalloc ( ndivs , sizeof ( * clks ) , GFP_KERNEL ) ;
2013-12-23 07:32:37 +04:00
if ( ! clks )
goto free_clkdata ;
clk_data - > clks = clks ;
/* It's not a good idea to have automatic reparenting changing
* our RAM clock ! */
clkflags = ! strcmp ( " pll5 " , parent ) ? 0 : CLK_SET_RATE_PARENT ;
2014-11-12 21:08:30 +03:00
for ( i = 0 ; i < ndivs ; i + + ) {
2013-12-23 07:32:37 +04:00
if ( of_property_read_string_index ( node , " clock-output-names " ,
i , & clk_name ) ! = 0 )
break ;
2015-03-24 20:22:07 +03:00
/* If this is the base factor clock, only update clks */
if ( data - > div [ i ] . self ) {
clk_data - > clks [ i ] = pclk ;
continue ;
}
2013-12-23 07:32:37 +04:00
gate_hw = NULL ;
rate_hw = NULL ;
rate_ops = NULL ;
/* If this leaf clock can be gated, create a gate */
if ( data - > div [ i ] . gate ) {
gate = kzalloc ( sizeof ( * gate ) , GFP_KERNEL ) ;
if ( ! gate )
goto free_clks ;
gate - > reg = reg ;
gate - > bit_idx = data - > div [ i ] . gate ;
gate - > lock = & clk_lock ;
gate_hw = & gate - > hw ;
}
/* Leaves can be fixed or configurable divisors */
if ( data - > div [ i ] . fixed ) {
fix_factor = kzalloc ( sizeof ( * fix_factor ) , GFP_KERNEL ) ;
if ( ! fix_factor )
goto free_gate ;
fix_factor - > mult = 1 ;
fix_factor - > div = data - > div [ i ] . fixed ;
rate_hw = & fix_factor - > hw ;
rate_ops = & clk_fixed_factor_ops ;
} else {
divider = kzalloc ( sizeof ( * divider ) , GFP_KERNEL ) ;
if ( ! divider )
goto free_gate ;
flags = data - > div [ i ] . pow ? CLK_DIVIDER_POWER_OF_TWO : 0 ;
divider - > reg = reg ;
divider - > shift = data - > div [ i ] . shift ;
divider - > width = SUNXI_DIVISOR_WIDTH ;
divider - > flags = flags ;
divider - > lock = & clk_lock ;
divider - > table = data - > div [ i ] . table ;
rate_hw = & divider - > hw ;
rate_ops = & clk_divider_ops ;
}
/* Wrap the (potential) gate and the divisor on a composite
* clock to unify them */
clks [ i ] = clk_register_composite ( NULL , clk_name , & parent , 1 ,
NULL , NULL ,
rate_hw , rate_ops ,
gate_hw , & clk_gate_ops ,
clkflags ) ;
WARN_ON ( IS_ERR ( clk_data - > clks [ i ] ) ) ;
}
/* Adjust to the real max */
clk_data - > clk_num = i ;
2016-02-16 13:46:08 +03:00
if ( of_clk_add_provider ( node , of_clk_src_onecell_get , clk_data ) ) {
pr_err ( " %s: failed to add clock provider for %s \n " ,
__func__ , clk_name ) ;
goto free_gate ;
}
2013-12-23 07:32:37 +04:00
2016-02-02 11:47:10 +03:00
return clks ;
2013-12-23 07:32:37 +04:00
free_gate :
kfree ( gate ) ;
free_clks :
kfree ( clks ) ;
free_clkdata :
kfree ( clk_data ) ;
2016-02-16 13:46:08 +03:00
out_unmap :
iounmap ( reg ) ;
2016-02-02 11:47:10 +03:00
return NULL ;
2013-12-23 07:32:37 +04:00
}
2016-02-02 11:07:22 +03:00
static void __init sun4i_pll5_clk_setup ( struct device_node * node )
{
struct clk * * clks ;
clks = sunxi_divs_clk_setup ( node , & pll5_divs_data ) ;
if ( ! clks )
return ;
/* Protect PLL5_DDR */
__clk_get ( clks [ 0 ] ) ;
clk_prepare_enable ( clks [ 0 ] ) ;
}
CLK_OF_DECLARE ( sun4i_pll5 , " allwinner,sun4i-a10-pll5-clk " ,
sun4i_pll5_clk_setup ) ;
static void __init sun4i_pll6_clk_setup ( struct device_node * node )
{
sunxi_divs_clk_setup ( node , & pll6_divs_data ) ;
}
CLK_OF_DECLARE ( sun4i_pll6 , " allwinner,sun4i-a10-pll6-clk " ,
sun4i_pll6_clk_setup ) ;
static void __init sun6i_pll6_clk_setup ( struct device_node * node )
{
sunxi_divs_clk_setup ( node , & sun6i_a31_pll6_divs_data ) ;
}
CLK_OF_DECLARE ( sun6i_pll6 , " allwinner,sun6i-a31-pll6-clk " ,
sun6i_pll6_clk_setup ) ;
2016-03-30 19:43:29 +03:00
/*
* sun6i display
*
* rate = parent_rate / ( m + 1 ) ;
*/
static void sun6i_display_factors ( struct factors_request * req )
{
u8 m ;
if ( req - > rate > req - > parent_rate )
req - > rate = req - > parent_rate ;
m = DIV_ROUND_UP ( req - > parent_rate , req - > rate ) ;
req - > rate = req - > parent_rate / m ;
req - > m = m - 1 ;
}
static const struct clk_factors_config sun6i_display_config = {
. mshift = 0 ,
. mwidth = 4 ,
} ;
static const struct factors_data sun6i_display_data __initconst = {
. enable = 31 ,
. mux = 24 ,
. muxmask = BIT ( 2 ) | BIT ( 1 ) | BIT ( 0 ) ,
. table = & sun6i_display_config ,
. getter = sun6i_display_factors ,
} ;
static void __init sun6i_display_setup ( struct device_node * node )
{
sunxi_factors_clk_setup ( node , & sun6i_display_data ) ;
}
CLK_OF_DECLARE ( sun6i_display , " allwinner,sun6i-a31-display-clk " ,
sun6i_display_setup ) ;