diff options
| -rw-r--r-- | arch/x86/Kconfig | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/pmc_atom.h | 31 | ||||
| -rw-r--r-- | arch/x86/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/pmc_atom.c | 104 |
4 files changed, 140 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a8f749ef0fdc..6295a2182a76 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -2403,6 +2403,10 @@ config IOSF_MBI | |||
| 2403 | default m | 2403 | default m |
| 2404 | depends on PCI | 2404 | depends on PCI |
| 2405 | 2405 | ||
| 2406 | config PMC_ATOM | ||
| 2407 | def_bool y | ||
| 2408 | depends on PCI | ||
| 2409 | |||
| 2406 | source "net/Kconfig" | 2410 | source "net/Kconfig" |
| 2407 | 2411 | ||
| 2408 | source "drivers/Kconfig" | 2412 | source "drivers/Kconfig" |
diff --git a/arch/x86/include/asm/pmc_atom.h b/arch/x86/include/asm/pmc_atom.h new file mode 100644 index 000000000000..03a2769f2d7f --- /dev/null +++ b/arch/x86/include/asm/pmc_atom.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * Intel Atom SOC Power Management Controller Header File | ||
| 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 | #ifndef PMC_ATOM_H | ||
| 17 | #define PMC_ATOM_H | ||
| 18 | |||
| 19 | /* ValleyView Power Control Unit PCI Device ID */ | ||
| 20 | #define PCI_DEVICE_ID_VLV_PMC 0x0F1C | ||
| 21 | |||
| 22 | /* PMC I/O Registers */ | ||
| 23 | #define ACPI_BASE_ADDR_OFFSET 0x40 | ||
| 24 | #define ACPI_BASE_ADDR_MASK 0xFFFFFE00 | ||
| 25 | #define ACPI_MMIO_REG_LEN 0x100 | ||
| 26 | |||
| 27 | #define PM1_CNT 0x4 | ||
| 28 | #define SLEEP_TYPE_MASK 0xFFFFECFF | ||
| 29 | #define SLEEP_TYPE_S5 0x1C00 | ||
| 30 | #define SLEEP_ENABLE 0x2000 | ||
| 31 | #endif /* PMC_ATOM_H */ | ||
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 047f9ff2e36c..bde3993624f1 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
| @@ -106,6 +106,7 @@ obj-$(CONFIG_EFI) += sysfb_efi.o | |||
| 106 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o | 106 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o |
| 107 | obj-$(CONFIG_TRACING) += tracepoint.o | 107 | obj-$(CONFIG_TRACING) += tracepoint.o |
| 108 | obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o | 108 | obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o |
| 109 | obj-$(CONFIG_PMC_ATOM) += pmc_atom.o | ||
| 109 | 110 | ||
| 110 | ### | 111 | ### |
| 111 | # 64 bit specific files | 112 | # 64 bit specific files |
diff --git a/arch/x86/kernel/pmc_atom.c b/arch/x86/kernel/pmc_atom.c new file mode 100644 index 000000000000..9eb79f6fc512 --- /dev/null +++ b/arch/x86/kernel/pmc_atom.c | |||
| @@ -0,0 +1,104 @@ | |||
| 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 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/pci.h> | ||
| 21 | #include <linux/device.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | |||
| 24 | #include <asm/pmc_atom.h> | ||
| 25 | |||
| 26 | static u32 acpi_base_addr; | ||
| 27 | |||
| 28 | static void pmc_power_off(void) | ||
| 29 | { | ||
| 30 | u16 pm1_cnt_port; | ||
| 31 | u32 pm1_cnt_value; | ||
| 32 | |||
| 33 | pr_info("Preparing to enter system sleep state S5\n"); | ||
| 34 | |||
| 35 | pm1_cnt_port = acpi_base_addr + PM1_CNT; | ||
| 36 | |||
| 37 | pm1_cnt_value = inl(pm1_cnt_port); | ||
| 38 | pm1_cnt_value &= SLEEP_TYPE_MASK; | ||
| 39 | pm1_cnt_value |= SLEEP_TYPE_S5; | ||
| 40 | pm1_cnt_value |= SLEEP_ENABLE; | ||
| 41 | |||
| 42 | outl(pm1_cnt_value, pm1_cnt_port); | ||
| 43 | } | ||
| 44 | |||
| 45 | static int pmc_setup_dev(struct pci_dev *pdev) | ||
| 46 | { | ||
| 47 | /* Obtain ACPI base address */ | ||
| 48 | pci_read_config_dword(pdev, ACPI_BASE_ADDR_OFFSET, &acpi_base_addr); | ||
| 49 | acpi_base_addr &= ACPI_BASE_ADDR_MASK; | ||
| 50 | |||
| 51 | /* Install power off function */ | ||
| 52 | if (acpi_base_addr != 0 && pm_power_off == NULL) | ||
| 53 | pm_power_off = pmc_power_off; | ||
| 54 | |||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Data for PCI driver interface | ||
| 60 | * | ||
| 61 | * This data only exists for exporting the supported | ||
| 62 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
| 63 | * register a pci_driver, because lpc_ich will register | ||
| 64 | * a driver on the same PCI id. | ||
| 65 | */ | ||
| 66 | static const struct pci_device_id pmc_pci_ids[] = { | ||
| 67 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VLV_PMC) }, | ||
| 68 | { 0, }, | ||
| 69 | }; | ||
| 70 | |||
| 71 | MODULE_DEVICE_TABLE(pci, pmc_pci_ids); | ||
| 72 | |||
| 73 | static int __init pmc_atom_init(void) | ||
| 74 | { | ||
| 75 | int err = -ENODEV; | ||
| 76 | struct pci_dev *pdev = NULL; | ||
| 77 | const struct pci_device_id *ent; | ||
| 78 | |||
| 79 | /* We look for our device - PCU PMC | ||
| 80 | * we assume that there is max. one device. | ||
| 81 | * | ||
| 82 | * We can't use plain pci_driver mechanism, | ||
| 83 | * as the device is really a multiple function device, | ||
| 84 | * main driver that binds to the pci_device is lpc_ich | ||
| 85 | * and have to find & bind to the device this way. | ||
| 86 | */ | ||
| 87 | for_each_pci_dev(pdev) { | ||
| 88 | ent = pci_match_id(pmc_pci_ids, pdev); | ||
| 89 | if (ent) { | ||
| 90 | err = pmc_setup_dev(pdev); | ||
| 91 | goto out; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | /* Device not found. */ | ||
| 95 | out: | ||
| 96 | return err; | ||
| 97 | } | ||
| 98 | |||
| 99 | module_init(pmc_atom_init); | ||
| 100 | /* no module_exit, this driver shouldn't be unloaded */ | ||
| 101 | |||
| 102 | MODULE_AUTHOR("Aubrey Li <aubrey.li@linux.intel.com>"); | ||
| 103 | MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface"); | ||
| 104 | MODULE_LICENSE("GPL v2"); | ||
