diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 15:50:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 15:50:54 -0400 |
commit | bfaf245022b4b8661af2e35f467cf0e91943c24c (patch) | |
tree | b5a6ee49a047557a791eb897c8c9545a155e36b7 /drivers/platform | |
parent | 96d928ed75c4ba4253e82910a697ec7b06ace8b4 (diff) | |
parent | 3e20a26b02bd4f24945c87407df51948dd488620 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"This is the main pull request for MIPS for Linux 4.1. Most
noteworthy:
- Add more Octeon-optimized crypto functions
- Octeon crypto preemption and locking fixes
- Little endian support for Octeon
- Use correct CSR to soft reset Octeons
- Support LEDs on the Octeon-based DSR-1000N
- Fix PCI interrupt mapping for the Octeon-based DSR-1000N
- Mark prom_free_prom_memory() as __init for a number of systems
- Support for Imagination's Pistachio SOC. This includes arch and
CLK bits. I'd like to merge pinctrl bits later
- Improve parallelism of csum_partial for certain pipelines
- Organize DTB files in subdirs like other architectures
- Implement read_sched_clock for all MIPS platforms other than
Octeon
- Massive series of 38 fixes and cleanups for the FPU emulator /
kernel
- Further FPU remulator work to support new features. This sits on a
separate branch which also has been pulled into the 4.1 KVM branch
- Clean up and fixes for the SEAD3 eval board; remove unused file
- Various updates for Netlogic platforms
- A number of small updates for Loongson 3 platforms
- Increase the memory limit for ATH79 platforms to 256MB
- A fair number of fixes and updates for BCM47xx platforms
- Finish the implementation of XPA support
- MIPS FDC support. No, not floppy controller but Fast Debug Channel :)
- Detect the R16000 used in SGI legacy platforms
- Fix Kconfig dependencies for the SSB bus support"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (265 commits)
MIPS: Makefile: Fix MIPS ASE detection code
MIPS: asm: elf: Set O32 default FPU flags
MIPS: BCM47XX: Fix detecting Microsoft MN-700 & Asus WL500G
MIPS: Kconfig: Disable SMP/CPS for 64-bit
MIPS: Hibernate: flush TLB entries earlier
MIPS: smp-cps: cpu_set FPU mask if FPU present
MIPS: lose_fpu(): Disable FPU when MSA enabled
MIPS: ralink: add missing symbol for RALINK_ILL_ACC
MIPS: ralink: Fix bad config symbol in PCI makefile.
SSB: fix Kconfig dependencies
MIPS: Malta: Detect and fix bad memsize values
Revert "MIPS: Avoid pipeline stalls on some MIPS32R2 cores."
MIPS: Octeon: Delete override of cpu_has_mips_r2_exec_hazard.
MIPS: Fix cpu_has_mips_r2_exec_hazard.
MIPS: kernel: entry.S: Set correct ISA level for mips_ihb
MIPS: asm: spinlock: Fix addiu instruction for R10000_LLSC_WAR case
MIPS: r4kcache: Use correct base register for MIPS R6 cache flushes
MIPS: Kconfig: Fix typo for the r2-to-r6 emulator kernel parameter
MIPS: unaligned: Fix regular load/store instruction emulation for EVA
MIPS: unaligned: Surround load/store macros in do {} while statements
...
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/Kconfig | 3 | ||||
-rw-r--r-- | drivers/platform/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/mips/Kconfig | 30 | ||||
-rw-r--r-- | drivers/platform/mips/Makefile | 2 | ||||
-rw-r--r-- | drivers/platform/mips/acpi_init.c | 150 | ||||
-rw-r--r-- | drivers/platform/mips/cpu_hwmon.c | 207 |
6 files changed, 393 insertions, 0 deletions
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 09fde58b12e0..0adccbf5c83f 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig | |||
@@ -1,6 +1,9 @@ | |||
1 | if X86 | 1 | if X86 |
2 | source "drivers/platform/x86/Kconfig" | 2 | source "drivers/platform/x86/Kconfig" |
3 | endif | 3 | endif |
4 | if MIPS | ||
5 | source "drivers/platform/mips/Kconfig" | ||
6 | endif | ||
4 | if GOLDFISH | 7 | if GOLDFISH |
5 | source "drivers/platform/goldfish/Kconfig" | 8 | source "drivers/platform/goldfish/Kconfig" |
6 | endif | 9 | endif |
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 3656b7b17b99..ca2692510733 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_X86) += x86/ | 5 | obj-$(CONFIG_X86) += x86/ |
6 | obj-$(CONFIG_MIPS) += mips/ | ||
6 | obj-$(CONFIG_OLPC) += olpc/ | 7 | obj-$(CONFIG_OLPC) += olpc/ |
7 | obj-$(CONFIG_GOLDFISH) += goldfish/ | 8 | obj-$(CONFIG_GOLDFISH) += goldfish/ |
8 | obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ | 9 | obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ |
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig new file mode 100644 index 000000000000..125e569017be --- /dev/null +++ b/drivers/platform/mips/Kconfig | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # MIPS Platform Specific Drivers | ||
3 | # | ||
4 | |||
5 | menuconfig MIPS_PLATFORM_DEVICES | ||
6 | bool "MIPS Platform Specific Device Drivers" | ||
7 | default y | ||
8 | help | ||
9 | Say Y here to get to see options for device drivers of various | ||
10 | MIPS platforms, including vendor-specific netbook/laptop/desktop | ||
11 | extension and hardware monitor drivers. This option itself does | ||
12 | not add any kernel code. | ||
13 | |||
14 | If you say N, all options in this submenu will be skipped and disabled. | ||
15 | |||
16 | if MIPS_PLATFORM_DEVICES | ||
17 | |||
18 | config MIPS_ACPI | ||
19 | bool | ||
20 | default y if LOONGSON_MACH3X | ||
21 | |||
22 | config CPU_HWMON | ||
23 | tristate "Loongson CPU HWMon Driver" | ||
24 | depends on LOONGSON_MACH3X | ||
25 | select HWMON | ||
26 | default y | ||
27 | help | ||
28 | Loongson-3A/3B CPU Hwmon (temperature sensor) driver. | ||
29 | |||
30 | endif # MIPS_PLATFORM_DEVICES | ||
diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile new file mode 100644 index 000000000000..43412849b195 --- /dev/null +++ b/drivers/platform/mips/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_MIPS_ACPI) += acpi_init.o | ||
2 | obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o | ||
diff --git a/drivers/platform/mips/acpi_init.c b/drivers/platform/mips/acpi_init.c new file mode 100644 index 000000000000..dbdad79ead8f --- /dev/null +++ b/drivers/platform/mips/acpi_init.c | |||
@@ -0,0 +1,150 @@ | |||
1 | #include <linux/io.h> | ||
2 | #include <linux/init.h> | ||
3 | #include <linux/ioport.h> | ||
4 | #include <linux/export.h> | ||
5 | |||
6 | #define SBX00_ACPI_IO_BASE 0x800 | ||
7 | #define SBX00_ACPI_IO_SIZE 0x100 | ||
8 | |||
9 | #define ACPI_PM_EVT_BLK (SBX00_ACPI_IO_BASE + 0x00) /* 4 bytes */ | ||
10 | #define ACPI_PM_CNT_BLK (SBX00_ACPI_IO_BASE + 0x04) /* 2 bytes */ | ||
11 | #define ACPI_PMA_CNT_BLK (SBX00_ACPI_IO_BASE + 0x0F) /* 1 byte */ | ||
12 | #define ACPI_PM_TMR_BLK (SBX00_ACPI_IO_BASE + 0x18) /* 4 bytes */ | ||
13 | #define ACPI_GPE0_BLK (SBX00_ACPI_IO_BASE + 0x10) /* 8 bytes */ | ||
14 | #define ACPI_END (SBX00_ACPI_IO_BASE + 0x80) | ||
15 | |||
16 | #define PM_INDEX 0xCD6 | ||
17 | #define PM_DATA 0xCD7 | ||
18 | #define PM2_INDEX 0xCD0 | ||
19 | #define PM2_DATA 0xCD1 | ||
20 | |||
21 | /* | ||
22 | * SCI interrupt need acpi space, allocate here | ||
23 | */ | ||
24 | |||
25 | static int __init register_acpi_resource(void) | ||
26 | { | ||
27 | request_region(SBX00_ACPI_IO_BASE, SBX00_ACPI_IO_SIZE, "acpi"); | ||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | static void pmio_write_index(u16 index, u8 reg, u8 value) | ||
32 | { | ||
33 | outb(reg, index); | ||
34 | outb(value, index + 1); | ||
35 | } | ||
36 | |||
37 | static u8 pmio_read_index(u16 index, u8 reg) | ||
38 | { | ||
39 | outb(reg, index); | ||
40 | return inb(index + 1); | ||
41 | } | ||
42 | |||
43 | void pm_iowrite(u8 reg, u8 value) | ||
44 | { | ||
45 | pmio_write_index(PM_INDEX, reg, value); | ||
46 | } | ||
47 | EXPORT_SYMBOL(pm_iowrite); | ||
48 | |||
49 | u8 pm_ioread(u8 reg) | ||
50 | { | ||
51 | return pmio_read_index(PM_INDEX, reg); | ||
52 | } | ||
53 | EXPORT_SYMBOL(pm_ioread); | ||
54 | |||
55 | void pm2_iowrite(u8 reg, u8 value) | ||
56 | { | ||
57 | pmio_write_index(PM2_INDEX, reg, value); | ||
58 | } | ||
59 | EXPORT_SYMBOL(pm2_iowrite); | ||
60 | |||
61 | u8 pm2_ioread(u8 reg) | ||
62 | { | ||
63 | return pmio_read_index(PM2_INDEX, reg); | ||
64 | } | ||
65 | EXPORT_SYMBOL(pm2_ioread); | ||
66 | |||
67 | static void acpi_hw_clear_status(void) | ||
68 | { | ||
69 | u16 value; | ||
70 | |||
71 | /* PMStatus: Clear WakeStatus/PwrBtnStatus */ | ||
72 | value = inw(ACPI_PM_EVT_BLK); | ||
73 | value |= (1 << 8 | 1 << 15); | ||
74 | outw(value, ACPI_PM_EVT_BLK); | ||
75 | |||
76 | /* GPEStatus: Clear all generated events */ | ||
77 | outl(inl(ACPI_GPE0_BLK), ACPI_GPE0_BLK); | ||
78 | } | ||
79 | |||
80 | void acpi_registers_setup(void) | ||
81 | { | ||
82 | u32 value; | ||
83 | |||
84 | /* PM Status Base */ | ||
85 | pm_iowrite(0x20, ACPI_PM_EVT_BLK & 0xff); | ||
86 | pm_iowrite(0x21, ACPI_PM_EVT_BLK >> 8); | ||
87 | |||
88 | /* PM Control Base */ | ||
89 | pm_iowrite(0x22, ACPI_PM_CNT_BLK & 0xff); | ||
90 | pm_iowrite(0x23, ACPI_PM_CNT_BLK >> 8); | ||
91 | |||
92 | /* GPM Base */ | ||
93 | pm_iowrite(0x28, ACPI_GPE0_BLK & 0xff); | ||
94 | pm_iowrite(0x29, ACPI_GPE0_BLK >> 8); | ||
95 | |||
96 | /* ACPI End */ | ||
97 | pm_iowrite(0x2e, ACPI_END & 0xff); | ||
98 | pm_iowrite(0x2f, ACPI_END >> 8); | ||
99 | |||
100 | /* IO Decode: When AcpiDecodeEnable set, South-Bridge uses the contents | ||
101 | * of the PM registers at index 0x20~0x2B to decode ACPI I/O address. */ | ||
102 | pm_iowrite(0x0e, 1 << 3); | ||
103 | |||
104 | /* SCI_EN set */ | ||
105 | outw(1, ACPI_PM_CNT_BLK); | ||
106 | |||
107 | /* Enable to generate SCI */ | ||
108 | pm_iowrite(0x10, pm_ioread(0x10) | 1); | ||
109 | |||
110 | /* GPM3/GPM9 enable */ | ||
111 | value = inl(ACPI_GPE0_BLK + 4); | ||
112 | outl(value | (1 << 14) | (1 << 22), ACPI_GPE0_BLK + 4); | ||
113 | |||
114 | /* Set GPM9 as input */ | ||
115 | pm_iowrite(0x8d, pm_ioread(0x8d) & (~(1 << 1))); | ||
116 | |||
117 | /* Set GPM9 as non-output */ | ||
118 | pm_iowrite(0x94, pm_ioread(0x94) | (1 << 3)); | ||
119 | |||
120 | /* GPM3 config ACPI trigger SCIOUT */ | ||
121 | pm_iowrite(0x33, pm_ioread(0x33) & (~(3 << 4))); | ||
122 | |||
123 | /* GPM9 config ACPI trigger SCIOUT */ | ||
124 | pm_iowrite(0x3d, pm_ioread(0x3d) & (~(3 << 2))); | ||
125 | |||
126 | /* GPM3 config falling edge trigger */ | ||
127 | pm_iowrite(0x37, pm_ioread(0x37) & (~(1 << 6))); | ||
128 | |||
129 | /* No wait for STPGNT# in ACPI Sx state */ | ||
130 | pm_iowrite(0x7c, pm_ioread(0x7c) | (1 << 6)); | ||
131 | |||
132 | /* Set GPM3 pull-down enable */ | ||
133 | value = pm2_ioread(0xf6); | ||
134 | value |= ((1 << 7) | (1 << 3)); | ||
135 | pm2_iowrite(0xf6, value); | ||
136 | |||
137 | /* Set GPM9 pull-down enable */ | ||
138 | value = pm2_ioread(0xf8); | ||
139 | value |= ((1 << 5) | (1 << 1)); | ||
140 | pm2_iowrite(0xf8, value); | ||
141 | } | ||
142 | |||
143 | int __init sbx00_acpi_init(void) | ||
144 | { | ||
145 | register_acpi_resource(); | ||
146 | acpi_registers_setup(); | ||
147 | acpi_hw_clear_status(); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c new file mode 100644 index 000000000000..0f6c63e17049 --- /dev/null +++ b/drivers/platform/mips/cpu_hwmon.c | |||
@@ -0,0 +1,207 @@ | |||
1 | #include <linux/err.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/reboot.h> | ||
4 | #include <linux/jiffies.h> | ||
5 | #include <linux/hwmon.h> | ||
6 | #include <linux/hwmon-sysfs.h> | ||
7 | |||
8 | #include <loongson.h> | ||
9 | #include <boot_param.h> | ||
10 | #include <loongson_hwmon.h> | ||
11 | |||
12 | /* | ||
13 | * Loongson-3 series cpu has two sensors inside, | ||
14 | * each of them from 0 to 255, | ||
15 | * if more than 127, that is dangerous. | ||
16 | * here only provide sensor1 data, because it always hot than sensor0 | ||
17 | */ | ||
18 | int loongson3_cpu_temp(int cpu) | ||
19 | { | ||
20 | u32 reg; | ||
21 | |||
22 | reg = LOONGSON_CHIPTEMP(cpu); | ||
23 | if (loongson_sysconf.cputype == Loongson_3A) | ||
24 | reg = (reg >> 8) & 0xff; | ||
25 | else if (loongson_sysconf.cputype == Loongson_3B) | ||
26 | reg = ((reg >> 8) & 0xff) - 100; | ||
27 | |||
28 | return (int)reg * 1000; | ||
29 | } | ||
30 | |||
31 | static struct device *cpu_hwmon_dev; | ||
32 | |||
33 | static ssize_t get_hwmon_name(struct device *dev, | ||
34 | struct device_attribute *attr, char *buf); | ||
35 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, get_hwmon_name, NULL, 0); | ||
36 | |||
37 | static struct attribute *cpu_hwmon_attributes[] = { | ||
38 | &sensor_dev_attr_name.dev_attr.attr, | ||
39 | NULL | ||
40 | }; | ||
41 | |||
42 | /* Hwmon device attribute group */ | ||
43 | static struct attribute_group cpu_hwmon_attribute_group = { | ||
44 | .attrs = cpu_hwmon_attributes, | ||
45 | }; | ||
46 | |||
47 | /* Hwmon device get name */ | ||
48 | static ssize_t get_hwmon_name(struct device *dev, | ||
49 | struct device_attribute *attr, char *buf) | ||
50 | { | ||
51 | return sprintf(buf, "cpu-hwmon\n"); | ||
52 | } | ||
53 | |||
54 | static ssize_t get_cpu0_temp(struct device *dev, | ||
55 | struct device_attribute *attr, char *buf); | ||
56 | static ssize_t get_cpu1_temp(struct device *dev, | ||
57 | struct device_attribute *attr, char *buf); | ||
58 | static ssize_t cpu0_temp_label(struct device *dev, | ||
59 | struct device_attribute *attr, char *buf); | ||
60 | static ssize_t cpu1_temp_label(struct device *dev, | ||
61 | struct device_attribute *attr, char *buf); | ||
62 | |||
63 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu0_temp, NULL, 1); | ||
64 | static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu0_temp_label, NULL, 1); | ||
65 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu1_temp, NULL, 2); | ||
66 | static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu1_temp_label, NULL, 2); | ||
67 | |||
68 | static const struct attribute *hwmon_cputemp1[] = { | ||
69 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
70 | &sensor_dev_attr_temp1_label.dev_attr.attr, | ||
71 | NULL | ||
72 | }; | ||
73 | |||
74 | static const struct attribute *hwmon_cputemp2[] = { | ||
75 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
76 | &sensor_dev_attr_temp2_label.dev_attr.attr, | ||
77 | NULL | ||
78 | }; | ||
79 | |||
80 | static ssize_t cpu0_temp_label(struct device *dev, | ||
81 | struct device_attribute *attr, char *buf) | ||
82 | { | ||
83 | return sprintf(buf, "CPU 0 Temprature\n"); | ||
84 | } | ||
85 | |||
86 | static ssize_t cpu1_temp_label(struct device *dev, | ||
87 | struct device_attribute *attr, char *buf) | ||
88 | { | ||
89 | return sprintf(buf, "CPU 1 Temprature\n"); | ||
90 | } | ||
91 | |||
92 | static ssize_t get_cpu0_temp(struct device *dev, | ||
93 | struct device_attribute *attr, char *buf) | ||
94 | { | ||
95 | int value = loongson3_cpu_temp(0); | ||
96 | return sprintf(buf, "%d\n", value); | ||
97 | } | ||
98 | |||
99 | static ssize_t get_cpu1_temp(struct device *dev, | ||
100 | struct device_attribute *attr, char *buf) | ||
101 | { | ||
102 | int value = loongson3_cpu_temp(1); | ||
103 | return sprintf(buf, "%d\n", value); | ||
104 | } | ||
105 | |||
106 | static int create_sysfs_cputemp_files(struct kobject *kobj) | ||
107 | { | ||
108 | int ret; | ||
109 | |||
110 | ret = sysfs_create_files(kobj, hwmon_cputemp1); | ||
111 | if (ret) | ||
112 | goto sysfs_create_temp1_fail; | ||
113 | |||
114 | if (loongson_sysconf.nr_cpus <= loongson_sysconf.cores_per_package) | ||
115 | return 0; | ||
116 | |||
117 | ret = sysfs_create_files(kobj, hwmon_cputemp2); | ||
118 | if (ret) | ||
119 | goto sysfs_create_temp2_fail; | ||
120 | |||
121 | return 0; | ||
122 | |||
123 | sysfs_create_temp2_fail: | ||
124 | sysfs_remove_files(kobj, hwmon_cputemp1); | ||
125 | |||
126 | sysfs_create_temp1_fail: | ||
127 | return -1; | ||
128 | } | ||
129 | |||
130 | static void remove_sysfs_cputemp_files(struct kobject *kobj) | ||
131 | { | ||
132 | sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp1); | ||
133 | |||
134 | if (loongson_sysconf.nr_cpus > loongson_sysconf.cores_per_package) | ||
135 | sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp2); | ||
136 | } | ||
137 | |||
138 | #define CPU_THERMAL_THRESHOLD 90000 | ||
139 | static struct delayed_work thermal_work; | ||
140 | |||
141 | static void do_thermal_timer(struct work_struct *work) | ||
142 | { | ||
143 | int value = loongson3_cpu_temp(0); | ||
144 | if (value <= CPU_THERMAL_THRESHOLD) | ||
145 | schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000)); | ||
146 | else | ||
147 | orderly_poweroff(true); | ||
148 | } | ||
149 | |||
150 | static int __init loongson_hwmon_init(void) | ||
151 | { | ||
152 | int ret; | ||
153 | |||
154 | pr_info("Loongson Hwmon Enter...\n"); | ||
155 | |||
156 | cpu_hwmon_dev = hwmon_device_register(NULL); | ||
157 | if (IS_ERR(cpu_hwmon_dev)) { | ||
158 | ret = -ENOMEM; | ||
159 | pr_err("hwmon_device_register fail!\n"); | ||
160 | goto fail_hwmon_device_register; | ||
161 | } | ||
162 | |||
163 | ret = sysfs_create_group(&cpu_hwmon_dev->kobj, | ||
164 | &cpu_hwmon_attribute_group); | ||
165 | if (ret) { | ||
166 | pr_err("fail to create loongson hwmon!\n"); | ||
167 | goto fail_sysfs_create_group_hwmon; | ||
168 | } | ||
169 | |||
170 | ret = create_sysfs_cputemp_files(&cpu_hwmon_dev->kobj); | ||
171 | if (ret) { | ||
172 | pr_err("fail to create cpu temprature interface!\n"); | ||
173 | goto fail_create_sysfs_cputemp_files; | ||
174 | } | ||
175 | |||
176 | INIT_DEFERRABLE_WORK(&thermal_work, do_thermal_timer); | ||
177 | schedule_delayed_work(&thermal_work, msecs_to_jiffies(20000)); | ||
178 | |||
179 | return ret; | ||
180 | |||
181 | fail_create_sysfs_cputemp_files: | ||
182 | sysfs_remove_group(&cpu_hwmon_dev->kobj, | ||
183 | &cpu_hwmon_attribute_group); | ||
184 | |||
185 | fail_sysfs_create_group_hwmon: | ||
186 | hwmon_device_unregister(cpu_hwmon_dev); | ||
187 | |||
188 | fail_hwmon_device_register: | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static void __exit loongson_hwmon_exit(void) | ||
193 | { | ||
194 | cancel_delayed_work_sync(&thermal_work); | ||
195 | remove_sysfs_cputemp_files(&cpu_hwmon_dev->kobj); | ||
196 | sysfs_remove_group(&cpu_hwmon_dev->kobj, | ||
197 | &cpu_hwmon_attribute_group); | ||
198 | hwmon_device_unregister(cpu_hwmon_dev); | ||
199 | } | ||
200 | |||
201 | module_init(loongson_hwmon_init); | ||
202 | module_exit(loongson_hwmon_exit); | ||
203 | |||
204 | MODULE_AUTHOR("Yu Xiang <xiangy@lemote.com>"); | ||
205 | MODULE_AUTHOR("Huacai Chen <chenhc@lemote.com>"); | ||
206 | MODULE_DESCRIPTION("Loongson CPU Hwmon driver"); | ||
207 | MODULE_LICENSE("GPL"); | ||