1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Intel Low Power Subsystem PWM controller driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2014, Intel Corporation
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Derived from the original pwm-lpss.c
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/acpi.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "pwm-lpss.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* BayTrail */
19*4882a593Smuzhiyun static const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
20*4882a593Smuzhiyun .clk_rate = 25000000,
21*4882a593Smuzhiyun .npwm = 1,
22*4882a593Smuzhiyun .base_unit_bits = 16,
23*4882a593Smuzhiyun };
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* Braswell */
26*4882a593Smuzhiyun static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
27*4882a593Smuzhiyun .clk_rate = 19200000,
28*4882a593Smuzhiyun .npwm = 1,
29*4882a593Smuzhiyun .base_unit_bits = 16,
30*4882a593Smuzhiyun .other_devices_aml_touches_pwm_regs = true,
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /* Broxton */
34*4882a593Smuzhiyun static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
35*4882a593Smuzhiyun .clk_rate = 19200000,
36*4882a593Smuzhiyun .npwm = 4,
37*4882a593Smuzhiyun .base_unit_bits = 22,
38*4882a593Smuzhiyun .bypass = true,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
pwm_lpss_probe_platform(struct platform_device * pdev)41*4882a593Smuzhiyun static int pwm_lpss_probe_platform(struct platform_device *pdev)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun const struct pwm_lpss_boardinfo *info;
44*4882a593Smuzhiyun const struct acpi_device_id *id;
45*4882a593Smuzhiyun struct pwm_lpss_chip *lpwm;
46*4882a593Smuzhiyun struct resource *r;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
49*4882a593Smuzhiyun if (!id)
50*4882a593Smuzhiyun return -ENODEV;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun info = (const struct pwm_lpss_boardinfo *)id->driver_data;
53*4882a593Smuzhiyun r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun lpwm = pwm_lpss_probe(&pdev->dev, r, info);
56*4882a593Smuzhiyun if (IS_ERR(lpwm))
57*4882a593Smuzhiyun return PTR_ERR(lpwm);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun platform_set_drvdata(pdev, lpwm);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE);
62*4882a593Smuzhiyun pm_runtime_set_active(&pdev->dev);
63*4882a593Smuzhiyun pm_runtime_enable(&pdev->dev);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
pwm_lpss_remove_platform(struct platform_device * pdev)68*4882a593Smuzhiyun static int pwm_lpss_remove_platform(struct platform_device *pdev)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun pm_runtime_disable(&pdev->dev);
73*4882a593Smuzhiyun return pwm_lpss_remove(lpwm);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
pwm_lpss_prepare(struct device * dev)76*4882a593Smuzhiyun static int pwm_lpss_prepare(struct device *dev)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun * If other device's AML code touches the PWM regs on suspend/resume
82*4882a593Smuzhiyun * force runtime-resume the PWM controller to allow this.
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun if (lpwm->info->other_devices_aml_touches_pwm_regs)
85*4882a593Smuzhiyun return 0; /* Force runtime-resume */
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return 1; /* If runtime-suspended leave as is */
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun static const struct dev_pm_ops pwm_lpss_platform_pm_ops = {
91*4882a593Smuzhiyun .prepare = pwm_lpss_prepare,
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun static const struct acpi_device_id pwm_lpss_acpi_match[] = {
95*4882a593Smuzhiyun { "80860F09", (unsigned long)&pwm_lpss_byt_info },
96*4882a593Smuzhiyun { "80862288", (unsigned long)&pwm_lpss_bsw_info },
97*4882a593Smuzhiyun { "80862289", (unsigned long)&pwm_lpss_bsw_info },
98*4882a593Smuzhiyun { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
99*4882a593Smuzhiyun { },
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun static struct platform_driver pwm_lpss_driver_platform = {
104*4882a593Smuzhiyun .driver = {
105*4882a593Smuzhiyun .name = "pwm-lpss",
106*4882a593Smuzhiyun .acpi_match_table = pwm_lpss_acpi_match,
107*4882a593Smuzhiyun .pm = &pwm_lpss_platform_pm_ops,
108*4882a593Smuzhiyun },
109*4882a593Smuzhiyun .probe = pwm_lpss_probe_platform,
110*4882a593Smuzhiyun .remove = pwm_lpss_remove_platform,
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun module_platform_driver(pwm_lpss_driver_platform);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun MODULE_DESCRIPTION("PWM platform driver for Intel LPSS");
115*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
116*4882a593Smuzhiyun MODULE_ALIAS("platform:pwm-lpss");
117