18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Intel Atom SOC Power Management Controller Driver
48c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
108c2ecf20Sopenharmony_ci#include <linux/device.h>
118c2ecf20Sopenharmony_ci#include <linux/dmi.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/clk-pmc-atom.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/pmc_atom.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/pci.h>
188c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct pmc_bit_map {
218c2ecf20Sopenharmony_ci	const char *name;
228c2ecf20Sopenharmony_ci	u32 bit_mask;
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct pmc_reg_map {
268c2ecf20Sopenharmony_ci	const struct pmc_bit_map *d3_sts_0;
278c2ecf20Sopenharmony_ci	const struct pmc_bit_map *d3_sts_1;
288c2ecf20Sopenharmony_ci	const struct pmc_bit_map *func_dis;
298c2ecf20Sopenharmony_ci	const struct pmc_bit_map *func_dis_2;
308c2ecf20Sopenharmony_ci	const struct pmc_bit_map *pss;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct pmc_data {
348c2ecf20Sopenharmony_ci	const struct pmc_reg_map *map;
358c2ecf20Sopenharmony_ci	const struct pmc_clk *clks;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct pmc_dev {
398c2ecf20Sopenharmony_ci	u32 base_addr;
408c2ecf20Sopenharmony_ci	void __iomem *regmap;
418c2ecf20Sopenharmony_ci	const struct pmc_reg_map *map;
428c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
438c2ecf20Sopenharmony_ci	struct dentry *dbgfs_dir;
448c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
458c2ecf20Sopenharmony_ci	bool init;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic struct pmc_dev pmc_device;
498c2ecf20Sopenharmony_cistatic u32 acpi_base_addr;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const struct pmc_clk byt_clks[] = {
528c2ecf20Sopenharmony_ci	{
538c2ecf20Sopenharmony_ci		.name = "xtal",
548c2ecf20Sopenharmony_ci		.freq = 25000000,
558c2ecf20Sopenharmony_ci		.parent_name = NULL,
568c2ecf20Sopenharmony_ci	},
578c2ecf20Sopenharmony_ci	{
588c2ecf20Sopenharmony_ci		.name = "pll",
598c2ecf20Sopenharmony_ci		.freq = 19200000,
608c2ecf20Sopenharmony_ci		.parent_name = "xtal",
618c2ecf20Sopenharmony_ci	},
628c2ecf20Sopenharmony_ci	{},
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const struct pmc_clk cht_clks[] = {
668c2ecf20Sopenharmony_ci	{
678c2ecf20Sopenharmony_ci		.name = "xtal",
688c2ecf20Sopenharmony_ci		.freq = 19200000,
698c2ecf20Sopenharmony_ci		.parent_name = NULL,
708c2ecf20Sopenharmony_ci	},
718c2ecf20Sopenharmony_ci	{},
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic const struct pmc_bit_map d3_sts_0_map[] = {
758c2ecf20Sopenharmony_ci	{"LPSS1_F0_DMA",	BIT_LPSS1_F0_DMA},
768c2ecf20Sopenharmony_ci	{"LPSS1_F1_PWM1",	BIT_LPSS1_F1_PWM1},
778c2ecf20Sopenharmony_ci	{"LPSS1_F2_PWM2",	BIT_LPSS1_F2_PWM2},
788c2ecf20Sopenharmony_ci	{"LPSS1_F3_HSUART1",	BIT_LPSS1_F3_HSUART1},
798c2ecf20Sopenharmony_ci	{"LPSS1_F4_HSUART2",	BIT_LPSS1_F4_HSUART2},
808c2ecf20Sopenharmony_ci	{"LPSS1_F5_SPI",	BIT_LPSS1_F5_SPI},
818c2ecf20Sopenharmony_ci	{"LPSS1_F6_Reserved",	BIT_LPSS1_F6_XXX},
828c2ecf20Sopenharmony_ci	{"LPSS1_F7_Reserved",	BIT_LPSS1_F7_XXX},
838c2ecf20Sopenharmony_ci	{"SCC_EMMC",		BIT_SCC_EMMC},
848c2ecf20Sopenharmony_ci	{"SCC_SDIO",		BIT_SCC_SDIO},
858c2ecf20Sopenharmony_ci	{"SCC_SDCARD",		BIT_SCC_SDCARD},
868c2ecf20Sopenharmony_ci	{"SCC_MIPI",		BIT_SCC_MIPI},
878c2ecf20Sopenharmony_ci	{"HDA",			BIT_HDA},
888c2ecf20Sopenharmony_ci	{"LPE",			BIT_LPE},
898c2ecf20Sopenharmony_ci	{"OTG",			BIT_OTG},
908c2ecf20Sopenharmony_ci	{"USH",			BIT_USH},
918c2ecf20Sopenharmony_ci	{"GBE",			BIT_GBE},
928c2ecf20Sopenharmony_ci	{"SATA",		BIT_SATA},
938c2ecf20Sopenharmony_ci	{"USB_EHCI",		BIT_USB_EHCI},
948c2ecf20Sopenharmony_ci	{"SEC",			BIT_SEC},
958c2ecf20Sopenharmony_ci	{"PCIE_PORT0",		BIT_PCIE_PORT0},
968c2ecf20Sopenharmony_ci	{"PCIE_PORT1",		BIT_PCIE_PORT1},
978c2ecf20Sopenharmony_ci	{"PCIE_PORT2",		BIT_PCIE_PORT2},
988c2ecf20Sopenharmony_ci	{"PCIE_PORT3",		BIT_PCIE_PORT3},
998c2ecf20Sopenharmony_ci	{"LPSS2_F0_DMA",	BIT_LPSS2_F0_DMA},
1008c2ecf20Sopenharmony_ci	{"LPSS2_F1_I2C1",	BIT_LPSS2_F1_I2C1},
1018c2ecf20Sopenharmony_ci	{"LPSS2_F2_I2C2",	BIT_LPSS2_F2_I2C2},
1028c2ecf20Sopenharmony_ci	{"LPSS2_F3_I2C3",	BIT_LPSS2_F3_I2C3},
1038c2ecf20Sopenharmony_ci	{"LPSS2_F3_I2C4",	BIT_LPSS2_F4_I2C4},
1048c2ecf20Sopenharmony_ci	{"LPSS2_F5_I2C5",	BIT_LPSS2_F5_I2C5},
1058c2ecf20Sopenharmony_ci	{"LPSS2_F6_I2C6",	BIT_LPSS2_F6_I2C6},
1068c2ecf20Sopenharmony_ci	{"LPSS2_F7_I2C7",	BIT_LPSS2_F7_I2C7},
1078c2ecf20Sopenharmony_ci	{},
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic struct pmc_bit_map byt_d3_sts_1_map[] = {
1118c2ecf20Sopenharmony_ci	{"SMB",			BIT_SMB},
1128c2ecf20Sopenharmony_ci	{"OTG_SS_PHY",		BIT_OTG_SS_PHY},
1138c2ecf20Sopenharmony_ci	{"USH_SS_PHY",		BIT_USH_SS_PHY},
1148c2ecf20Sopenharmony_ci	{"DFX",			BIT_DFX},
1158c2ecf20Sopenharmony_ci	{},
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic struct pmc_bit_map cht_d3_sts_1_map[] = {
1198c2ecf20Sopenharmony_ci	{"SMB",			BIT_SMB},
1208c2ecf20Sopenharmony_ci	{"GMM",			BIT_STS_GMM},
1218c2ecf20Sopenharmony_ci	{"ISH",			BIT_STS_ISH},
1228c2ecf20Sopenharmony_ci	{},
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic struct pmc_bit_map cht_func_dis_2_map[] = {
1268c2ecf20Sopenharmony_ci	{"SMB",			BIT_SMB},
1278c2ecf20Sopenharmony_ci	{"GMM",			BIT_FD_GMM},
1288c2ecf20Sopenharmony_ci	{"ISH",			BIT_FD_ISH},
1298c2ecf20Sopenharmony_ci	{},
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic const struct pmc_bit_map byt_pss_map[] = {
1338c2ecf20Sopenharmony_ci	{"GBE",			PMC_PSS_BIT_GBE},
1348c2ecf20Sopenharmony_ci	{"SATA",		PMC_PSS_BIT_SATA},
1358c2ecf20Sopenharmony_ci	{"HDA",			PMC_PSS_BIT_HDA},
1368c2ecf20Sopenharmony_ci	{"SEC",			PMC_PSS_BIT_SEC},
1378c2ecf20Sopenharmony_ci	{"PCIE",		PMC_PSS_BIT_PCIE},
1388c2ecf20Sopenharmony_ci	{"LPSS",		PMC_PSS_BIT_LPSS},
1398c2ecf20Sopenharmony_ci	{"LPE",			PMC_PSS_BIT_LPE},
1408c2ecf20Sopenharmony_ci	{"DFX",			PMC_PSS_BIT_DFX},
1418c2ecf20Sopenharmony_ci	{"USH_CTRL",		PMC_PSS_BIT_USH_CTRL},
1428c2ecf20Sopenharmony_ci	{"USH_SUS",		PMC_PSS_BIT_USH_SUS},
1438c2ecf20Sopenharmony_ci	{"USH_VCCS",		PMC_PSS_BIT_USH_VCCS},
1448c2ecf20Sopenharmony_ci	{"USH_VCCA",		PMC_PSS_BIT_USH_VCCA},
1458c2ecf20Sopenharmony_ci	{"OTG_CTRL",		PMC_PSS_BIT_OTG_CTRL},
1468c2ecf20Sopenharmony_ci	{"OTG_VCCS",		PMC_PSS_BIT_OTG_VCCS},
1478c2ecf20Sopenharmony_ci	{"OTG_VCCA_CLK",	PMC_PSS_BIT_OTG_VCCA_CLK},
1488c2ecf20Sopenharmony_ci	{"OTG_VCCA",		PMC_PSS_BIT_OTG_VCCA},
1498c2ecf20Sopenharmony_ci	{"USB",			PMC_PSS_BIT_USB},
1508c2ecf20Sopenharmony_ci	{"USB_SUS",		PMC_PSS_BIT_USB_SUS},
1518c2ecf20Sopenharmony_ci	{},
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic const struct pmc_bit_map cht_pss_map[] = {
1558c2ecf20Sopenharmony_ci	{"SATA",		PMC_PSS_BIT_SATA},
1568c2ecf20Sopenharmony_ci	{"HDA",			PMC_PSS_BIT_HDA},
1578c2ecf20Sopenharmony_ci	{"SEC",			PMC_PSS_BIT_SEC},
1588c2ecf20Sopenharmony_ci	{"PCIE",		PMC_PSS_BIT_PCIE},
1598c2ecf20Sopenharmony_ci	{"LPSS",		PMC_PSS_BIT_LPSS},
1608c2ecf20Sopenharmony_ci	{"LPE",			PMC_PSS_BIT_LPE},
1618c2ecf20Sopenharmony_ci	{"UFS",			PMC_PSS_BIT_CHT_UFS},
1628c2ecf20Sopenharmony_ci	{"UXD",			PMC_PSS_BIT_CHT_UXD},
1638c2ecf20Sopenharmony_ci	{"UXD_FD",		PMC_PSS_BIT_CHT_UXD_FD},
1648c2ecf20Sopenharmony_ci	{"UX_ENG",		PMC_PSS_BIT_CHT_UX_ENG},
1658c2ecf20Sopenharmony_ci	{"USB_SUS",		PMC_PSS_BIT_CHT_USB_SUS},
1668c2ecf20Sopenharmony_ci	{"GMM",			PMC_PSS_BIT_CHT_GMM},
1678c2ecf20Sopenharmony_ci	{"ISH",			PMC_PSS_BIT_CHT_ISH},
1688c2ecf20Sopenharmony_ci	{"DFX_MASTER",		PMC_PSS_BIT_CHT_DFX_MASTER},
1698c2ecf20Sopenharmony_ci	{"DFX_CLUSTER1",	PMC_PSS_BIT_CHT_DFX_CLUSTER1},
1708c2ecf20Sopenharmony_ci	{"DFX_CLUSTER2",	PMC_PSS_BIT_CHT_DFX_CLUSTER2},
1718c2ecf20Sopenharmony_ci	{"DFX_CLUSTER3",	PMC_PSS_BIT_CHT_DFX_CLUSTER3},
1728c2ecf20Sopenharmony_ci	{"DFX_CLUSTER4",	PMC_PSS_BIT_CHT_DFX_CLUSTER4},
1738c2ecf20Sopenharmony_ci	{"DFX_CLUSTER5",	PMC_PSS_BIT_CHT_DFX_CLUSTER5},
1748c2ecf20Sopenharmony_ci	{},
1758c2ecf20Sopenharmony_ci};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic const struct pmc_reg_map byt_reg_map = {
1788c2ecf20Sopenharmony_ci	.d3_sts_0	= d3_sts_0_map,
1798c2ecf20Sopenharmony_ci	.d3_sts_1	= byt_d3_sts_1_map,
1808c2ecf20Sopenharmony_ci	.func_dis	= d3_sts_0_map,
1818c2ecf20Sopenharmony_ci	.func_dis_2	= byt_d3_sts_1_map,
1828c2ecf20Sopenharmony_ci	.pss		= byt_pss_map,
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic const struct pmc_reg_map cht_reg_map = {
1868c2ecf20Sopenharmony_ci	.d3_sts_0	= d3_sts_0_map,
1878c2ecf20Sopenharmony_ci	.d3_sts_1	= cht_d3_sts_1_map,
1888c2ecf20Sopenharmony_ci	.func_dis	= d3_sts_0_map,
1898c2ecf20Sopenharmony_ci	.func_dis_2	= cht_func_dis_2_map,
1908c2ecf20Sopenharmony_ci	.pss		= cht_pss_map,
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic const struct pmc_data byt_data = {
1948c2ecf20Sopenharmony_ci	.map = &byt_reg_map,
1958c2ecf20Sopenharmony_ci	.clks = byt_clks,
1968c2ecf20Sopenharmony_ci};
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic const struct pmc_data cht_data = {
1998c2ecf20Sopenharmony_ci	.map = &cht_reg_map,
2008c2ecf20Sopenharmony_ci	.clks = cht_clks,
2018c2ecf20Sopenharmony_ci};
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	return readl(pmc->regmap + reg_offset);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic inline void pmc_reg_write(struct pmc_dev *pmc, int reg_offset, u32 val)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	writel(val, pmc->regmap + reg_offset);
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ciint pmc_atom_read(int offset, u32 *value)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct pmc_dev *pmc = &pmc_device;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (!pmc->init)
2188c2ecf20Sopenharmony_ci		return -ENODEV;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	*value = pmc_reg_read(pmc, offset);
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pmc_atom_read);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ciint pmc_atom_write(int offset, u32 value)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	struct pmc_dev *pmc = &pmc_device;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (!pmc->init)
2308c2ecf20Sopenharmony_ci		return -ENODEV;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	pmc_reg_write(pmc, offset, value);
2338c2ecf20Sopenharmony_ci	return 0;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pmc_atom_write);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic void pmc_power_off(void)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	u16	pm1_cnt_port;
2408c2ecf20Sopenharmony_ci	u32	pm1_cnt_value;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	pr_info("Preparing to enter system sleep state S5\n");
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	pm1_cnt_port = acpi_base_addr + PM1_CNT;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	pm1_cnt_value = inl(pm1_cnt_port);
2478c2ecf20Sopenharmony_ci	pm1_cnt_value &= ~SLEEP_TYPE_MASK;
2488c2ecf20Sopenharmony_ci	pm1_cnt_value |= SLEEP_TYPE_S5;
2498c2ecf20Sopenharmony_ci	pm1_cnt_value |= SLEEP_ENABLE;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	outl(pm1_cnt_value, pm1_cnt_port);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void pmc_hw_reg_setup(struct pmc_dev *pmc)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	/*
2578c2ecf20Sopenharmony_ci	 * Disable PMC S0IX_WAKE_EN events coming from:
2588c2ecf20Sopenharmony_ci	 * - LPC clock run
2598c2ecf20Sopenharmony_ci	 * - GPIO_SUS ored dedicated IRQs
2608c2ecf20Sopenharmony_ci	 * - GPIO_SCORE ored dedicated IRQs
2618c2ecf20Sopenharmony_ci	 * - GPIO_SUS shared IRQ
2628c2ecf20Sopenharmony_ci	 * - GPIO_SCORE shared IRQ
2638c2ecf20Sopenharmony_ci	 */
2648c2ecf20Sopenharmony_ci	pmc_reg_write(pmc, PMC_S0IX_WAKE_EN, (u32)PMC_WAKE_EN_SETTING);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
2688c2ecf20Sopenharmony_cistatic void pmc_dev_state_print(struct seq_file *s, int reg_index,
2698c2ecf20Sopenharmony_ci				u32 sts, const struct pmc_bit_map *sts_map,
2708c2ecf20Sopenharmony_ci				u32 fd, const struct pmc_bit_map *fd_map)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	int offset = PMC_REG_BIT_WIDTH * reg_index;
2738c2ecf20Sopenharmony_ci	int index;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	for (index = 0; sts_map[index].name; index++) {
2768c2ecf20Sopenharmony_ci		seq_printf(s, "Dev: %-2d - %-32s\tState: %s [%s]\n",
2778c2ecf20Sopenharmony_ci			offset + index, sts_map[index].name,
2788c2ecf20Sopenharmony_ci			fd_map[index].bit_mask & fd ?  "Disabled" : "Enabled ",
2798c2ecf20Sopenharmony_ci			sts_map[index].bit_mask & sts ?  "D3" : "D0");
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int pmc_dev_state_show(struct seq_file *s, void *unused)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct pmc_dev *pmc = s->private;
2868c2ecf20Sopenharmony_ci	const struct pmc_reg_map *m = pmc->map;
2878c2ecf20Sopenharmony_ci	u32 func_dis, func_dis_2;
2888c2ecf20Sopenharmony_ci	u32 d3_sts_0, d3_sts_1;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	func_dis = pmc_reg_read(pmc, PMC_FUNC_DIS);
2918c2ecf20Sopenharmony_ci	func_dis_2 = pmc_reg_read(pmc, PMC_FUNC_DIS_2);
2928c2ecf20Sopenharmony_ci	d3_sts_0 = pmc_reg_read(pmc, PMC_D3_STS_0);
2938c2ecf20Sopenharmony_ci	d3_sts_1 = pmc_reg_read(pmc, PMC_D3_STS_1);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* Low part */
2968c2ecf20Sopenharmony_ci	pmc_dev_state_print(s, 0, d3_sts_0, m->d3_sts_0, func_dis, m->func_dis);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	/* High part */
2998c2ecf20Sopenharmony_ci	pmc_dev_state_print(s, 1, d3_sts_1, m->d3_sts_1, func_dis_2, m->func_dis_2);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pmc_dev_state);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int pmc_pss_state_show(struct seq_file *s, void *unused)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct pmc_dev *pmc = s->private;
3098c2ecf20Sopenharmony_ci	const struct pmc_bit_map *map = pmc->map->pss;
3108c2ecf20Sopenharmony_ci	u32 pss = pmc_reg_read(pmc, PMC_PSS);
3118c2ecf20Sopenharmony_ci	int index;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	for (index = 0; map[index].name; index++) {
3148c2ecf20Sopenharmony_ci		seq_printf(s, "Island: %-2d - %-32s\tState: %s\n",
3158c2ecf20Sopenharmony_ci			index, map[index].name,
3168c2ecf20Sopenharmony_ci			map[index].bit_mask & pss ? "Off" : "On");
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci	return 0;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pmc_pss_state);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct pmc_dev *pmc = s->private;
3268c2ecf20Sopenharmony_ci	u64 s0ir_tmr, s0i1_tmr, s0i2_tmr, s0i3_tmr, s0_tmr;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	s0ir_tmr = (u64)pmc_reg_read(pmc, PMC_S0IR_TMR) << PMC_TMR_SHIFT;
3298c2ecf20Sopenharmony_ci	s0i1_tmr = (u64)pmc_reg_read(pmc, PMC_S0I1_TMR) << PMC_TMR_SHIFT;
3308c2ecf20Sopenharmony_ci	s0i2_tmr = (u64)pmc_reg_read(pmc, PMC_S0I2_TMR) << PMC_TMR_SHIFT;
3318c2ecf20Sopenharmony_ci	s0i3_tmr = (u64)pmc_reg_read(pmc, PMC_S0I3_TMR) << PMC_TMR_SHIFT;
3328c2ecf20Sopenharmony_ci	s0_tmr = (u64)pmc_reg_read(pmc, PMC_S0_TMR) << PMC_TMR_SHIFT;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	seq_printf(s, "S0IR Residency:\t%lldus\n", s0ir_tmr);
3358c2ecf20Sopenharmony_ci	seq_printf(s, "S0I1 Residency:\t%lldus\n", s0i1_tmr);
3368c2ecf20Sopenharmony_ci	seq_printf(s, "S0I2 Residency:\t%lldus\n", s0i2_tmr);
3378c2ecf20Sopenharmony_ci	seq_printf(s, "S0I3 Residency:\t%lldus\n", s0i3_tmr);
3388c2ecf20Sopenharmony_ci	seq_printf(s, "S0   Residency:\t%lldus\n", s0_tmr);
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic void pmc_dbgfs_register(struct pmc_dev *pmc)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct dentry *dir;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	dir = debugfs_create_dir("pmc_atom", NULL);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	pmc->dbgfs_dir = dir;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	debugfs_create_file("dev_state", S_IFREG | S_IRUGO, dir, pmc,
3538c2ecf20Sopenharmony_ci			    &pmc_dev_state_fops);
3548c2ecf20Sopenharmony_ci	debugfs_create_file("pss_state", S_IFREG | S_IRUGO, dir, pmc,
3558c2ecf20Sopenharmony_ci			    &pmc_pss_state_fops);
3568c2ecf20Sopenharmony_ci	debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, dir, pmc,
3578c2ecf20Sopenharmony_ci			    &pmc_sleep_tmr_fops);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci#else
3608c2ecf20Sopenharmony_cistatic void pmc_dbgfs_register(struct pmc_dev *pmc)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci/*
3668c2ecf20Sopenharmony_ci * Some systems need one or more of their pmc_plt_clks to be
3678c2ecf20Sopenharmony_ci * marked as critical.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_cistatic const struct dmi_system_id critclk_systems[] = {
3708c2ecf20Sopenharmony_ci	{
3718c2ecf20Sopenharmony_ci		/* pmc_plt_clk0 is used for an external HSIC USB HUB */
3728c2ecf20Sopenharmony_ci		.ident = "MPL CEC1x",
3738c2ecf20Sopenharmony_ci		.matches = {
3748c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "MPL AG"),
3758c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "CEC10 Family"),
3768c2ecf20Sopenharmony_ci		},
3778c2ecf20Sopenharmony_ci	},
3788c2ecf20Sopenharmony_ci	{
3798c2ecf20Sopenharmony_ci		/* pmc_plt_clk0 - 3 are used for the 4 ethernet controllers */
3808c2ecf20Sopenharmony_ci		.ident = "Lex 3I380D",
3818c2ecf20Sopenharmony_ci		.matches = {
3828c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"),
3838c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "3I380D"),
3848c2ecf20Sopenharmony_ci		},
3858c2ecf20Sopenharmony_ci	},
3868c2ecf20Sopenharmony_ci	{
3878c2ecf20Sopenharmony_ci		/* pmc_plt_clk* - are used for ethernet controllers */
3888c2ecf20Sopenharmony_ci		.ident = "Lex 2I385SW",
3898c2ecf20Sopenharmony_ci		.matches = {
3908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"),
3918c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "2I385SW"),
3928c2ecf20Sopenharmony_ci		},
3938c2ecf20Sopenharmony_ci	},
3948c2ecf20Sopenharmony_ci	{
3958c2ecf20Sopenharmony_ci		/* pmc_plt_clk* - are used for ethernet controllers */
3968c2ecf20Sopenharmony_ci		.ident = "Beckhoff Baytrail",
3978c2ecf20Sopenharmony_ci		.matches = {
3988c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"),
3998c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_FAMILY, "CBxx63"),
4008c2ecf20Sopenharmony_ci		},
4018c2ecf20Sopenharmony_ci	},
4028c2ecf20Sopenharmony_ci	{
4038c2ecf20Sopenharmony_ci		.ident = "SIMATIC IPC227E",
4048c2ecf20Sopenharmony_ci		.matches = {
4058c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
4068c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_VERSION, "6ES7647-8B"),
4078c2ecf20Sopenharmony_ci		},
4088c2ecf20Sopenharmony_ci	},
4098c2ecf20Sopenharmony_ci	{
4108c2ecf20Sopenharmony_ci		.ident = "SIMATIC IPC277E",
4118c2ecf20Sopenharmony_ci		.matches = {
4128c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
4138c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_VERSION, "6AV7882-0"),
4148c2ecf20Sopenharmony_ci		},
4158c2ecf20Sopenharmony_ci	},
4168c2ecf20Sopenharmony_ci	{
4178c2ecf20Sopenharmony_ci		.ident = "CONNECT X300",
4188c2ecf20Sopenharmony_ci		.matches = {
4198c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
4208c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_VERSION, "A5E45074588"),
4218c2ecf20Sopenharmony_ci		},
4228c2ecf20Sopenharmony_ci	},
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	{ /*sentinel*/ }
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap,
4288c2ecf20Sopenharmony_ci			  const struct pmc_data *pmc_data)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct platform_device *clkdev;
4318c2ecf20Sopenharmony_ci	struct pmc_clk_data *clk_data;
4328c2ecf20Sopenharmony_ci	const struct dmi_system_id *d = dmi_first_match(critclk_systems);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
4358c2ecf20Sopenharmony_ci	if (!clk_data)
4368c2ecf20Sopenharmony_ci		return -ENOMEM;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	clk_data->base = pmc_regmap; /* offset is added by client */
4398c2ecf20Sopenharmony_ci	clk_data->clks = pmc_data->clks;
4408c2ecf20Sopenharmony_ci	if (d) {
4418c2ecf20Sopenharmony_ci		clk_data->critical = true;
4428c2ecf20Sopenharmony_ci		pr_info("%s critclks quirk enabled\n", d->ident);
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom",
4468c2ecf20Sopenharmony_ci					       PLATFORM_DEVID_NONE,
4478c2ecf20Sopenharmony_ci					       clk_data, sizeof(*clk_data));
4488c2ecf20Sopenharmony_ci	if (IS_ERR(clkdev)) {
4498c2ecf20Sopenharmony_ci		kfree(clk_data);
4508c2ecf20Sopenharmony_ci		return PTR_ERR(clkdev);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	kfree(clk_data);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct pmc_dev *pmc = &pmc_device;
4618c2ecf20Sopenharmony_ci	const struct pmc_data *data = (struct pmc_data *)ent->driver_data;
4628c2ecf20Sopenharmony_ci	const struct pmc_reg_map *map = data->map;
4638c2ecf20Sopenharmony_ci	int ret;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/* Obtain ACPI base address */
4668c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, ACPI_BASE_ADDR_OFFSET, &acpi_base_addr);
4678c2ecf20Sopenharmony_ci	acpi_base_addr &= ACPI_BASE_ADDR_MASK;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	/* Install power off function */
4708c2ecf20Sopenharmony_ci	if (acpi_base_addr != 0 && pm_power_off == NULL)
4718c2ecf20Sopenharmony_ci		pm_power_off = pmc_power_off;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, PMC_BASE_ADDR_OFFSET, &pmc->base_addr);
4748c2ecf20Sopenharmony_ci	pmc->base_addr &= PMC_BASE_ADDR_MASK;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	pmc->regmap = ioremap(pmc->base_addr, PMC_MMIO_REG_LEN);
4778c2ecf20Sopenharmony_ci	if (!pmc->regmap) {
4788c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "error: ioremap failed\n");
4798c2ecf20Sopenharmony_ci		return -ENOMEM;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	pmc->map = map;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/* PMC hardware registers setup */
4858c2ecf20Sopenharmony_ci	pmc_hw_reg_setup(pmc);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	pmc_dbgfs_register(pmc);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* Register platform clocks - PMC_PLT_CLK [0..5] */
4908c2ecf20Sopenharmony_ci	ret = pmc_setup_clks(pdev, pmc->regmap, data);
4918c2ecf20Sopenharmony_ci	if (ret)
4928c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "platform clocks register failed: %d\n",
4938c2ecf20Sopenharmony_ci			 ret);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	pmc->init = true;
4968c2ecf20Sopenharmony_ci	return ret;
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci/*
5008c2ecf20Sopenharmony_ci * Data for PCI driver interface
5018c2ecf20Sopenharmony_ci *
5028c2ecf20Sopenharmony_ci * used by pci_match_id() call below.
5038c2ecf20Sopenharmony_ci */
5048c2ecf20Sopenharmony_cistatic const struct pci_device_id pmc_pci_ids[] = {
5058c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data },
5068c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data },
5078c2ecf20Sopenharmony_ci	{ 0, },
5088c2ecf20Sopenharmony_ci};
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int __init pmc_atom_init(void)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct pci_dev *pdev = NULL;
5138c2ecf20Sopenharmony_ci	const struct pci_device_id *ent;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* We look for our device - PCU PMC
5168c2ecf20Sopenharmony_ci	 * we assume that there is max. one device.
5178c2ecf20Sopenharmony_ci	 *
5188c2ecf20Sopenharmony_ci	 * We can't use plain pci_driver mechanism,
5198c2ecf20Sopenharmony_ci	 * as the device is really a multiple function device,
5208c2ecf20Sopenharmony_ci	 * main driver that binds to the pci_device is lpc_ich
5218c2ecf20Sopenharmony_ci	 * and have to find & bind to the device this way.
5228c2ecf20Sopenharmony_ci	 */
5238c2ecf20Sopenharmony_ci	for_each_pci_dev(pdev) {
5248c2ecf20Sopenharmony_ci		ent = pci_match_id(pmc_pci_ids, pdev);
5258c2ecf20Sopenharmony_ci		if (ent)
5268c2ecf20Sopenharmony_ci			return pmc_setup_dev(pdev, ent);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci	/* Device not found. */
5298c2ecf20Sopenharmony_ci	return -ENODEV;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cidevice_initcall(pmc_atom_init);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci/*
5358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Aubrey Li <aubrey.li@linux.intel.com>");
5368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface");
5378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
5388c2ecf20Sopenharmony_ci*/
539