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