18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Intel Low Power Subsystem PWM controller PCI driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014, Intel Corporation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Derived from the original pwm-lpss.c
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/pci.h>
138c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "pwm-lpss.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* BayTrail */
188c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
198c2ecf20Sopenharmony_ci	.clk_rate = 25000000,
208c2ecf20Sopenharmony_ci	.npwm = 1,
218c2ecf20Sopenharmony_ci	.base_unit_bits = 16,
228c2ecf20Sopenharmony_ci};
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Braswell */
258c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
268c2ecf20Sopenharmony_ci	.clk_rate = 19200000,
278c2ecf20Sopenharmony_ci	.npwm = 1,
288c2ecf20Sopenharmony_ci	.base_unit_bits = 16,
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* Broxton */
328c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
338c2ecf20Sopenharmony_ci	.clk_rate = 19200000,
348c2ecf20Sopenharmony_ci	.npwm = 4,
358c2ecf20Sopenharmony_ci	.base_unit_bits = 22,
368c2ecf20Sopenharmony_ci	.bypass = true,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Tangier */
408c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_tng_info = {
418c2ecf20Sopenharmony_ci	.clk_rate = 19200000,
428c2ecf20Sopenharmony_ci	.npwm = 4,
438c2ecf20Sopenharmony_ci	.base_unit_bits = 22,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int pwm_lpss_probe_pci(struct pci_dev *pdev,
478c2ecf20Sopenharmony_ci			      const struct pci_device_id *id)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	const struct pwm_lpss_boardinfo *info;
508c2ecf20Sopenharmony_ci	struct pwm_lpss_chip *lpwm;
518c2ecf20Sopenharmony_ci	int err;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	err = pcim_enable_device(pdev);
548c2ecf20Sopenharmony_ci	if (err < 0)
558c2ecf20Sopenharmony_ci		return err;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	info = (struct pwm_lpss_boardinfo *)id->driver_data;
588c2ecf20Sopenharmony_ci	lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info);
598c2ecf20Sopenharmony_ci	if (IS_ERR(lpwm))
608c2ecf20Sopenharmony_ci		return PTR_ERR(lpwm);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, lpwm);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	pm_runtime_put(&pdev->dev);
658c2ecf20Sopenharmony_ci	pm_runtime_allow(&pdev->dev);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return 0;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void pwm_lpss_remove_pci(struct pci_dev *pdev)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	pm_runtime_forbid(&pdev->dev);
758c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	pwm_lpss_remove(lpwm);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
818c2ecf20Sopenharmony_cistatic int pwm_lpss_runtime_suspend_pci(struct device *dev)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	/*
848c2ecf20Sopenharmony_ci	 * The PCI core will handle transition to D3 automatically. We only
858c2ecf20Sopenharmony_ci	 * need to provide runtime PM hooks for that to happen.
868c2ecf20Sopenharmony_ci	 */
878c2ecf20Sopenharmony_ci	return 0;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int pwm_lpss_runtime_resume_pci(struct device *dev)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return 0;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci#endif
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic const struct dev_pm_ops pwm_lpss_pci_pm = {
978c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(pwm_lpss_runtime_suspend_pci,
988c2ecf20Sopenharmony_ci			   pwm_lpss_runtime_resume_pci, NULL)
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const struct pci_device_id pwm_lpss_pci_ids[] = {
1028c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info},
1038c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info},
1048c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info},
1058c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x11a5), (unsigned long)&pwm_lpss_tng_info},
1068c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
1078c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
1088c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
1098c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x31c8), (unsigned long)&pwm_lpss_bxt_info},
1108c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info},
1118c2ecf20Sopenharmony_ci	{ },
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic struct pci_driver pwm_lpss_driver_pci = {
1168c2ecf20Sopenharmony_ci	.name = "pwm-lpss",
1178c2ecf20Sopenharmony_ci	.id_table = pwm_lpss_pci_ids,
1188c2ecf20Sopenharmony_ci	.probe = pwm_lpss_probe_pci,
1198c2ecf20Sopenharmony_ci	.remove = pwm_lpss_remove_pci,
1208c2ecf20Sopenharmony_ci	.driver = {
1218c2ecf20Sopenharmony_ci		.pm = &pwm_lpss_pci_pm,
1228c2ecf20Sopenharmony_ci	},
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_cimodule_pci_driver(pwm_lpss_driver_pci);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PWM PCI driver for Intel LPSS");
1278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
128