Merge tag 'pci-v6.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
[linux-2.6-microblaze.git] / drivers / pwm / pwm-lpss-platform.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Intel Low Power Subsystem PWM controller driver
4  *
5  * Copyright (C) 2014, Intel Corporation
6  *
7  * Derived from the original pwm-lpss.c
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/property.h>
16
17 #include "pwm-lpss.h"
18
19
20 static int pwm_lpss_probe_platform(struct platform_device *pdev)
21 {
22         const struct pwm_lpss_boardinfo *info;
23         struct pwm_chip *chip;
24         void __iomem *base;
25
26         info = device_get_match_data(&pdev->dev);
27         if (!info)
28                 return -ENODEV;
29
30         base = devm_platform_ioremap_resource(pdev, 0);
31         if (IS_ERR(base))
32                 return PTR_ERR(base);
33
34         chip = devm_pwm_lpss_probe(&pdev->dev, base, info);
35         if (IS_ERR(chip))
36                 return PTR_ERR(chip);
37
38         /*
39          * On Cherry Trail devices the GFX0._PS0 AML checks if the controller
40          * is on and if it is not on it turns it on and restores what it
41          * believes is the correct state to the PWM controller.
42          * Because of this we must disallow direct-complete, which keeps the
43          * controller (runtime)suspended on resume, to avoid 2 issues:
44          * 1. The controller getting turned on without the linux-pm code
45          *    knowing about this. On devices where the controller is unused
46          *    this causes it to stay on during the next suspend causing high
47          *    battery drain (because S0i3 is not reached)
48          * 2. The state restoring code unexpectedly messing with the controller
49          *
50          * Leaving the controller runtime-suspended (skipping runtime-resume +
51          * normal-suspend) during suspend is fine.
52          */
53         if (info->other_devices_aml_touches_pwm_regs)
54                 dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NO_DIRECT_COMPLETE|
55                                                     DPM_FLAG_SMART_SUSPEND);
56
57         pm_runtime_set_active(&pdev->dev);
58         pm_runtime_enable(&pdev->dev);
59
60         return 0;
61 }
62
63 static void pwm_lpss_remove_platform(struct platform_device *pdev)
64 {
65         pm_runtime_disable(&pdev->dev);
66 }
67
68 static const struct acpi_device_id pwm_lpss_acpi_match[] = {
69         { "80860F09", (unsigned long)&pwm_lpss_byt_info },
70         { "80862288", (unsigned long)&pwm_lpss_bsw_info },
71         { "80862289", (unsigned long)&pwm_lpss_bsw_info },
72         { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
73         { },
74 };
75 MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
76
77 static struct platform_driver pwm_lpss_driver_platform = {
78         .driver = {
79                 .name = "pwm-lpss",
80                 .acpi_match_table = pwm_lpss_acpi_match,
81         },
82         .probe = pwm_lpss_probe_platform,
83         .remove_new = pwm_lpss_remove_platform,
84 };
85 module_platform_driver(pwm_lpss_driver_platform);
86
87 MODULE_DESCRIPTION("PWM platform driver for Intel LPSS");
88 MODULE_LICENSE("GPL v2");
89 MODULE_IMPORT_NS(PWM_LPSS);
90 MODULE_ALIAS("platform:pwm-lpss");