]>
Commit | Line | Data |
---|---|---|
93e5eadd LA |
1 | /* |
2 | * Intel Atom SOC Power Management Controller Driver | |
3 | * Copyright (c) 2014, Intel Corporation. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | */ | |
15 | ||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
17 | ||
80a7581f IT |
18 | #include <linux/debugfs.h> |
19 | #include <linux/device.h> | |
7c2e0713 | 20 | #include <linux/dmi.h> |
93e5eadd | 21 | #include <linux/init.h> |
80a7581f | 22 | #include <linux/io.h> |
282a4e4c | 23 | #include <linux/platform_data/x86/clk-pmc-atom.h> |
80a7581f | 24 | #include <linux/platform_data/x86/pmc_atom.h> |
282a4e4c | 25 | #include <linux/platform_device.h> |
93e5eadd | 26 | #include <linux/pci.h> |
f855911c | 27 | #include <linux/seq_file.h> |
93e5eadd | 28 | |
940406d1 AS |
29 | struct pmc_bit_map { |
30 | const char *name; | |
31 | u32 bit_mask; | |
32 | }; | |
33 | ||
34 | struct pmc_reg_map { | |
2b8f8edd AS |
35 | const struct pmc_bit_map *d3_sts_0; |
36 | const struct pmc_bit_map *d3_sts_1; | |
37 | const struct pmc_bit_map *func_dis; | |
38 | const struct pmc_bit_map *func_dis_2; | |
940406d1 AS |
39 | const struct pmc_bit_map *pss; |
40 | }; | |
41 | ||
282a4e4c IT |
42 | struct pmc_data { |
43 | const struct pmc_reg_map *map; | |
44 | const struct pmc_clk *clks; | |
45 | }; | |
46 | ||
b00055ca LA |
47 | struct pmc_dev { |
48 | u32 base_addr; | |
49 | void __iomem *regmap; | |
940406d1 | 50 | const struct pmc_reg_map *map; |
f855911c LA |
51 | #ifdef CONFIG_DEBUG_FS |
52 | struct dentry *dbgfs_dir; | |
53 | #endif /* CONFIG_DEBUG_FS */ | |
68872eb9 | 54 | bool init; |
b00055ca LA |
55 | }; |
56 | ||
57 | static struct pmc_dev pmc_device; | |
93e5eadd LA |
58 | static u32 acpi_base_addr; |
59 | ||
282a4e4c IT |
60 | static const struct pmc_clk byt_clks[] = { |
61 | { | |
62 | .name = "xtal", | |
63 | .freq = 25000000, | |
64 | .parent_name = NULL, | |
65 | }, | |
66 | { | |
67 | .name = "pll", | |
68 | .freq = 19200000, | |
69 | .parent_name = "xtal", | |
70 | }, | |
71 | {}, | |
72 | }; | |
73 | ||
74 | static const struct pmc_clk cht_clks[] = { | |
75 | { | |
76 | .name = "xtal", | |
77 | .freq = 19200000, | |
78 | .parent_name = NULL, | |
79 | }, | |
80 | {}, | |
81 | }; | |
82 | ||
2b8f8edd | 83 | static const struct pmc_bit_map d3_sts_0_map[] = { |
c3c65aa6 AS |
84 | {"LPSS1_F0_DMA", BIT_LPSS1_F0_DMA}, |
85 | {"LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1}, | |
86 | {"LPSS1_F2_PWM2", BIT_LPSS1_F2_PWM2}, | |
87 | {"LPSS1_F3_HSUART1", BIT_LPSS1_F3_HSUART1}, | |
88 | {"LPSS1_F4_HSUART2", BIT_LPSS1_F4_HSUART2}, | |
89 | {"LPSS1_F5_SPI", BIT_LPSS1_F5_SPI}, | |
90 | {"LPSS1_F6_Reserved", BIT_LPSS1_F6_XXX}, | |
91 | {"LPSS1_F7_Reserved", BIT_LPSS1_F7_XXX}, | |
92 | {"SCC_EMMC", BIT_SCC_EMMC}, | |
93 | {"SCC_SDIO", BIT_SCC_SDIO}, | |
94 | {"SCC_SDCARD", BIT_SCC_SDCARD}, | |
95 | {"SCC_MIPI", BIT_SCC_MIPI}, | |
96 | {"HDA", BIT_HDA}, | |
97 | {"LPE", BIT_LPE}, | |
98 | {"OTG", BIT_OTG}, | |
99 | {"USH", BIT_USH}, | |
100 | {"GBE", BIT_GBE}, | |
101 | {"SATA", BIT_SATA}, | |
102 | {"USB_EHCI", BIT_USB_EHCI}, | |
103 | {"SEC", BIT_SEC}, | |
104 | {"PCIE_PORT0", BIT_PCIE_PORT0}, | |
105 | {"PCIE_PORT1", BIT_PCIE_PORT1}, | |
106 | {"PCIE_PORT2", BIT_PCIE_PORT2}, | |
107 | {"PCIE_PORT3", BIT_PCIE_PORT3}, | |
108 | {"LPSS2_F0_DMA", BIT_LPSS2_F0_DMA}, | |
109 | {"LPSS2_F1_I2C1", BIT_LPSS2_F1_I2C1}, | |
110 | {"LPSS2_F2_I2C2", BIT_LPSS2_F2_I2C2}, | |
111 | {"LPSS2_F3_I2C3", BIT_LPSS2_F3_I2C3}, | |
112 | {"LPSS2_F3_I2C4", BIT_LPSS2_F4_I2C4}, | |
113 | {"LPSS2_F5_I2C5", BIT_LPSS2_F5_I2C5}, | |
114 | {"LPSS2_F6_I2C6", BIT_LPSS2_F6_I2C6}, | |
115 | {"LPSS2_F7_I2C7", BIT_LPSS2_F7_I2C7}, | |
2b8f8edd AS |
116 | {}, |
117 | }; | |
118 | ||
119 | static struct pmc_bit_map byt_d3_sts_1_map[] = { | |
c3c65aa6 AS |
120 | {"SMB", BIT_SMB}, |
121 | {"OTG_SS_PHY", BIT_OTG_SS_PHY}, | |
122 | {"USH_SS_PHY", BIT_USH_SS_PHY}, | |
123 | {"DFX", BIT_DFX}, | |
124 | {}, | |
f855911c LA |
125 | }; |
126 | ||
2b8f8edd AS |
127 | static struct pmc_bit_map cht_d3_sts_1_map[] = { |
128 | {"SMB", BIT_SMB}, | |
129 | {"GMM", BIT_STS_GMM}, | |
130 | {"ISH", BIT_STS_ISH}, | |
131 | {}, | |
132 | }; | |
133 | ||
134 | static struct pmc_bit_map cht_func_dis_2_map[] = { | |
135 | {"SMB", BIT_SMB}, | |
136 | {"GMM", BIT_FD_GMM}, | |
137 | {"ISH", BIT_FD_ISH}, | |
138 | {}, | |
139 | }; | |
140 | ||
141 | static const struct pmc_bit_map byt_pss_map[] = { | |
c3c65aa6 AS |
142 | {"GBE", PMC_PSS_BIT_GBE}, |
143 | {"SATA", PMC_PSS_BIT_SATA}, | |
144 | {"HDA", PMC_PSS_BIT_HDA}, | |
145 | {"SEC", PMC_PSS_BIT_SEC}, | |
146 | {"PCIE", PMC_PSS_BIT_PCIE}, | |
147 | {"LPSS", PMC_PSS_BIT_LPSS}, | |
148 | {"LPE", PMC_PSS_BIT_LPE}, | |
149 | {"DFX", PMC_PSS_BIT_DFX}, | |
150 | {"USH_CTRL", PMC_PSS_BIT_USH_CTRL}, | |
151 | {"USH_SUS", PMC_PSS_BIT_USH_SUS}, | |
152 | {"USH_VCCS", PMC_PSS_BIT_USH_VCCS}, | |
153 | {"USH_VCCA", PMC_PSS_BIT_USH_VCCA}, | |
154 | {"OTG_CTRL", PMC_PSS_BIT_OTG_CTRL}, | |
155 | {"OTG_VCCS", PMC_PSS_BIT_OTG_VCCS}, | |
156 | {"OTG_VCCA_CLK", PMC_PSS_BIT_OTG_VCCA_CLK}, | |
157 | {"OTG_VCCA", PMC_PSS_BIT_OTG_VCCA}, | |
158 | {"USB", PMC_PSS_BIT_USB}, | |
159 | {"USB_SUS", PMC_PSS_BIT_USB_SUS}, | |
160 | {}, | |
0e154020 AS |
161 | }; |
162 | ||
2b8f8edd AS |
163 | static const struct pmc_bit_map cht_pss_map[] = { |
164 | {"SATA", PMC_PSS_BIT_SATA}, | |
165 | {"HDA", PMC_PSS_BIT_HDA}, | |
166 | {"SEC", PMC_PSS_BIT_SEC}, | |
167 | {"PCIE", PMC_PSS_BIT_PCIE}, | |
168 | {"LPSS", PMC_PSS_BIT_LPSS}, | |
169 | {"LPE", PMC_PSS_BIT_LPE}, | |
170 | {"UFS", PMC_PSS_BIT_CHT_UFS}, | |
171 | {"UXD", PMC_PSS_BIT_CHT_UXD}, | |
172 | {"UXD_FD", PMC_PSS_BIT_CHT_UXD_FD}, | |
173 | {"UX_ENG", PMC_PSS_BIT_CHT_UX_ENG}, | |
174 | {"USB_SUS", PMC_PSS_BIT_CHT_USB_SUS}, | |
175 | {"GMM", PMC_PSS_BIT_CHT_GMM}, | |
176 | {"ISH", PMC_PSS_BIT_CHT_ISH}, | |
177 | {"DFX_MASTER", PMC_PSS_BIT_CHT_DFX_MASTER}, | |
178 | {"DFX_CLUSTER1", PMC_PSS_BIT_CHT_DFX_CLUSTER1}, | |
179 | {"DFX_CLUSTER2", PMC_PSS_BIT_CHT_DFX_CLUSTER2}, | |
180 | {"DFX_CLUSTER3", PMC_PSS_BIT_CHT_DFX_CLUSTER3}, | |
181 | {"DFX_CLUSTER4", PMC_PSS_BIT_CHT_DFX_CLUSTER4}, | |
182 | {"DFX_CLUSTER5", PMC_PSS_BIT_CHT_DFX_CLUSTER5}, | |
183 | {}, | |
184 | }; | |
185 | ||
186 | static const struct pmc_reg_map byt_reg_map = { | |
187 | .d3_sts_0 = d3_sts_0_map, | |
188 | .d3_sts_1 = byt_d3_sts_1_map, | |
189 | .func_dis = d3_sts_0_map, | |
190 | .func_dis_2 = byt_d3_sts_1_map, | |
191 | .pss = byt_pss_map, | |
192 | }; | |
193 | ||
194 | static const struct pmc_reg_map cht_reg_map = { | |
195 | .d3_sts_0 = d3_sts_0_map, | |
196 | .d3_sts_1 = cht_d3_sts_1_map, | |
197 | .func_dis = d3_sts_0_map, | |
198 | .func_dis_2 = cht_func_dis_2_map, | |
199 | .pss = cht_pss_map, | |
940406d1 AS |
200 | }; |
201 | ||
282a4e4c IT |
202 | static const struct pmc_data byt_data = { |
203 | .map = &byt_reg_map, | |
204 | .clks = byt_clks, | |
205 | }; | |
206 | ||
207 | static const struct pmc_data cht_data = { | |
208 | .map = &cht_reg_map, | |
209 | .clks = cht_clks, | |
210 | }; | |
211 | ||
b00055ca LA |
212 | static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) |
213 | { | |
214 | return readl(pmc->regmap + reg_offset); | |
215 | } | |
216 | ||
217 | static inline void pmc_reg_write(struct pmc_dev *pmc, int reg_offset, u32 val) | |
218 | { | |
219 | writel(val, pmc->regmap + reg_offset); | |
220 | } | |
221 | ||
68872eb9 AS |
222 | int pmc_atom_read(int offset, u32 *value) |
223 | { | |
224 | struct pmc_dev *pmc = &pmc_device; | |
225 | ||
226 | if (!pmc->init) | |
227 | return -ENODEV; | |
228 | ||
229 | *value = pmc_reg_read(pmc, offset); | |
230 | return 0; | |
231 | } | |
232 | EXPORT_SYMBOL_GPL(pmc_atom_read); | |
233 | ||
234 | int pmc_atom_write(int offset, u32 value) | |
235 | { | |
236 | struct pmc_dev *pmc = &pmc_device; | |
237 | ||
238 | if (!pmc->init) | |
239 | return -ENODEV; | |
240 | ||
241 | pmc_reg_write(pmc, offset, value); | |
242 | return 0; | |
243 | } | |
244 | EXPORT_SYMBOL_GPL(pmc_atom_write); | |
245 | ||
93e5eadd LA |
246 | static void pmc_power_off(void) |
247 | { | |
248 | u16 pm1_cnt_port; | |
249 | u32 pm1_cnt_value; | |
250 | ||
251 | pr_info("Preparing to enter system sleep state S5\n"); | |
252 | ||
253 | pm1_cnt_port = acpi_base_addr + PM1_CNT; | |
254 | ||
255 | pm1_cnt_value = inl(pm1_cnt_port); | |
256 | pm1_cnt_value &= SLEEP_TYPE_MASK; | |
257 | pm1_cnt_value |= SLEEP_TYPE_S5; | |
258 | pm1_cnt_value |= SLEEP_ENABLE; | |
259 | ||
260 | outl(pm1_cnt_value, pm1_cnt_port); | |
261 | } | |
262 | ||
b00055ca LA |
263 | static void pmc_hw_reg_setup(struct pmc_dev *pmc) |
264 | { | |
265 | /* | |
266 | * Disable PMC S0IX_WAKE_EN events coming from: | |
267 | * - LPC clock run | |
268 | * - GPIO_SUS ored dedicated IRQs | |
269 | * - GPIO_SCORE ored dedicated IRQs | |
270 | * - GPIO_SUS shared IRQ | |
271 | * - GPIO_SCORE shared IRQ | |
272 | */ | |
273 | pmc_reg_write(pmc, PMC_S0IX_WAKE_EN, (u32)PMC_WAKE_EN_SETTING); | |
274 | } | |
275 | ||
f855911c | 276 | #ifdef CONFIG_DEBUG_FS |
2b8f8edd AS |
277 | static void pmc_dev_state_print(struct seq_file *s, int reg_index, |
278 | u32 sts, const struct pmc_bit_map *sts_map, | |
279 | u32 fd, const struct pmc_bit_map *fd_map) | |
280 | { | |
281 | int offset = PMC_REG_BIT_WIDTH * reg_index; | |
282 | int index; | |
283 | ||
284 | for (index = 0; sts_map[index].name; index++) { | |
285 | seq_printf(s, "Dev: %-2d - %-32s\tState: %s [%s]\n", | |
286 | offset + index, sts_map[index].name, | |
287 | fd_map[index].bit_mask & fd ? "Disabled" : "Enabled ", | |
288 | sts_map[index].bit_mask & sts ? "D3" : "D0"); | |
289 | } | |
290 | } | |
291 | ||
f855911c LA |
292 | static int pmc_dev_state_show(struct seq_file *s, void *unused) |
293 | { | |
294 | struct pmc_dev *pmc = s->private; | |
2b8f8edd AS |
295 | const struct pmc_reg_map *m = pmc->map; |
296 | u32 func_dis, func_dis_2; | |
297 | u32 d3_sts_0, d3_sts_1; | |
f855911c LA |
298 | |
299 | func_dis = pmc_reg_read(pmc, PMC_FUNC_DIS); | |
300 | func_dis_2 = pmc_reg_read(pmc, PMC_FUNC_DIS_2); | |
301 | d3_sts_0 = pmc_reg_read(pmc, PMC_D3_STS_0); | |
302 | d3_sts_1 = pmc_reg_read(pmc, PMC_D3_STS_1); | |
303 | ||
2b8f8edd AS |
304 | /* Low part */ |
305 | pmc_dev_state_print(s, 0, d3_sts_0, m->d3_sts_0, func_dis, m->func_dis); | |
306 | ||
307 | /* High part */ | |
308 | pmc_dev_state_print(s, 1, d3_sts_1, m->d3_sts_1, func_dis_2, m->func_dis_2); | |
f855911c | 309 | |
f855911c LA |
310 | return 0; |
311 | } | |
312 | ||
1ea74a56 | 313 | DEFINE_SHOW_ATTRIBUTE(pmc_dev_state); |
f855911c | 314 | |
0e154020 AS |
315 | static int pmc_pss_state_show(struct seq_file *s, void *unused) |
316 | { | |
317 | struct pmc_dev *pmc = s->private; | |
940406d1 | 318 | const struct pmc_bit_map *map = pmc->map->pss; |
0e154020 | 319 | u32 pss = pmc_reg_read(pmc, PMC_PSS); |
940406d1 | 320 | int index; |
0e154020 | 321 | |
940406d1 | 322 | for (index = 0; map[index].name; index++) { |
c3c65aa6 | 323 | seq_printf(s, "Island: %-2d - %-32s\tState: %s\n", |
940406d1 AS |
324 | index, map[index].name, |
325 | map[index].bit_mask & pss ? "Off" : "On"); | |
0e154020 AS |
326 | } |
327 | return 0; | |
328 | } | |
329 | ||
1ea74a56 | 330 | DEFINE_SHOW_ATTRIBUTE(pmc_pss_state); |
0e154020 | 331 | |
f855911c LA |
332 | static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) |
333 | { | |
334 | struct pmc_dev *pmc = s->private; | |
335 | u64 s0ir_tmr, s0i1_tmr, s0i2_tmr, s0i3_tmr, s0_tmr; | |
336 | ||
4c51cb00 DC |
337 | s0ir_tmr = (u64)pmc_reg_read(pmc, PMC_S0IR_TMR) << PMC_TMR_SHIFT; |
338 | s0i1_tmr = (u64)pmc_reg_read(pmc, PMC_S0I1_TMR) << PMC_TMR_SHIFT; | |
339 | s0i2_tmr = (u64)pmc_reg_read(pmc, PMC_S0I2_TMR) << PMC_TMR_SHIFT; | |
340 | s0i3_tmr = (u64)pmc_reg_read(pmc, PMC_S0I3_TMR) << PMC_TMR_SHIFT; | |
341 | s0_tmr = (u64)pmc_reg_read(pmc, PMC_S0_TMR) << PMC_TMR_SHIFT; | |
f855911c LA |
342 | |
343 | seq_printf(s, "S0IR Residency:\t%lldus\n", s0ir_tmr); | |
344 | seq_printf(s, "S0I1 Residency:\t%lldus\n", s0i1_tmr); | |
345 | seq_printf(s, "S0I2 Residency:\t%lldus\n", s0i2_tmr); | |
346 | seq_printf(s, "S0I3 Residency:\t%lldus\n", s0i3_tmr); | |
347 | seq_printf(s, "S0 Residency:\t%lldus\n", s0_tmr); | |
348 | return 0; | |
349 | } | |
350 | ||
1ea74a56 | 351 | DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr); |
f855911c LA |
352 | |
353 | static void pmc_dbgfs_unregister(struct pmc_dev *pmc) | |
354 | { | |
f855911c | 355 | debugfs_remove_recursive(pmc->dbgfs_dir); |
f855911c LA |
356 | } |
357 | ||
68872eb9 | 358 | static int pmc_dbgfs_register(struct pmc_dev *pmc) |
f855911c LA |
359 | { |
360 | struct dentry *dir, *f; | |
361 | ||
362 | dir = debugfs_create_dir("pmc_atom", NULL); | |
363 | if (!dir) | |
364 | return -ENOMEM; | |
365 | ||
1b43d712 AS |
366 | pmc->dbgfs_dir = dir; |
367 | ||
f855911c | 368 | f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO, |
1ea74a56 | 369 | dir, pmc, &pmc_dev_state_fops); |
68872eb9 | 370 | if (!f) |
f855911c | 371 | goto err; |
0e154020 AS |
372 | |
373 | f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO, | |
1ea74a56 | 374 | dir, pmc, &pmc_pss_state_fops); |
68872eb9 | 375 | if (!f) |
0e154020 | 376 | goto err; |
0e154020 | 377 | |
f855911c | 378 | f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, |
1ea74a56 | 379 | dir, pmc, &pmc_sleep_tmr_fops); |
68872eb9 | 380 | if (!f) |
f855911c | 381 | goto err; |
1b43d712 | 382 | |
f855911c LA |
383 | return 0; |
384 | err: | |
385 | pmc_dbgfs_unregister(pmc); | |
386 | return -ENODEV; | |
387 | } | |
9575a6a2 | 388 | #else |
68872eb9 | 389 | static int pmc_dbgfs_register(struct pmc_dev *pmc) |
9575a6a2 MK |
390 | { |
391 | return 0; | |
392 | } | |
f855911c LA |
393 | #endif /* CONFIG_DEBUG_FS */ |
394 | ||
7c2e0713 DM |
395 | /* |
396 | * Some systems need one or more of their pmc_plt_clks to be | |
397 | * marked as critical. | |
398 | */ | |
b995dcca | 399 | static const struct dmi_system_id critclk_systems[] = { |
7c2e0713 DM |
400 | { |
401 | .ident = "MPL CEC1x", | |
402 | .matches = { | |
403 | DMI_MATCH(DMI_SYS_VENDOR, "MPL AG"), | |
404 | DMI_MATCH(DMI_PRODUCT_NAME, "CEC10 Family"), | |
405 | }, | |
406 | }, | |
407 | { /*sentinel*/ } | |
408 | }; | |
409 | ||
282a4e4c IT |
410 | static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap, |
411 | const struct pmc_data *pmc_data) | |
412 | { | |
413 | struct platform_device *clkdev; | |
414 | struct pmc_clk_data *clk_data; | |
7c2e0713 | 415 | const struct dmi_system_id *d = dmi_first_match(critclk_systems); |
282a4e4c IT |
416 | |
417 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
418 | if (!clk_data) | |
419 | return -ENOMEM; | |
420 | ||
421 | clk_data->base = pmc_regmap; /* offset is added by client */ | |
422 | clk_data->clks = pmc_data->clks; | |
7c2e0713 DM |
423 | if (d) { |
424 | clk_data->critical = true; | |
425 | pr_info("%s critclks quirk enabled\n", d->ident); | |
426 | } | |
282a4e4c IT |
427 | |
428 | clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom", | |
429 | PLATFORM_DEVID_NONE, | |
430 | clk_data, sizeof(*clk_data)); | |
431 | if (IS_ERR(clkdev)) { | |
432 | kfree(clk_data); | |
433 | return PTR_ERR(clkdev); | |
434 | } | |
435 | ||
436 | kfree(clk_data); | |
437 | ||
438 | return 0; | |
439 | } | |
440 | ||
2b8f8edd | 441 | static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) |
93e5eadd | 442 | { |
b00055ca | 443 | struct pmc_dev *pmc = &pmc_device; |
282a4e4c IT |
444 | const struct pmc_data *data = (struct pmc_data *)ent->driver_data; |
445 | const struct pmc_reg_map *map = data->map; | |
f855911c | 446 | int ret; |
b00055ca | 447 | |
93e5eadd LA |
448 | /* Obtain ACPI base address */ |
449 | pci_read_config_dword(pdev, ACPI_BASE_ADDR_OFFSET, &acpi_base_addr); | |
450 | acpi_base_addr &= ACPI_BASE_ADDR_MASK; | |
451 | ||
452 | /* Install power off function */ | |
453 | if (acpi_base_addr != 0 && pm_power_off == NULL) | |
454 | pm_power_off = pmc_power_off; | |
455 | ||
b00055ca LA |
456 | pci_read_config_dword(pdev, PMC_BASE_ADDR_OFFSET, &pmc->base_addr); |
457 | pmc->base_addr &= PMC_BASE_ADDR_MASK; | |
458 | ||
459 | pmc->regmap = ioremap_nocache(pmc->base_addr, PMC_MMIO_REG_LEN); | |
460 | if (!pmc->regmap) { | |
461 | dev_err(&pdev->dev, "error: ioremap failed\n"); | |
462 | return -ENOMEM; | |
463 | } | |
464 | ||
940406d1 AS |
465 | pmc->map = map; |
466 | ||
b00055ca LA |
467 | /* PMC hardware registers setup */ |
468 | pmc_hw_reg_setup(pmc); | |
f855911c | 469 | |
68872eb9 AS |
470 | ret = pmc_dbgfs_register(pmc); |
471 | if (ret) | |
472 | dev_warn(&pdev->dev, "debugfs register failed\n"); | |
9575a6a2 | 473 | |
282a4e4c IT |
474 | /* Register platform clocks - PMC_PLT_CLK [0..5] */ |
475 | ret = pmc_setup_clks(pdev, pmc->regmap, data); | |
476 | if (ret) | |
477 | dev_warn(&pdev->dev, "platform clocks register failed: %d\n", | |
478 | ret); | |
479 | ||
68872eb9 | 480 | pmc->init = true; |
9575a6a2 | 481 | return ret; |
93e5eadd LA |
482 | } |
483 | ||
484 | /* | |
485 | * Data for PCI driver interface | |
486 | * | |
e971aa2c | 487 | * used by pci_match_id() call below. |
93e5eadd LA |
488 | */ |
489 | static const struct pci_device_id pmc_pci_ids[] = { | |
282a4e4c IT |
490 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data }, |
491 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data }, | |
93e5eadd LA |
492 | { 0, }, |
493 | }; | |
494 | ||
93e5eadd LA |
495 | static int __init pmc_atom_init(void) |
496 | { | |
93e5eadd LA |
497 | struct pci_dev *pdev = NULL; |
498 | const struct pci_device_id *ent; | |
499 | ||
500 | /* We look for our device - PCU PMC | |
501 | * we assume that there is max. one device. | |
502 | * | |
503 | * We can't use plain pci_driver mechanism, | |
504 | * as the device is really a multiple function device, | |
505 | * main driver that binds to the pci_device is lpc_ich | |
506 | * and have to find & bind to the device this way. | |
507 | */ | |
508 | for_each_pci_dev(pdev) { | |
509 | ent = pci_match_id(pmc_pci_ids, pdev); | |
4b25f42a | 510 | if (ent) |
2b8f8edd | 511 | return pmc_setup_dev(pdev, ent); |
93e5eadd LA |
512 | } |
513 | /* Device not found. */ | |
4b25f42a | 514 | return -ENODEV; |
93e5eadd LA |
515 | } |
516 | ||
e971aa2c | 517 | device_initcall(pmc_atom_init); |
93e5eadd | 518 | |
e971aa2c | 519 | /* |
93e5eadd LA |
520 | MODULE_AUTHOR("Aubrey Li <aubrey.li@linux.intel.com>"); |
521 | MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface"); | |
522 | MODULE_LICENSE("GPL v2"); | |
e971aa2c | 523 | */ |