2018-05-09 12:59:00 +03:00
// SPDX-License-Identifier: MIT
/*
2021-12-12 21:05:23 +03:00
* clock framework for AMD FCH controller block
2018-05-09 12:59:00 +03:00
*
* Copyright 2018 Advanced Micro Devices , Inc .
*/
# include <linux/clk.h>
# include <linux/clkdev.h>
# include <linux/clk-provider.h>
2021-12-12 21:05:23 +03:00
# include <linux/pci.h>
2020-07-31 16:36:01 +03:00
# include <linux/platform_data/clk-fch.h>
2018-05-09 12:59:00 +03:00
# include <linux/platform_device.h>
/* Clock Driving Strength 2 register */
# define CLKDRVSTR2 0x28
/* Clock Control 1 register */
# define MISCCLKCNTL1 0x40
/* Auxiliary clock1 enable bit */
# define OSCCLKENB 2
/* 25Mhz auxiliary output clock freq bit */
# define OSCOUT1CLK25MHZ 16
# define ST_CLK_48M 0
# define ST_CLK_25M 1
# define ST_CLK_MUX 2
# define ST_CLK_GATE 3
# define ST_MAX_CLKS 4
2021-12-12 21:05:23 +03:00
# define CLK_48M_FIXED 0
# define CLK_GATE_FIXED 1
# define CLK_MAX_FIXED 2
/* List of supported CPU ids for clk mux with 25Mhz clk support */
# define AMD_CPU_ID_ST 0x1576
2020-07-31 16:36:04 +03:00
2018-05-09 12:59:00 +03:00
static const char * const clk_oscout1_parents [ ] = { " clk48MHz " , " clk25MHz " } ;
static struct clk_hw * hws [ ST_MAX_CLKS ] ;
2021-12-12 21:05:23 +03:00
static const struct pci_device_id fch_pci_ids [ ] = {
{ PCI_DEVICE ( PCI_VENDOR_ID_AMD , AMD_CPU_ID_ST ) } ,
{ }
} ;
2020-07-31 16:36:02 +03:00
static int fch_clk_probe ( struct platform_device * pdev )
2018-05-09 12:59:00 +03:00
{
2020-07-31 16:36:02 +03:00
struct fch_clk_data * fch_data ;
2021-12-12 21:05:23 +03:00
struct pci_dev * rdev ;
2018-05-09 12:59:00 +03:00
2020-07-31 16:36:02 +03:00
fch_data = dev_get_platdata ( & pdev - > dev ) ;
if ( ! fch_data | | ! fch_data - > base )
2018-05-09 12:59:00 +03:00
return - EINVAL ;
2021-12-12 21:05:23 +03:00
rdev = pci_get_domain_bus_and_slot ( 0 , 0 , PCI_DEVFN ( 0 , 0 ) ) ;
if ( ! rdev ) {
dev_err ( & pdev - > dev , " FCH device not found \n " ) ;
return - ENODEV ;
}
if ( pci_match_id ( fch_pci_ids , rdev ) ) {
2020-07-31 16:36:04 +03:00
hws [ ST_CLK_48M ] = clk_hw_register_fixed_rate ( NULL , " clk48MHz " ,
NULL , 0 , 48000000 ) ;
hws [ ST_CLK_25M ] = clk_hw_register_fixed_rate ( NULL , " clk25MHz " ,
NULL , 0 , 25000000 ) ;
hws [ ST_CLK_MUX ] = clk_hw_register_mux ( NULL , " oscout1_mux " ,
clk_oscout1_parents , ARRAY_SIZE ( clk_oscout1_parents ) ,
0 , fch_data - > base + CLKDRVSTR2 , OSCOUT1CLK25MHZ , 3 , 0 ,
NULL ) ;
2018-05-09 12:59:00 +03:00
2020-07-31 16:36:04 +03:00
clk_set_parent ( hws [ ST_CLK_MUX ] - > clk , hws [ ST_CLK_48M ] - > clk ) ;
2018-05-09 12:59:00 +03:00
2020-07-31 16:36:04 +03:00
hws [ ST_CLK_GATE ] = clk_hw_register_gate ( NULL , " oscout1 " ,
" oscout1_mux " , 0 , fch_data - > base + MISCCLKCNTL1 ,
OSCCLKENB , CLK_GATE_SET_TO_DISABLE , NULL ) ;
2018-05-09 12:59:00 +03:00
2020-07-31 16:36:04 +03:00
devm_clk_hw_register_clkdev ( & pdev - > dev , hws [ ST_CLK_GATE ] ,
2021-12-12 21:05:26 +03:00
fch_data - > name , NULL ) ;
2020-07-31 16:36:04 +03:00
} else {
2021-12-12 21:05:23 +03:00
hws [ CLK_48M_FIXED ] = clk_hw_register_fixed_rate ( NULL , " clk48MHz " ,
2020-07-31 16:36:04 +03:00
NULL , 0 , 48000000 ) ;
2018-05-09 12:59:00 +03:00
2021-12-12 21:05:23 +03:00
hws [ CLK_GATE_FIXED ] = clk_hw_register_gate ( NULL , " oscout1 " ,
2020-07-31 16:36:04 +03:00
" clk48MHz " , 0 , fch_data - > base + MISCCLKCNTL1 ,
2021-12-12 21:05:27 +03:00
OSCCLKENB , 0 , NULL ) ;
2020-07-31 16:36:04 +03:00
2021-12-12 21:05:23 +03:00
devm_clk_hw_register_clkdev ( & pdev - > dev , hws [ CLK_GATE_FIXED ] ,
2021-12-12 21:05:26 +03:00
fch_data - > name , NULL ) ;
2020-07-31 16:36:04 +03:00
}
2018-05-09 12:59:00 +03:00
2021-12-12 21:05:23 +03:00
pci_dev_put ( rdev ) ;
2018-05-09 12:59:00 +03:00
return 0 ;
}
2020-07-31 16:36:02 +03:00
static int fch_clk_remove ( struct platform_device * pdev )
2018-05-09 12:59:00 +03:00
{
2020-07-31 16:36:04 +03:00
int i , clks ;
2021-12-12 21:05:23 +03:00
struct pci_dev * rdev ;
2018-05-09 12:59:00 +03:00
2021-12-12 21:05:23 +03:00
rdev = pci_get_domain_bus_and_slot ( 0 , 0 , PCI_DEVFN ( 0 , 0 ) ) ;
if ( ! rdev )
return - ENODEV ;
2020-07-31 16:36:04 +03:00
2021-12-12 21:05:23 +03:00
clks = pci_match_id ( fch_pci_ids , rdev ) ? CLK_MAX_FIXED : ST_MAX_CLKS ;
2020-07-31 16:36:04 +03:00
for ( i = 0 ; i < clks ; i + + )
2018-05-09 12:59:00 +03:00
clk_hw_unregister ( hws [ i ] ) ;
2020-07-31 16:36:04 +03:00
2021-12-12 21:05:23 +03:00
pci_dev_put ( rdev ) ;
2018-05-09 12:59:00 +03:00
return 0 ;
}
2020-07-31 16:36:02 +03:00
static struct platform_driver fch_clk_driver = {
2018-05-09 12:59:00 +03:00
. driver = {
2020-07-31 16:36:02 +03:00
. name = " clk-fch " ,
2018-05-09 12:59:00 +03:00
. suppress_bind_attrs = true ,
} ,
2020-07-31 16:36:02 +03:00
. probe = fch_clk_probe ,
. remove = fch_clk_remove ,
2018-05-09 12:59:00 +03:00
} ;
2020-07-31 16:36:02 +03:00
builtin_platform_driver ( fch_clk_driver ) ;