2019-05-29 16:57:50 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2011-01-07 22:36:15 -07:00
/*
* tegra_asoc_utils . c - Harmony machine ASoC driver
*
* Author : Stephen Warren < swarren @ nvidia . com >
2012-04-06 11:15:55 -06:00
* Copyright ( C ) 2010 , 2012 - NVIDIA , Inc .
2011-01-07 22:36:15 -07:00
*/
# include <linux/clk.h>
2011-01-28 14:26:40 -07:00
# include <linux/device.h>
2011-01-07 22:36:15 -07:00
# include <linux/err.h>
# include <linux/kernel.h>
2011-07-15 12:38:28 -04:00
# include <linux/module.h>
2012-04-06 11:15:55 -06:00
# include <linux/of.h>
2011-01-07 22:36:15 -07:00
# include "tegra_asoc_utils.h"
2011-01-28 14:26:40 -07:00
int tegra_asoc_utils_set_rate ( struct tegra_asoc_utils_data * data , int srate ,
2011-04-19 15:25:09 -06:00
int mclk )
2011-01-07 22:36:15 -07:00
{
int new_baseclock ;
2011-04-19 15:25:09 -06:00
bool clk_change ;
2011-01-07 22:36:15 -07:00
int err ;
switch ( srate ) {
case 11025 :
case 22050 :
case 44100 :
case 88200 :
2012-04-06 11:15:55 -06:00
if ( data - > soc = = TEGRA_ASOC_UTILS_SOC_TEGRA20 )
new_baseclock = 56448000 ;
2013-03-21 13:56:42 -06:00
else if ( data - > soc = = TEGRA_ASOC_UTILS_SOC_TEGRA30 )
2012-04-06 11:15:55 -06:00
new_baseclock = 564480000 ;
2013-03-21 13:56:42 -06:00
else
new_baseclock = 282240000 ;
2011-01-07 22:36:15 -07:00
break ;
case 8000 :
case 16000 :
case 32000 :
case 48000 :
case 64000 :
case 96000 :
2012-04-06 11:15:55 -06:00
if ( data - > soc = = TEGRA_ASOC_UTILS_SOC_TEGRA20 )
new_baseclock = 73728000 ;
2013-03-21 13:56:42 -06:00
else if ( data - > soc = = TEGRA_ASOC_UTILS_SOC_TEGRA30 )
2012-04-06 11:15:55 -06:00
new_baseclock = 552960000 ;
2013-03-21 13:56:42 -06:00
else
new_baseclock = 368640000 ;
2011-01-07 22:36:15 -07:00
break ;
default :
return - EINVAL ;
}
2011-04-19 15:25:09 -06:00
clk_change = ( ( new_baseclock ! = data - > set_baseclock ) | |
2011-01-28 14:26:40 -07:00
( mclk ! = data - > set_mclk ) ) ;
2011-04-19 15:25:09 -06:00
if ( ! clk_change )
return 0 ;
2011-01-07 22:36:15 -07:00
2011-01-28 14:26:40 -07:00
data - > set_baseclock = 0 ;
data - > set_mclk = 0 ;
2011-01-07 22:36:15 -07:00
2012-06-05 09:59:42 +05:30
clk_disable_unprepare ( data - > clk_cdev1 ) ;
2011-01-07 22:36:15 -07:00
2011-01-28 14:26:40 -07:00
err = clk_set_rate ( data - > clk_pll_a , new_baseclock ) ;
2011-01-07 22:36:15 -07:00
if ( err ) {
2011-01-28 14:26:40 -07:00
dev_err ( data - > dev , " Can't set pll_a rate: %d \n " , err ) ;
2011-01-07 22:36:15 -07:00
return err ;
}
2011-01-28 14:26:40 -07:00
err = clk_set_rate ( data - > clk_pll_a_out0 , mclk ) ;
2011-01-07 22:36:15 -07:00
if ( err ) {
2011-01-28 14:26:40 -07:00
dev_err ( data - > dev , " Can't set pll_a_out0 rate: %d \n " , err ) ;
2011-01-07 22:36:15 -07:00
return err ;
}
2012-04-06 11:15:55 -06:00
/* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
2011-01-07 22:36:15 -07:00
2012-06-05 09:59:42 +05:30
err = clk_prepare_enable ( data - > clk_cdev1 ) ;
2011-01-07 22:36:15 -07:00
if ( err ) {
2011-01-28 14:26:40 -07:00
dev_err ( data - > dev , " Can't enable cdev1: %d \n " , err ) ;
2011-01-07 22:36:15 -07:00
return err ;
}
2011-01-28 14:26:40 -07:00
data - > set_baseclock = new_baseclock ;
data - > set_mclk = mclk ;
2011-01-07 22:36:15 -07:00
return 0 ;
}
2011-02-22 17:23:56 -07:00
EXPORT_SYMBOL_GPL ( tegra_asoc_utils_set_rate ) ;
2011-01-07 22:36:15 -07:00
2012-12-20 00:17:33 +01:00
int tegra_asoc_utils_set_ac97_rate ( struct tegra_asoc_utils_data * data )
{
const int pll_rate = 73728000 ;
const int ac97_rate = 24576000 ;
int err ;
clk_disable_unprepare ( data - > clk_cdev1 ) ;
/*
* AC97 rate is fixed at 24.576 MHz and is used for both the host
* controller and the external codec
*/
err = clk_set_rate ( data - > clk_pll_a , pll_rate ) ;
if ( err ) {
dev_err ( data - > dev , " Can't set pll_a rate: %d \n " , err ) ;
return err ;
}
err = clk_set_rate ( data - > clk_pll_a_out0 , ac97_rate ) ;
if ( err ) {
dev_err ( data - > dev , " Can't set pll_a_out0 rate: %d \n " , err ) ;
return err ;
}
/* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
err = clk_prepare_enable ( data - > clk_cdev1 ) ;
if ( err ) {
dev_err ( data - > dev , " Can't enable cdev1: %d \n " , err ) ;
return err ;
}
data - > set_baseclock = pll_rate ;
data - > set_mclk = ac97_rate ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( tegra_asoc_utils_set_ac97_rate ) ;
2011-01-28 14:26:40 -07:00
int tegra_asoc_utils_init ( struct tegra_asoc_utils_data * data ,
struct device * dev )
2011-01-07 22:36:15 -07:00
{
2020-01-13 23:24:23 -08:00
struct clk * clk_out_1 , * clk_extern1 ;
2011-01-07 22:36:15 -07:00
int ret ;
2011-01-28 14:26:40 -07:00
data - > dev = dev ;
2012-04-10 13:11:17 -06:00
if ( of_machine_is_compatible ( " nvidia,tegra20 " ) )
2012-04-06 11:15:55 -06:00
data - > soc = TEGRA_ASOC_UTILS_SOC_TEGRA20 ;
else if ( of_machine_is_compatible ( " nvidia,tegra30 " ) )
data - > soc = TEGRA_ASOC_UTILS_SOC_TEGRA30 ;
2013-05-13 13:26:12 -06:00
else if ( of_machine_is_compatible ( " nvidia,tegra114 " ) )
2013-03-21 13:56:42 -06:00
data - > soc = TEGRA_ASOC_UTILS_SOC_TEGRA114 ;
2013-10-11 15:43:17 -06:00
else if ( of_machine_is_compatible ( " nvidia,tegra124 " ) )
data - > soc = TEGRA_ASOC_UTILS_SOC_TEGRA124 ;
2013-05-13 13:26:12 -06:00
else {
2013-03-21 13:56:42 -06:00
dev_err ( data - > dev , " SoC unknown to Tegra ASoC utils \n " ) ;
2012-04-06 11:15:55 -06:00
return - EINVAL ;
2013-03-21 13:56:42 -06:00
}
2012-04-06 11:15:55 -06:00
2020-01-13 23:24:17 -08:00
data - > clk_pll_a = devm_clk_get ( dev , " pll_a " ) ;
2011-01-28 14:26:40 -07:00
if ( IS_ERR ( data - > clk_pll_a ) ) {
dev_err ( data - > dev , " Can't retrieve clk pll_a \n " ) ;
2020-01-13 23:24:17 -08:00
return PTR_ERR ( data - > clk_pll_a ) ;
2011-01-07 22:36:15 -07:00
}
2020-01-13 23:24:17 -08:00
data - > clk_pll_a_out0 = devm_clk_get ( dev , " pll_a_out0 " ) ;
2011-01-28 14:26:40 -07:00
if ( IS_ERR ( data - > clk_pll_a_out0 ) ) {
dev_err ( data - > dev , " Can't retrieve clk pll_a_out0 \n " ) ;
2020-01-13 23:24:17 -08:00
return PTR_ERR ( data - > clk_pll_a_out0 ) ;
2011-01-07 22:36:15 -07:00
}
2020-01-13 23:24:17 -08:00
data - > clk_cdev1 = devm_clk_get ( dev , " mclk " ) ;
2011-01-28 14:26:40 -07:00
if ( IS_ERR ( data - > clk_cdev1 ) ) {
dev_err ( data - > dev , " Can't retrieve clk cdev1 \n " ) ;
2020-01-13 23:24:17 -08:00
return PTR_ERR ( data - > clk_cdev1 ) ;
2011-01-07 22:36:15 -07:00
}
2020-01-13 23:24:23 -08:00
/*
* If clock parents are not set in DT , configure here to use clk_out_1
* as mclk and extern1 as parent for Tegra30 and higher .
*/
if ( ! of_find_property ( dev - > of_node , " assigned-clock-parents " , NULL ) & &
data - > soc > TEGRA_ASOC_UTILS_SOC_TEGRA20 ) {
dev_warn ( data - > dev ,
" Configuring clocks for a legacy device-tree \n " ) ;
dev_warn ( data - > dev ,
" Please update DT to use assigned-clock-parents \n " ) ;
clk_extern1 = devm_clk_get ( dev , " extern1 " ) ;
if ( IS_ERR ( clk_extern1 ) ) {
dev_err ( data - > dev , " Can't retrieve clk extern1 \n " ) ;
return PTR_ERR ( clk_extern1 ) ;
}
ret = clk_set_parent ( clk_extern1 , data - > clk_pll_a_out0 ) ;
if ( ret < 0 ) {
dev_err ( data - > dev ,
" Set parent failed for clk extern1 \n " ) ;
return ret ;
}
clk_out_1 = devm_clk_get ( dev , " pmc_clk_out_1 " ) ;
if ( IS_ERR ( clk_out_1 ) ) {
dev_err ( data - > dev , " Can't retrieve pmc_clk_out_1 \n " ) ;
return PTR_ERR ( clk_out_1 ) ;
}
ret = clk_set_parent ( clk_out_1 , clk_extern1 ) ;
if ( ret < 0 ) {
dev_err ( data - > dev ,
" Set parent failed for pmc_clk_out_1 \n " ) ;
return ret ;
}
data - > clk_cdev1 = clk_out_1 ;
}
2020-01-13 23:24:24 -08:00
/*
* FIXME : There is some unknown dependency between audio mclk disable
* and suspend - resume functionality on Tegra30 , although audio mclk is
* only needed for audio .
*/
ret = clk_prepare_enable ( data - > clk_cdev1 ) ;
if ( ret ) {
dev_err ( data - > dev , " Can't enable cdev1: %d \n " , ret ) ;
2020-01-13 23:24:17 -08:00
return ret ;
2020-01-13 23:24:24 -08:00
}
2012-04-06 11:18:16 -06:00
2011-01-07 22:36:15 -07:00
return 0 ;
}
2011-02-22 17:23:56 -07:00
EXPORT_SYMBOL_GPL ( tegra_asoc_utils_init ) ;
2011-01-07 22:36:15 -07:00
2011-02-22 17:23:56 -07:00
MODULE_AUTHOR ( " Stephen Warren <swarren@nvidia.com> " ) ;
MODULE_DESCRIPTION ( " Tegra ASoC utility code " ) ;
MODULE_LICENSE ( " GPL " ) ;