18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel Low Power Subsystem PWM controller 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/acpi.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "pwm-lpss.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* BayTrail */ 198c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { 208c2ecf20Sopenharmony_ci .clk_rate = 25000000, 218c2ecf20Sopenharmony_ci .npwm = 1, 228c2ecf20Sopenharmony_ci .base_unit_bits = 16, 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Braswell */ 268c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { 278c2ecf20Sopenharmony_ci .clk_rate = 19200000, 288c2ecf20Sopenharmony_ci .npwm = 1, 298c2ecf20Sopenharmony_ci .base_unit_bits = 16, 308c2ecf20Sopenharmony_ci .other_devices_aml_touches_pwm_regs = true, 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Broxton */ 348c2ecf20Sopenharmony_cistatic const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = { 358c2ecf20Sopenharmony_ci .clk_rate = 19200000, 368c2ecf20Sopenharmony_ci .npwm = 4, 378c2ecf20Sopenharmony_ci .base_unit_bits = 22, 388c2ecf20Sopenharmony_ci .bypass = true, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int pwm_lpss_probe_platform(struct platform_device *pdev) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci const struct pwm_lpss_boardinfo *info; 448c2ecf20Sopenharmony_ci const struct acpi_device_id *id; 458c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm; 468c2ecf20Sopenharmony_ci struct resource *r; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); 498c2ecf20Sopenharmony_ci if (!id) 508c2ecf20Sopenharmony_ci return -ENODEV; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci info = (const struct pwm_lpss_boardinfo *)id->driver_data; 538c2ecf20Sopenharmony_ci r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci lpwm = pwm_lpss_probe(&pdev->dev, r, info); 568c2ecf20Sopenharmony_ci if (IS_ERR(lpwm)) 578c2ecf20Sopenharmony_ci return PTR_ERR(lpwm); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, lpwm); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE); 628c2ecf20Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 638c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int pwm_lpss_remove_platform(struct platform_device *pdev) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 738c2ecf20Sopenharmony_ci return pwm_lpss_remove(lpwm); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int pwm_lpss_prepare(struct device *dev) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * If other device's AML code touches the PWM regs on suspend/resume 828c2ecf20Sopenharmony_ci * force runtime-resume the PWM controller to allow this. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci if (lpwm->info->other_devices_aml_touches_pwm_regs) 858c2ecf20Sopenharmony_ci return 0; /* Force runtime-resume */ 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return 1; /* If runtime-suspended leave as is */ 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const struct dev_pm_ops pwm_lpss_platform_pm_ops = { 918c2ecf20Sopenharmony_ci .prepare = pwm_lpss_prepare, 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic const struct acpi_device_id pwm_lpss_acpi_match[] = { 958c2ecf20Sopenharmony_ci { "80860F09", (unsigned long)&pwm_lpss_byt_info }, 968c2ecf20Sopenharmony_ci { "80862288", (unsigned long)&pwm_lpss_bsw_info }, 978c2ecf20Sopenharmony_ci { "80862289", (unsigned long)&pwm_lpss_bsw_info }, 988c2ecf20Sopenharmony_ci { "80865AC8", (unsigned long)&pwm_lpss_bxt_info }, 998c2ecf20Sopenharmony_ci { }, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic struct platform_driver pwm_lpss_driver_platform = { 1048c2ecf20Sopenharmony_ci .driver = { 1058c2ecf20Sopenharmony_ci .name = "pwm-lpss", 1068c2ecf20Sopenharmony_ci .acpi_match_table = pwm_lpss_acpi_match, 1078c2ecf20Sopenharmony_ci .pm = &pwm_lpss_platform_pm_ops, 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci .probe = pwm_lpss_probe_platform, 1108c2ecf20Sopenharmony_ci .remove = pwm_lpss_remove_platform, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_cimodule_platform_driver(pwm_lpss_driver_platform); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PWM platform driver for Intel LPSS"); 1158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1168c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:pwm-lpss"); 117