xref: /OK3568_Linux_fs/kernel/drivers/pwm/pwm-lpss-platform.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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