2019-05-29 07:18:02 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-06-30 14:08:42 +08:00
/*
2022-08-01 14:37:34 +03:00
* Intel Atom SoC Power Management Controller Driver
* Copyright ( c ) 2014 - 2015 , 2017 , 2022 Intel Corporation .
2014-06-30 14:08:42 +08:00
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2017-01-23 12:07:43 -06:00
# include <linux/debugfs.h>
# include <linux/device.h>
2019-04-08 15:33:54 +02:00
# include <linux/dmi.h>
2014-06-30 14:08:42 +08:00
# include <linux/init.h>
2017-01-23 12:07:43 -06:00
# include <linux/io.h>
2017-01-23 12:07:44 -06:00
# include <linux/platform_data/x86/clk-pmc-atom.h>
2017-01-23 12:07:43 -06:00
# include <linux/platform_data/x86/pmc_atom.h>
2021-12-13 13:05:02 +01:00
# include <linux/platform_data/x86/simatic-ipc.h>
2017-01-23 12:07:44 -06:00
# include <linux/platform_device.h>
2014-06-30 14:08:42 +08:00
# include <linux/pci.h>
2014-06-30 14:10:33 +08:00
# include <linux/seq_file.h>
2014-06-30 14:08:42 +08:00
2015-07-06 17:29:02 +03:00
struct pmc_bit_map {
const char * name ;
u32 bit_mask ;
} ;
struct pmc_reg_map {
2015-07-06 17:29:03 +03:00
const struct pmc_bit_map * d3_sts_0 ;
const struct pmc_bit_map * d3_sts_1 ;
const struct pmc_bit_map * func_dis ;
const struct pmc_bit_map * func_dis_2 ;
2015-07-06 17:29:02 +03:00
const struct pmc_bit_map * pss ;
} ;
2017-01-23 12:07:44 -06:00
struct pmc_data {
const struct pmc_reg_map * map ;
const struct pmc_clk * clks ;
} ;
2014-06-30 14:09:38 +08:00
struct pmc_dev {
u32 base_addr ;
void __iomem * regmap ;
2015-07-06 17:29:02 +03:00
const struct pmc_reg_map * map ;
2014-06-30 14:10:33 +08:00
# ifdef CONFIG_DEBUG_FS
struct dentry * dbgfs_dir ;
# endif /* CONFIG_DEBUG_FS */
2015-07-06 17:29:00 +03:00
bool init ;
2014-06-30 14:09:38 +08:00
} ;
static struct pmc_dev pmc_device ;
2014-06-30 14:08:42 +08:00
static u32 acpi_base_addr ;
2017-01-23 12:07:44 -06:00
static const struct pmc_clk byt_clks [ ] = {
{
. name = " xtal " ,
. freq = 25000000 ,
. parent_name = NULL ,
} ,
{
. name = " pll " ,
. freq = 19200000 ,
. parent_name = " xtal " ,
} ,
2022-08-01 14:37:33 +03:00
{ }
2017-01-23 12:07:44 -06:00
} ;
static const struct pmc_clk cht_clks [ ] = {
{
. name = " xtal " ,
. freq = 19200000 ,
. parent_name = NULL ,
} ,
2022-08-01 14:37:33 +03:00
{ }
2017-01-23 12:07:44 -06:00
} ;
2015-07-06 17:29:03 +03:00
static const struct pmc_bit_map d3_sts_0_map [ ] = {
2015-07-06 17:29:01 +03:00
{ " LPSS1_F0_DMA " , BIT_LPSS1_F0_DMA } ,
{ " LPSS1_F1_PWM1 " , BIT_LPSS1_F1_PWM1 } ,
{ " LPSS1_F2_PWM2 " , BIT_LPSS1_F2_PWM2 } ,
{ " LPSS1_F3_HSUART1 " , BIT_LPSS1_F3_HSUART1 } ,
{ " LPSS1_F4_HSUART2 " , BIT_LPSS1_F4_HSUART2 } ,
{ " LPSS1_F5_SPI " , BIT_LPSS1_F5_SPI } ,
{ " LPSS1_F6_Reserved " , BIT_LPSS1_F6_XXX } ,
{ " LPSS1_F7_Reserved " , BIT_LPSS1_F7_XXX } ,
{ " SCC_EMMC " , BIT_SCC_EMMC } ,
{ " SCC_SDIO " , BIT_SCC_SDIO } ,
{ " SCC_SDCARD " , BIT_SCC_SDCARD } ,
{ " SCC_MIPI " , BIT_SCC_MIPI } ,
{ " HDA " , BIT_HDA } ,
{ " LPE " , BIT_LPE } ,
{ " OTG " , BIT_OTG } ,
{ " USH " , BIT_USH } ,
{ " GBE " , BIT_GBE } ,
{ " SATA " , BIT_SATA } ,
{ " USB_EHCI " , BIT_USB_EHCI } ,
{ " SEC " , BIT_SEC } ,
{ " PCIE_PORT0 " , BIT_PCIE_PORT0 } ,
{ " PCIE_PORT1 " , BIT_PCIE_PORT1 } ,
{ " PCIE_PORT2 " , BIT_PCIE_PORT2 } ,
{ " PCIE_PORT3 " , BIT_PCIE_PORT3 } ,
{ " LPSS2_F0_DMA " , BIT_LPSS2_F0_DMA } ,
{ " LPSS2_F1_I2C1 " , BIT_LPSS2_F1_I2C1 } ,
{ " LPSS2_F2_I2C2 " , BIT_LPSS2_F2_I2C2 } ,
{ " LPSS2_F3_I2C3 " , BIT_LPSS2_F3_I2C3 } ,
{ " LPSS2_F3_I2C4 " , BIT_LPSS2_F4_I2C4 } ,
{ " LPSS2_F5_I2C5 " , BIT_LPSS2_F5_I2C5 } ,
{ " LPSS2_F6_I2C6 " , BIT_LPSS2_F6_I2C6 } ,
{ " LPSS2_F7_I2C7 " , BIT_LPSS2_F7_I2C7 } ,
2022-08-01 14:37:33 +03:00
{ }
2015-07-06 17:29:03 +03:00
} ;
static struct pmc_bit_map byt_d3_sts_1_map [ ] = {
2015-07-06 17:29:01 +03:00
{ " SMB " , BIT_SMB } ,
{ " OTG_SS_PHY " , BIT_OTG_SS_PHY } ,
{ " USH_SS_PHY " , BIT_USH_SS_PHY } ,
{ " DFX " , BIT_DFX } ,
2022-08-01 14:37:33 +03:00
{ }
2014-06-30 14:10:33 +08:00
} ;
2015-07-06 17:29:03 +03:00
static struct pmc_bit_map cht_d3_sts_1_map [ ] = {
{ " SMB " , BIT_SMB } ,
{ " GMM " , BIT_STS_GMM } ,
{ " ISH " , BIT_STS_ISH } ,
2022-08-01 14:37:33 +03:00
{ }
2015-07-06 17:29:03 +03:00
} ;
static struct pmc_bit_map cht_func_dis_2_map [ ] = {
{ " SMB " , BIT_SMB } ,
{ " GMM " , BIT_FD_GMM } ,
{ " ISH " , BIT_FD_ISH } ,
2022-08-01 14:37:33 +03:00
{ }
2015-07-06 17:29:03 +03:00
} ;
static const struct pmc_bit_map byt_pss_map [ ] = {
2015-07-06 17:29:01 +03:00
{ " GBE " , PMC_PSS_BIT_GBE } ,
{ " SATA " , PMC_PSS_BIT_SATA } ,
{ " HDA " , PMC_PSS_BIT_HDA } ,
{ " SEC " , PMC_PSS_BIT_SEC } ,
{ " PCIE " , PMC_PSS_BIT_PCIE } ,
{ " LPSS " , PMC_PSS_BIT_LPSS } ,
{ " LPE " , PMC_PSS_BIT_LPE } ,
{ " DFX " , PMC_PSS_BIT_DFX } ,
{ " USH_CTRL " , PMC_PSS_BIT_USH_CTRL } ,
{ " USH_SUS " , PMC_PSS_BIT_USH_SUS } ,
{ " USH_VCCS " , PMC_PSS_BIT_USH_VCCS } ,
{ " USH_VCCA " , PMC_PSS_BIT_USH_VCCA } ,
{ " OTG_CTRL " , PMC_PSS_BIT_OTG_CTRL } ,
{ " OTG_VCCS " , PMC_PSS_BIT_OTG_VCCS } ,
{ " OTG_VCCA_CLK " , PMC_PSS_BIT_OTG_VCCA_CLK } ,
{ " OTG_VCCA " , PMC_PSS_BIT_OTG_VCCA } ,
{ " USB " , PMC_PSS_BIT_USB } ,
{ " USB_SUS " , PMC_PSS_BIT_USB_SUS } ,
2022-08-01 14:37:33 +03:00
{ }
2015-01-14 18:39:35 +02:00
} ;
2015-07-06 17:29:03 +03:00
static const struct pmc_bit_map cht_pss_map [ ] = {
{ " SATA " , PMC_PSS_BIT_SATA } ,
{ " HDA " , PMC_PSS_BIT_HDA } ,
{ " SEC " , PMC_PSS_BIT_SEC } ,
{ " PCIE " , PMC_PSS_BIT_PCIE } ,
{ " LPSS " , PMC_PSS_BIT_LPSS } ,
{ " LPE " , PMC_PSS_BIT_LPE } ,
{ " UFS " , PMC_PSS_BIT_CHT_UFS } ,
{ " UXD " , PMC_PSS_BIT_CHT_UXD } ,
{ " UXD_FD " , PMC_PSS_BIT_CHT_UXD_FD } ,
{ " UX_ENG " , PMC_PSS_BIT_CHT_UX_ENG } ,
{ " USB_SUS " , PMC_PSS_BIT_CHT_USB_SUS } ,
{ " GMM " , PMC_PSS_BIT_CHT_GMM } ,
{ " ISH " , PMC_PSS_BIT_CHT_ISH } ,
{ " DFX_MASTER " , PMC_PSS_BIT_CHT_DFX_MASTER } ,
{ " DFX_CLUSTER1 " , PMC_PSS_BIT_CHT_DFX_CLUSTER1 } ,
{ " DFX_CLUSTER2 " , PMC_PSS_BIT_CHT_DFX_CLUSTER2 } ,
{ " DFX_CLUSTER3 " , PMC_PSS_BIT_CHT_DFX_CLUSTER3 } ,
{ " DFX_CLUSTER4 " , PMC_PSS_BIT_CHT_DFX_CLUSTER4 } ,
{ " DFX_CLUSTER5 " , PMC_PSS_BIT_CHT_DFX_CLUSTER5 } ,
2022-08-01 14:37:33 +03:00
{ }
2015-07-06 17:29:03 +03:00
} ;
static const struct pmc_reg_map byt_reg_map = {
. d3_sts_0 = d3_sts_0_map ,
. d3_sts_1 = byt_d3_sts_1_map ,
. func_dis = d3_sts_0_map ,
. func_dis_2 = byt_d3_sts_1_map ,
. pss = byt_pss_map ,
} ;
static const struct pmc_reg_map cht_reg_map = {
. d3_sts_0 = d3_sts_0_map ,
. d3_sts_1 = cht_d3_sts_1_map ,
. func_dis = d3_sts_0_map ,
. func_dis_2 = cht_func_dis_2_map ,
. pss = cht_pss_map ,
2015-07-06 17:29:02 +03:00
} ;
2017-01-23 12:07:44 -06:00
static const struct pmc_data byt_data = {
. map = & byt_reg_map ,
. clks = byt_clks ,
} ;
static const struct pmc_data cht_data = {
. map = & cht_reg_map ,
. clks = cht_clks ,
} ;
2014-06-30 14:09:38 +08:00
static inline u32 pmc_reg_read ( struct pmc_dev * pmc , int reg_offset )
{
return readl ( pmc - > regmap + reg_offset ) ;
}
static inline void pmc_reg_write ( struct pmc_dev * pmc , int reg_offset , u32 val )
{
writel ( val , pmc - > regmap + reg_offset ) ;
}
2015-07-06 17:29:00 +03:00
int pmc_atom_read ( int offset , u32 * value )
{
struct pmc_dev * pmc = & pmc_device ;
if ( ! pmc - > init )
return - ENODEV ;
* value = pmc_reg_read ( pmc , offset ) ;
return 0 ;
}
2014-06-30 14:08:42 +08:00
static void pmc_power_off ( void )
{
u16 pm1_cnt_port ;
u32 pm1_cnt_value ;
pr_info ( " Preparing to enter system sleep state S5 \n " ) ;
pm1_cnt_port = acpi_base_addr + PM1_CNT ;
pm1_cnt_value = inl ( pm1_cnt_port ) ;
2022-08-01 14:37:31 +03:00
pm1_cnt_value & = ~ SLEEP_TYPE_MASK ;
2014-06-30 14:08:42 +08:00
pm1_cnt_value | = SLEEP_TYPE_S5 ;
pm1_cnt_value | = SLEEP_ENABLE ;
outl ( pm1_cnt_value , pm1_cnt_port ) ;
}
2014-06-30 14:09:38 +08:00
static void pmc_hw_reg_setup ( struct pmc_dev * pmc )
{
/*
* Disable PMC S0IX_WAKE_EN events coming from :
* - LPC clock run
* - GPIO_SUS ored dedicated IRQs
* - GPIO_SCORE ored dedicated IRQs
* - GPIO_SUS shared IRQ
* - GPIO_SCORE shared IRQ
*/
pmc_reg_write ( pmc , PMC_S0IX_WAKE_EN , ( u32 ) PMC_WAKE_EN_SETTING ) ;
}
2014-06-30 14:10:33 +08:00
# ifdef CONFIG_DEBUG_FS
2015-07-06 17:29:03 +03:00
static void pmc_dev_state_print ( struct seq_file * s , int reg_index ,
u32 sts , const struct pmc_bit_map * sts_map ,
u32 fd , const struct pmc_bit_map * fd_map )
{
int offset = PMC_REG_BIT_WIDTH * reg_index ;
int index ;
for ( index = 0 ; sts_map [ index ] . name ; index + + ) {
seq_printf ( s , " Dev: %-2d - %-32s \t State: %s [%s] \n " ,
offset + index , sts_map [ index ] . name ,
fd_map [ index ] . bit_mask & fd ? " Disabled " : " Enabled " ,
sts_map [ index ] . bit_mask & sts ? " D3 " : " D0 " ) ;
}
}
2014-06-30 14:10:33 +08:00
static int pmc_dev_state_show ( struct seq_file * s , void * unused )
{
struct pmc_dev * pmc = s - > private ;
2015-07-06 17:29:03 +03:00
const struct pmc_reg_map * m = pmc - > map ;
u32 func_dis , func_dis_2 ;
u32 d3_sts_0 , d3_sts_1 ;
2014-06-30 14:10:33 +08:00
func_dis = pmc_reg_read ( pmc , PMC_FUNC_DIS ) ;
func_dis_2 = pmc_reg_read ( pmc , PMC_FUNC_DIS_2 ) ;
d3_sts_0 = pmc_reg_read ( pmc , PMC_D3_STS_0 ) ;
d3_sts_1 = pmc_reg_read ( pmc , PMC_D3_STS_1 ) ;
2015-07-06 17:29:03 +03:00
/* Low part */
pmc_dev_state_print ( s , 0 , d3_sts_0 , m - > d3_sts_0 , func_dis , m - > func_dis ) ;
/* High part */
pmc_dev_state_print ( s , 1 , d3_sts_1 , m - > d3_sts_1 , func_dis_2 , m - > func_dis_2 ) ;
2014-06-30 14:10:33 +08:00
return 0 ;
}
2017-12-19 16:29:07 +02:00
DEFINE_SHOW_ATTRIBUTE ( pmc_dev_state ) ;
2014-06-30 14:10:33 +08:00
2015-01-14 18:39:35 +02:00
static int pmc_pss_state_show ( struct seq_file * s , void * unused )
{
struct pmc_dev * pmc = s - > private ;
2015-07-06 17:29:02 +03:00
const struct pmc_bit_map * map = pmc - > map - > pss ;
2015-01-14 18:39:35 +02:00
u32 pss = pmc_reg_read ( pmc , PMC_PSS ) ;
2015-07-06 17:29:02 +03:00
int index ;
2015-01-14 18:39:35 +02:00
2015-07-06 17:29:02 +03:00
for ( index = 0 ; map [ index ] . name ; index + + ) {
2015-07-06 17:29:01 +03:00
seq_printf ( s , " Island: %-2d - %-32s \t State: %s \n " ,
2015-07-06 17:29:02 +03:00
index , map [ index ] . name ,
map [ index ] . bit_mask & pss ? " Off " : " On " ) ;
2015-01-14 18:39:35 +02:00
}
return 0 ;
}
2017-12-19 16:29:07 +02:00
DEFINE_SHOW_ATTRIBUTE ( pmc_pss_state ) ;
2015-01-14 18:39:35 +02:00
2014-06-30 14:10:33 +08:00
static int pmc_sleep_tmr_show ( struct seq_file * s , void * unused )
{
struct pmc_dev * pmc = s - > private ;
u64 s0ir_tmr , s0i1_tmr , s0i2_tmr , s0i3_tmr , s0_tmr ;
2014-08-01 11:27:15 +03:00
s0ir_tmr = ( u64 ) pmc_reg_read ( pmc , PMC_S0IR_TMR ) < < PMC_TMR_SHIFT ;
s0i1_tmr = ( u64 ) pmc_reg_read ( pmc , PMC_S0I1_TMR ) < < PMC_TMR_SHIFT ;
s0i2_tmr = ( u64 ) pmc_reg_read ( pmc , PMC_S0I2_TMR ) < < PMC_TMR_SHIFT ;
s0i3_tmr = ( u64 ) pmc_reg_read ( pmc , PMC_S0I3_TMR ) < < PMC_TMR_SHIFT ;
s0_tmr = ( u64 ) pmc_reg_read ( pmc , PMC_S0_TMR ) < < PMC_TMR_SHIFT ;
2014-06-30 14:10:33 +08:00
seq_printf ( s , " S0IR Residency: \t %lldus \n " , s0ir_tmr ) ;
seq_printf ( s , " S0I1 Residency: \t %lldus \n " , s0i1_tmr ) ;
seq_printf ( s , " S0I2 Residency: \t %lldus \n " , s0i2_tmr ) ;
seq_printf ( s , " S0I3 Residency: \t %lldus \n " , s0i3_tmr ) ;
seq_printf ( s , " S0 Residency: \t %lldus \n " , s0_tmr ) ;
return 0 ;
}
2017-12-19 16:29:07 +02:00
DEFINE_SHOW_ATTRIBUTE ( pmc_sleep_tmr ) ;
2014-06-30 14:10:33 +08:00
2019-06-12 14:12:56 +02:00
static void pmc_dbgfs_register ( struct pmc_dev * pmc )
2014-06-30 14:10:33 +08:00
{
2019-06-12 14:12:56 +02:00
struct dentry * dir ;
2014-06-30 14:10:33 +08:00
dir = debugfs_create_dir ( " pmc_atom " , NULL ) ;
2015-01-14 18:39:31 +02:00
pmc - > dbgfs_dir = dir ;
2019-06-12 14:12:56 +02:00
debugfs_create_file ( " dev_state " , S_IFREG | S_IRUGO , dir , pmc ,
& pmc_dev_state_fops ) ;
debugfs_create_file ( " pss_state " , S_IFREG | S_IRUGO , dir , pmc ,
& pmc_pss_state_fops ) ;
debugfs_create_file ( " sleep_state " , S_IFREG | S_IRUGO , dir , pmc ,
& pmc_sleep_tmr_fops ) ;
2014-06-30 14:10:33 +08:00
}
2014-09-17 07:17:56 -07:00
# else
2019-06-12 14:12:56 +02:00
static void pmc_dbgfs_register ( struct pmc_dev * pmc )
2014-09-17 07:17:56 -07:00
{
}
2014-06-30 14:10:33 +08:00
# endif /* CONFIG_DEBUG_FS */
2021-12-13 13:05:02 +01:00
static bool pmc_clk_is_critical = true ;
static int dmi_callback ( const struct dmi_system_id * d )
{
2022-08-01 14:37:32 +03:00
pr_info ( " %s: PMC critical clocks quirk enabled \n " , d - > ident ) ;
2021-12-13 13:05:02 +01:00
return 1 ;
}
static int dmi_callback_siemens ( const struct dmi_system_id * d )
{
u32 st_id ;
if ( dmi_walk ( simatic_ipc_find_dmi_entry_helper , & st_id ) )
goto out ;
if ( st_id = = SIMATIC_IPC_IPC227E | | st_id = = SIMATIC_IPC_IPC277E )
return dmi_callback ( d ) ;
out :
pmc_clk_is_critical = false ;
return 1 ;
}
2019-04-08 15:33:54 +02:00
/*
* Some systems need one or more of their pmc_plt_clks to be
* marked as critical .
*/
2019-04-11 10:22:43 -07:00
static const struct dmi_system_id critclk_systems [ ] = {
2019-04-08 15:33:54 +02:00
{
2019-04-29 17:01:35 +02:00
/* pmc_plt_clk0 is used for an external HSIC USB HUB */
2019-04-08 15:33:54 +02:00
. ident = " MPL CEC1x " ,
2021-12-13 13:05:02 +01:00
. callback = dmi_callback ,
2019-04-08 15:33:54 +02:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " MPL AG " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " CEC10 Family " ) ,
} ,
} ,
2019-04-29 17:01:35 +02:00
{
2022-07-28 20:06:35 +02:00
/*
* Lex System / Lex Computech Co . makes a lot of Bay Trail
* based embedded boards which often come with multiple
* ethernet controllers using multiple pmc_plt_clks . See :
* https : //www.lex.com.tw/products/embedded-ipc-board/
*/
. ident = " Lex BayTrail " ,
2021-12-13 13:05:02 +01:00
. callback = dmi_callback ,
2019-04-29 17:01:35 +02:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Lex BayTrail " ) ,
2020-02-03 21:11:06 +01:00
} ,
} ,
2019-05-02 15:03:51 +02:00
{
/* pmc_plt_clk* - are used for ethernet controllers */
2021-04-12 15:30:06 +02:00
. ident = " Beckhoff Baytrail " ,
2021-12-13 13:05:02 +01:00
. callback = dmi_callback ,
2019-05-02 15:03:51 +02:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Beckhoff Automation " ) ,
2021-04-12 15:30:06 +02:00
DMI_MATCH ( DMI_PRODUCT_FAMILY , " CBxx63 " ) ,
2019-05-02 15:03:51 +02:00
} ,
} ,
2019-09-04 08:42:30 +02:00
{
2021-12-13 13:05:02 +01:00
. ident = " SIEMENS AG " ,
. callback = dmi_callback_siemens ,
2019-09-04 08:42:30 +02:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " SIEMENS AG " ) ,
2019-11-29 10:16:49 +01:00
} ,
} ,
2022-08-01 14:37:33 +03:00
{ }
2019-04-08 15:33:54 +02:00
} ;
2017-01-23 12:07:44 -06:00
static int pmc_setup_clks ( struct pci_dev * pdev , void __iomem * pmc_regmap ,
const struct pmc_data * pmc_data )
{
struct platform_device * clkdev ;
struct pmc_clk_data * clk_data ;
clk_data = kzalloc ( sizeof ( * clk_data ) , GFP_KERNEL ) ;
if ( ! clk_data )
return - ENOMEM ;
clk_data - > base = pmc_regmap ; /* offset is added by client */
clk_data - > clks = pmc_data - > clks ;
2021-12-13 13:05:02 +01:00
if ( dmi_check_system ( critclk_systems ) )
clk_data - > critical = pmc_clk_is_critical ;
2017-01-23 12:07:44 -06:00
clkdev = platform_device_register_data ( & pdev - > dev , " clk-pmc-atom " ,
PLATFORM_DEVID_NONE ,
clk_data , sizeof ( * clk_data ) ) ;
if ( IS_ERR ( clkdev ) ) {
kfree ( clk_data ) ;
return PTR_ERR ( clkdev ) ;
}
kfree ( clk_data ) ;
return 0 ;
}
2015-07-06 17:29:03 +03:00
static int pmc_setup_dev ( struct pci_dev * pdev , const struct pci_device_id * ent )
2014-06-30 14:08:42 +08:00
{
2014-06-30 14:09:38 +08:00
struct pmc_dev * pmc = & pmc_device ;
2017-01-23 12:07:44 -06:00
const struct pmc_data * data = ( struct pmc_data * ) ent - > driver_data ;
const struct pmc_reg_map * map = data - > map ;
2014-06-30 14:10:33 +08:00
int ret ;
2014-06-30 14:09:38 +08:00
2014-06-30 14:08:42 +08:00
/* Obtain ACPI base address */
pci_read_config_dword ( pdev , ACPI_BASE_ADDR_OFFSET , & acpi_base_addr ) ;
acpi_base_addr & = ACPI_BASE_ADDR_MASK ;
/* Install power off function */
if ( acpi_base_addr ! = 0 & & pm_power_off = = NULL )
pm_power_off = pmc_power_off ;
2014-06-30 14:09:38 +08:00
pci_read_config_dword ( pdev , PMC_BASE_ADDR_OFFSET , & pmc - > base_addr ) ;
pmc - > base_addr & = PMC_BASE_ADDR_MASK ;
2020-01-06 09:43:50 +01:00
pmc - > regmap = ioremap ( pmc - > base_addr , PMC_MMIO_REG_LEN ) ;
2014-06-30 14:09:38 +08:00
if ( ! pmc - > regmap ) {
dev_err ( & pdev - > dev , " error: ioremap failed \n " ) ;
return - ENOMEM ;
}
2015-07-06 17:29:02 +03:00
pmc - > map = map ;
2014-06-30 14:09:38 +08:00
/* PMC hardware registers setup */
pmc_hw_reg_setup ( pmc ) ;
2014-06-30 14:10:33 +08:00
2019-06-12 14:12:56 +02:00
pmc_dbgfs_register ( pmc ) ;
2014-09-17 07:17:56 -07:00
2017-01-23 12:07:44 -06:00
/* Register platform clocks - PMC_PLT_CLK [0..5] */
ret = pmc_setup_clks ( pdev , pmc - > regmap , data ) ;
if ( ret )
dev_warn ( & pdev - > dev , " platform clocks register failed: %d \n " ,
ret ) ;
2015-07-06 17:29:00 +03:00
pmc - > init = true ;
2014-09-17 07:17:56 -07:00
return ret ;
2014-06-30 14:08:42 +08:00
}
2022-08-01 14:37:34 +03:00
/* Data for PCI driver interface used by pci_match_id() call below */
2014-06-30 14:08:42 +08:00
static const struct pci_device_id pmc_pci_ids [ ] = {
2017-01-23 12:07:44 -06:00
{ PCI_VDEVICE ( INTEL , PCI_DEVICE_ID_VLV_PMC ) , ( kernel_ulong_t ) & byt_data } ,
{ PCI_VDEVICE ( INTEL , PCI_DEVICE_ID_CHT_PMC ) , ( kernel_ulong_t ) & cht_data } ,
2022-08-01 14:37:33 +03:00
{ }
2014-06-30 14:08:42 +08:00
} ;
static int __init pmc_atom_init ( void )
{
struct pci_dev * pdev = NULL ;
const struct pci_device_id * ent ;
2022-08-01 14:37:34 +03:00
/*
* We look for our device - PCU PMC .
* We assume that there is maximum one device .
2014-06-30 14:08:42 +08:00
*
* We can ' t use plain pci_driver mechanism ,
* as the device is really a multiple function device ,
* main driver that binds to the pci_device is lpc_ich
* and have to find & bind to the device this way .
*/
for_each_pci_dev ( pdev ) {
ent = pci_match_id ( pmc_pci_ids , pdev ) ;
2015-01-14 18:39:34 +02:00
if ( ent )
2015-07-06 17:29:03 +03:00
return pmc_setup_dev ( pdev , ent ) ;
2014-06-30 14:08:42 +08:00
}
2022-08-01 14:37:34 +03:00
/* Device not found */
2015-01-14 18:39:34 +02:00
return - ENODEV ;
2014-06-30 14:08:42 +08:00
}
2015-08-24 19:34:53 -04:00
device_initcall ( pmc_atom_init ) ;
2014-06-30 14:08:42 +08:00
2015-08-24 19:34:53 -04:00
/*
2014-06-30 14:08:42 +08:00
MODULE_AUTHOR ( " Aubrey Li <aubrey.li@linux.intel.com> " ) ;
2022-08-01 14:37:34 +03:00
MODULE_DESCRIPTION ( " Intel Atom SoC Power Management Controller Interface " ) ;
2014-06-30 14:08:42 +08:00
MODULE_LICENSE ( " GPL v2 " ) ;
2015-08-24 19:34:53 -04:00
*/