Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'pm-cpuidle'

* pm-cpuidle:
cpuidle: Fix three reference count leaks
cpuidle: Convert Qualcomm SPM driver to a generic CPUidle driver
Documentation: ABI: make current_governer_ro as a candidate for removal
Documentation: cpuidle: update the document
cpuidle: sysfs: Remove sysfs_switch and switch attributes
cpuidle: Make cpuidle governor switchable to be the default behaviour
cpuidle: sysfs: Accept governor name with 15 characters
cpuidle: sysfs: Fix the overlap for showing available governors
cpuidle: psci: Fixup execution order when entering a domain idle state
cpuidle: sysfs: Minor coding style corrections
cpuidle: sysfs: Remove the unused define_one_r(o/w) macros

+125 -180
+9
Documentation/ABI/obsolete/sysfs-cpuidle
··· 1 + What: /sys/devices/system/cpu/cpuidle/current_governor_ro 2 + Date: April, 2020 3 + Contact: linux-pm@vger.kernel.org 4 + Description: 5 + current_governor_ro shows current using cpuidle governor, but read only. 6 + with the update that cpuidle governor can be changed at runtime in default, 7 + both current_governor and current_governor_ro co-exist under 8 + /sys/devices/system/cpu/cpuidle/ file, it's duplicate so make 9 + current_governor_ro obselete.
+9 -15
Documentation/ABI/testing/sysfs-devices-system-cpu
··· 106 106 See Documentation/admin-guide/cputopology.rst for more information. 107 107 108 108 109 - What: /sys/devices/system/cpu/cpuidle/current_driver 110 - /sys/devices/system/cpu/cpuidle/current_governer_ro 111 - /sys/devices/system/cpu/cpuidle/available_governors 109 + What: /sys/devices/system/cpu/cpuidle/available_governors 110 + /sys/devices/system/cpu/cpuidle/current_driver 112 111 /sys/devices/system/cpu/cpuidle/current_governor 112 + /sys/devices/system/cpu/cpuidle/current_governer_ro 113 113 Date: September 2007 114 114 Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org> 115 115 Description: Discover cpuidle policy and mechanism ··· 119 119 consumption during idle. 120 120 121 121 Idle policy (governor) is differentiated from idle mechanism 122 - (driver) 123 - 124 - current_driver: (RO) displays current idle mechanism 125 - 126 - current_governor_ro: (RO) displays current idle policy 127 - 128 - With the cpuidle_sysfs_switch boot option enabled (meant for 129 - developer testing), the following three attributes are visible 130 - instead: 131 - 132 - current_driver: same as described above 122 + (driver). 133 123 134 124 available_governors: (RO) displays a space separated list of 135 - available governors 125 + available governors. 126 + 127 + current_driver: (RO) displays current idle mechanism. 136 128 137 129 current_governor: (RW) displays current idle policy. Users can 138 130 switch the governor at runtime by writing to this file. 131 + 132 + current_governor_ro: (RO) displays current idle policy. 139 133 140 134 See Documentation/admin-guide/pm/cpuidle.rst and 141 135 Documentation/driver-api/pm/cpuidle.rst for more information.
+9 -11
Documentation/admin-guide/pm/cpuidle.rst
··· 159 159 and that is the primary reason for having more than one governor in the 160 160 ``CPUIdle`` subsystem. 161 161 162 - There are three ``CPUIdle`` governors available, ``menu``, `TEO <teo-gov_>`_ 163 - and ``ladder``. Which of them is used by default depends on the configuration 164 - of the kernel and in particular on whether or not the scheduler tick can be 165 - `stopped by the idle loop <idle-cpus-and-tick_>`_. It is possible to change the 166 - governor at run time if the ``cpuidle_sysfs_switch`` command line parameter has 167 - been passed to the kernel, but that is not safe in general, so it should not be 168 - done on production systems (that may change in the future, though). The name of 169 - the ``CPUIdle`` governor currently used by the kernel can be read from the 170 - :file:`current_governor_ro` (or :file:`current_governor` if 171 - ``cpuidle_sysfs_switch`` is present in the kernel command line) file under 172 - :file:`/sys/devices/system/cpu/cpuidle/` in ``sysfs``. 162 + There are four ``CPUIdle`` governors available, ``menu``, `TEO <teo-gov_>`_, 163 + ``ladder`` and ``haltpoll``. Which of them is used by default depends on the 164 + configuration of the kernel and in particular on whether or not the scheduler 165 + tick can be `stopped by the idle loop <idle-cpus-and-tick_>`_. Available 166 + governors can be read from the :file:`available_governors`, and the governor 167 + can be changed at runtime. The name of the ``CPUIdle`` governor currently 168 + used by the kernel can be read from the :file:`current_governor_ro` or 169 + :file:`current_governor` file under :file:`/sys/devices/system/cpu/cpuidle/` 170 + in ``sysfs``. 173 171 174 172 Which ``CPUIdle`` driver is used, on the other hand, usually depends on the 175 173 platform the kernel is running on, but there are platforms with more than one
+2 -3
Documentation/driver-api/pm/cpuidle.rst
··· 68 68 governor currently in use, or the name of the new governor was passed to the 69 69 kernel as the value of the ``cpuidle.governor=`` command line parameter, the new 70 70 governor will be used from that point on (there can be only one ``CPUIdle`` 71 - governor in use at a time). Also, if ``cpuidle_sysfs_switch`` is passed to the 72 - kernel in the command line, user space can choose the ``CPUIdle`` governor to 73 - use at run time via ``sysfs``. 71 + governor in use at a time). Also, user space can choose the ``CPUIdle`` 72 + governor to use at run time via ``sysfs``. 74 73 75 74 Once registered, ``CPUIdle`` governors cannot be unregistered, so it is not 76 75 practical to put them into loadable kernel modules.
+1
MAINTAINERS
··· 2225 2225 F: drivers/*/qcom/ 2226 2226 F: drivers/bluetooth/btqcomsmd.c 2227 2227 F: drivers/clocksource/timer-qcom.c 2228 + F: drivers/cpuidle/cpuidle-qcom-spm.c 2228 2229 F: drivers/extcon/extcon-qcom* 2229 2230 F: drivers/i2c/busses/i2c-qcom-geni.c 2230 2231 F: drivers/i2c/busses/i2c-qup.c
+13
drivers/cpuidle/Kconfig.arm
··· 94 94 select ARM_CPU_SUSPEND 95 95 help 96 96 Select this to enable cpuidle for NVIDIA Tegra20/30/114/124 SoCs. 97 + 98 + config ARM_QCOM_SPM_CPUIDLE 99 + bool "CPU Idle Driver for Qualcomm Subsystem Power Manager (SPM)" 100 + depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64 101 + select ARM_CPU_SUSPEND 102 + select CPU_IDLE_MULTIPLE_DRIVERS 103 + select DT_IDLE_STATES 104 + select QCOM_SCM 105 + help 106 + Select this to enable cpuidle for Qualcomm processors. 107 + The Subsystem Power Manager (SPM) controls low power modes for the 108 + CPU and L2 cores. It interface with various system drivers to put 109 + the cores in low power modes.
+1
drivers/cpuidle/Makefile
··· 25 25 cpuidle_psci-y := cpuidle-psci.o 26 26 cpuidle_psci-$(CONFIG_PM_GENERIC_DOMAINS_OF) += cpuidle-psci-domain.o 27 27 obj-$(CONFIG_ARM_TEGRA_CPUIDLE) += cpuidle-tegra.o 28 + obj-$(CONFIG_ARM_QCOM_SPM_CPUIDLE) += cpuidle-qcom-spm.o 28 29 29 30 ############################################################################### 30 31 # MIPS drivers
+7 -1
drivers/cpuidle/cpuidle-psci.c
··· 58 58 u32 state; 59 59 int ret; 60 60 61 + ret = cpu_pm_enter(); 62 + if (ret) 63 + return -1; 64 + 61 65 /* Do runtime PM to manage a hierarchical CPU toplogy. */ 62 66 pm_runtime_put_sync_suspend(pd_dev); 63 67 ··· 69 65 if (!state) 70 66 state = states[idx]; 71 67 72 - ret = psci_enter_state(idx, state); 68 + ret = psci_cpu_suspend_enter(state) ? -1 : idx; 73 69 74 70 pm_runtime_get_sync(pd_dev); 71 + 72 + cpu_pm_exit(); 75 73 76 74 /* Clear the domain state to start fresh when back from idle. */ 77 75 psci_set_domain_state(0);
+22 -53
drivers/cpuidle/sysfs.c
··· 18 18 19 19 #include "cpuidle.h" 20 20 21 - static unsigned int sysfs_switch; 22 - static int __init cpuidle_sysfs_setup(char *unused) 23 - { 24 - sysfs_switch = 1; 25 - return 1; 26 - } 27 - __setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup); 28 - 29 21 static ssize_t show_available_governors(struct device *dev, 30 22 struct device_attribute *attr, 31 23 char *buf) ··· 27 35 28 36 mutex_lock(&cpuidle_lock); 29 37 list_for_each_entry(tmp, &cpuidle_governors, governor_list) { 30 - if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - 31 - CPUIDLE_NAME_LEN - 2)) 38 + if (i >= (ssize_t) (PAGE_SIZE - (CPUIDLE_NAME_LEN + 2))) 32 39 goto out; 33 - i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name); 40 + 41 + i += scnprintf(&buf[i], CPUIDLE_NAME_LEN + 1, "%s ", tmp->name); 34 42 } 35 43 36 44 out: ··· 77 85 struct device_attribute *attr, 78 86 const char *buf, size_t count) 79 87 { 80 - char gov_name[CPUIDLE_NAME_LEN]; 81 - int ret = -EINVAL; 82 - size_t len = count; 88 + char gov_name[CPUIDLE_NAME_LEN + 1]; 89 + int ret; 83 90 struct cpuidle_governor *gov; 84 91 85 - if (!len || len >= sizeof(gov_name)) 92 + ret = sscanf(buf, "%" __stringify(CPUIDLE_NAME_LEN) "s", gov_name); 93 + if (ret != 1) 86 94 return -EINVAL; 87 95 88 - memcpy(gov_name, buf, len); 89 - gov_name[len] = '\0'; 90 - if (gov_name[len - 1] == '\n') 91 - gov_name[--len] = '\0'; 92 - 93 96 mutex_lock(&cpuidle_lock); 94 - 97 + ret = -EINVAL; 95 98 list_for_each_entry(gov, &cpuidle_governors, governor_list) { 96 - if (strlen(gov->name) == len && !strcmp(gov->name, gov_name)) { 99 + if (!strncmp(gov->name, gov_name, CPUIDLE_NAME_LEN)) { 97 100 ret = cpuidle_switch_governor(gov); 98 101 break; 99 102 } 100 103 } 101 - 102 104 mutex_unlock(&cpuidle_lock); 103 105 104 - if (ret) 105 - return ret; 106 - else 107 - return count; 106 + return ret ? ret : count; 108 107 } 109 108 109 + static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL); 110 110 static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL); 111 + static DEVICE_ATTR(current_governor, 0644, show_current_governor, 112 + store_current_governor); 111 113 static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL); 112 114 113 - static struct attribute *cpuidle_default_attrs[] = { 115 + static struct attribute *cpuidle_attrs[] = { 116 + &dev_attr_available_governors.attr, 114 117 &dev_attr_current_driver.attr, 118 + &dev_attr_current_governor.attr, 115 119 &dev_attr_current_governor_ro.attr, 116 120 NULL 117 121 }; 118 122 119 - static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL); 120 - static DEVICE_ATTR(current_governor, 0644, show_current_governor, 121 - store_current_governor); 122 - 123 - static struct attribute *cpuidle_switch_attrs[] = { 124 - &dev_attr_available_governors.attr, 125 - &dev_attr_current_driver.attr, 126 - &dev_attr_current_governor.attr, 127 - NULL 128 - }; 129 - 130 123 static struct attribute_group cpuidle_attr_group = { 131 - .attrs = cpuidle_default_attrs, 124 + .attrs = cpuidle_attrs, 132 125 .name = "cpuidle", 133 126 }; 134 127 ··· 123 146 */ 124 147 int cpuidle_add_interface(struct device *dev) 125 148 { 126 - if (sysfs_switch) 127 - cpuidle_attr_group.attrs = cpuidle_switch_attrs; 128 - 129 149 return sysfs_create_group(&dev->kobj, &cpuidle_attr_group); 130 150 } 131 151 ··· 140 166 ssize_t (*show)(struct cpuidle_device *, char *); 141 167 ssize_t (*store)(struct cpuidle_device *, const char *, size_t count); 142 168 }; 143 - 144 - #define define_one_ro(_name, show) \ 145 - static struct cpuidle_attr attr_##_name = __ATTR(_name, 0444, show, NULL) 146 - #define define_one_rw(_name, show, store) \ 147 - static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store) 148 169 149 170 #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) 150 171 ··· 400 431 #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) 401 432 402 433 static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr, 403 - char * buf) 434 + char *buf) 404 435 { 405 436 int ret = -EIO; 406 437 struct cpuidle_state *state = kobj_to_state(kobj); 407 438 struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); 408 - struct cpuidle_state_attr * cattr = attr_to_stateattr(attr); 439 + struct cpuidle_state_attr *cattr = attr_to_stateattr(attr); 409 440 410 441 if (cattr->show) 411 442 ret = cattr->show(state, state_usage, buf); ··· 484 515 ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, 485 516 &kdev->kobj, "state%d", i); 486 517 if (ret) { 487 - kfree(kobj); 518 + kobject_put(&kobj->kobj); 488 519 goto error_state; 489 520 } 490 521 cpuidle_add_s2idle_attr_group(kobj); ··· 615 646 ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, 616 647 &kdev->kobj, "driver"); 617 648 if (ret) { 618 - kfree(kdrv); 649 + kobject_put(&kdrv->kobj); 619 650 return ret; 620 651 } 621 652 ··· 709 740 error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj, 710 741 "cpuidle"); 711 742 if (error) { 712 - kfree(kdev); 743 + kobject_put(&kdev->kobj); 713 744 return error; 714 745 } 715 746
-10
drivers/soc/qcom/Kconfig
··· 80 80 tristate 81 81 select QCOM_QMI_HELPERS 82 82 83 - config QCOM_PM 84 - bool "Qualcomm Power Management" 85 - depends on ARCH_QCOM && !ARM64 86 - select ARM_CPU_SUSPEND 87 - select QCOM_SCM 88 - help 89 - QCOM Platform specific power driver to manage cores and L2 low power 90 - modes. It interface with various system drivers to put the cores in 91 - low power modes. 92 - 93 83 config QCOM_QMI_HELPERS 94 84 tristate 95 85 depends on NET
-1
drivers/soc/qcom/Makefile
··· 8 8 obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o 9 9 obj-$(CONFIG_QCOM_OCMEM) += ocmem.o 10 10 obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o 11 - obj-$(CONFIG_QCOM_PM) += spm.o 12 11 obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o 13 12 qmi_helpers-y += qmi_encdec.o qmi_interface.o 14 13 obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
+52 -86
drivers/soc/qcom/spm.c drivers/cpuidle/cpuidle-qcom-spm.c
··· 19 19 #include <linux/cpu_pm.h> 20 20 #include <linux/qcom_scm.h> 21 21 22 - #include <asm/cpuidle.h> 23 22 #include <asm/proc-fns.h> 24 23 #include <asm/suspend.h> 24 + 25 + #include "dt_idle_states.h" 25 26 26 27 #define MAX_PMIC_DATA 2 27 28 #define MAX_SEQ_DATA 64 ··· 63 62 }; 64 63 65 64 struct spm_driver_data { 65 + struct cpuidle_driver cpuidle_driver; 66 66 void __iomem *reg_base; 67 67 const struct spm_reg_data *reg_data; 68 68 }; ··· 108 106 .start_index[PM_SLEEP_MODE_STBY] = 0, 109 107 .start_index[PM_SLEEP_MODE_SPC] = 2, 110 108 }; 111 - 112 - static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv); 113 - 114 - typedef int (*idle_fn)(void); 115 - static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops); 116 109 117 110 static inline void spm_register_write(struct spm_driver_data *drv, 118 111 enum spm_reg reg, u32 val) ··· 169 172 return -1; 170 173 } 171 174 172 - static int qcom_cpu_spc(void) 175 + static int qcom_cpu_spc(struct spm_driver_data *drv) 173 176 { 174 177 int ret; 175 - struct spm_driver_data *drv = __this_cpu_read(cpu_spm_drv); 176 178 177 179 spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC); 178 180 ret = cpu_suspend(0, qcom_pm_collapse); ··· 186 190 return ret; 187 191 } 188 192 189 - static int qcom_idle_enter(unsigned long index) 193 + static int spm_enter_idle_state(struct cpuidle_device *dev, 194 + struct cpuidle_driver *drv, int idx) 190 195 { 191 - return __this_cpu_read(qcom_idle_ops)[index](); 196 + struct spm_driver_data *data = container_of(drv, struct spm_driver_data, 197 + cpuidle_driver); 198 + 199 + return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data); 192 200 } 193 201 194 - static const struct of_device_id qcom_idle_state_match[] __initconst = { 195 - { .compatible = "qcom,idle-state-spc", .data = qcom_cpu_spc }, 202 + static struct cpuidle_driver qcom_spm_idle_driver = { 203 + .name = "qcom_spm", 204 + .owner = THIS_MODULE, 205 + .states[0] = { 206 + .enter = spm_enter_idle_state, 207 + .exit_latency = 1, 208 + .target_residency = 1, 209 + .power_usage = UINT_MAX, 210 + .name = "WFI", 211 + .desc = "ARM WFI", 212 + } 213 + }; 214 + 215 + static const struct of_device_id qcom_idle_state_match[] = { 216 + { .compatible = "qcom,idle-state-spc", .data = spm_enter_idle_state }, 196 217 { }, 197 218 }; 198 219 199 - static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu) 220 + static int spm_cpuidle_init(struct cpuidle_driver *drv, int cpu) 200 221 { 201 - const struct of_device_id *match_id; 202 - struct device_node *state_node; 203 - int i; 204 - int state_count = 1; 205 - idle_fn idle_fns[CPUIDLE_STATE_MAX]; 206 - idle_fn *fns; 207 - cpumask_t mask; 208 - bool use_scm_power_down = false; 222 + int ret; 209 223 210 - if (!qcom_scm_is_available()) 211 - return -EPROBE_DEFER; 224 + memcpy(drv, &qcom_spm_idle_driver, sizeof(*drv)); 225 + drv->cpumask = (struct cpumask *)cpumask_of(cpu); 212 226 213 - for (i = 0; ; i++) { 214 - state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); 215 - if (!state_node) 216 - break; 227 + /* Parse idle states from device tree */ 228 + ret = dt_init_idle_driver(drv, qcom_idle_state_match, 1); 229 + if (ret <= 0) 230 + return ret ? : -ENODEV; 217 231 218 - if (!of_device_is_available(state_node)) 219 - continue; 220 - 221 - if (i == CPUIDLE_STATE_MAX) { 222 - pr_warn("%s: cpuidle states reached max possible\n", 223 - __func__); 224 - break; 225 - } 226 - 227 - match_id = of_match_node(qcom_idle_state_match, state_node); 228 - if (!match_id) 229 - return -ENODEV; 230 - 231 - idle_fns[state_count] = match_id->data; 232 - 233 - /* Check if any of the states allow power down */ 234 - if (match_id->data == qcom_cpu_spc) 235 - use_scm_power_down = true; 236 - 237 - state_count++; 238 - } 239 - 240 - if (state_count == 1) 241 - goto check_spm; 242 - 243 - fns = devm_kcalloc(get_cpu_device(cpu), state_count, sizeof(*fns), 244 - GFP_KERNEL); 245 - if (!fns) 246 - return -ENOMEM; 247 - 248 - for (i = 1; i < state_count; i++) 249 - fns[i] = idle_fns[i]; 250 - 251 - if (use_scm_power_down) { 252 - /* We have atleast one power down mode */ 253 - cpumask_clear(&mask); 254 - cpumask_set_cpu(cpu, &mask); 255 - qcom_scm_set_warm_boot_addr(cpu_resume_arm, &mask); 256 - } 257 - 258 - per_cpu(qcom_idle_ops, cpu) = fns; 259 - 260 - /* 261 - * SPM probe for the cpu should have happened by now, if the 262 - * SPM device does not exist, return -ENXIO to indicate that the 263 - * cpu does not support idle states. 264 - */ 265 - check_spm: 266 - return per_cpu(cpu_spm_drv, cpu) ? 0 : -ENXIO; 232 + /* We have atleast one power down mode */ 233 + return qcom_scm_set_warm_boot_addr(cpu_resume_arm, drv->cpumask); 267 234 } 268 - 269 - static const struct cpuidle_ops qcom_cpuidle_ops __initconst = { 270 - .suspend = qcom_idle_enter, 271 - .init = qcom_cpuidle_init, 272 - }; 273 - 274 - CPUIDLE_METHOD_OF_DECLARE(qcom_idle_v1, "qcom,kpss-acc-v1", &qcom_cpuidle_ops); 275 - CPUIDLE_METHOD_OF_DECLARE(qcom_idle_v2, "qcom,kpss-acc-v2", &qcom_cpuidle_ops); 276 235 277 236 static struct spm_driver_data *spm_get_drv(struct platform_device *pdev, 278 237 int *spm_cpu) ··· 274 323 struct resource *res; 275 324 const struct of_device_id *match_id; 276 325 void __iomem *addr; 277 - int cpu; 326 + int cpu, ret; 327 + 328 + if (!qcom_scm_is_available()) 329 + return -EPROBE_DEFER; 278 330 279 331 drv = spm_get_drv(pdev, &cpu); 280 332 if (!drv) 281 333 return -EINVAL; 334 + platform_set_drvdata(pdev, drv); 282 335 283 336 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 284 337 drv->reg_base = devm_ioremap_resource(&pdev->dev, res); ··· 294 339 return -ENODEV; 295 340 296 341 drv->reg_data = match_id->data; 342 + 343 + ret = spm_cpuidle_init(&drv->cpuidle_driver, cpu); 344 + if (ret) 345 + return ret; 297 346 298 347 /* Write the SPM sequences first.. */ 299 348 addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY]; ··· 321 362 /* Set up Standby as the default low power mode */ 322 363 spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); 323 364 324 - per_cpu(cpu_spm_drv, cpu) = drv; 365 + return cpuidle_register(&drv->cpuidle_driver, NULL); 366 + } 325 367 368 + static int spm_dev_remove(struct platform_device *pdev) 369 + { 370 + struct spm_driver_data *drv = platform_get_drvdata(pdev); 371 + 372 + cpuidle_unregister(&drv->cpuidle_driver); 326 373 return 0; 327 374 } 328 375 329 376 static struct platform_driver spm_driver = { 330 377 .probe = spm_dev_probe, 378 + .remove = spm_dev_remove, 331 379 .driver = { 332 380 .name = "saw", 333 381 .of_match_table = spm_match_table,