1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * DesignWare PWM Controller driver (PCI part) 4 * 5 * Copyright (C) 2018-2020 Intel Corporation 6 * 7 * Author: Felipe Balbi (Intel) 8 * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com> 9 * Author: Raymond Tan <raymond.tan@intel.com> 10 * 11 * Limitations: 12 * - The hardware cannot generate a 0 % or 100 % duty cycle. Both high and low 13 * periods are one or more input clock periods long. 14 */ 15 16 #define DEFAULT_MOUDLE_NAMESPACE dwc_pwm 17 18 #include <linux/bitops.h> 19 #include <linux/export.h> 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/pci.h> 23 #include <linux/pm_runtime.h> 24 #include <linux/pwm.h> 25 26 #include "pwm-dwc.h" 27 28 /* Elkhart Lake */ 29 static const struct dwc_pwm_info ehl_pwm_info = { 30 .nr = 2, 31 .size = 0x1000, 32 }; 33 34 static int dwc_pwm_init_one(struct device *dev, struct dwc_pwm_drvdata *ddata, unsigned int idx) 35 { 36 struct pwm_chip *chip; 37 struct dwc_pwm *dwc; 38 int ret; 39 40 chip = dwc_pwm_alloc(dev); 41 if (IS_ERR(chip)) 42 return PTR_ERR(chip); 43 44 dwc = to_dwc_pwm(chip); 45 dwc->base = ddata->io_base + (ddata->info->size * idx); 46 47 ret = devm_pwmchip_add(dev, chip); 48 if (ret) 49 return ret; 50 51 ddata->chips[idx] = chip; 52 return 0; 53 } 54 55 static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id) 56 { 57 const struct dwc_pwm_info *info; 58 struct device *dev = &pci->dev; 59 struct dwc_pwm_drvdata *ddata; 60 unsigned int idx; 61 int ret; 62 63 ret = pcim_enable_device(pci); 64 if (ret) 65 return dev_err_probe(dev, ret, "Failed to enable device\n"); 66 67 pci_set_master(pci); 68 69 ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci)); 70 if (ret) 71 return dev_err_probe(dev, ret, "Failed to iomap PCI BAR\n"); 72 73 info = (const struct dwc_pwm_info *)id->driver_data; 74 ddata = devm_kzalloc(dev, struct_size(ddata, chips, info->nr), GFP_KERNEL); 75 if (!ddata) 76 return -ENOMEM; 77 78 /* 79 * No need to check for pcim_iomap_table() failure, 80 * pcim_iomap_regions() already does it for us. 81 */ 82 ddata->io_base = pcim_iomap_table(pci)[0]; 83 ddata->info = info; 84 85 for (idx = 0; idx < ddata->info->nr; idx++) { 86 ret = dwc_pwm_init_one(dev, ddata, idx); 87 if (ret) 88 return ret; 89 } 90 91 dev_set_drvdata(dev, ddata); 92 93 pm_runtime_put(dev); 94 pm_runtime_allow(dev); 95 96 return 0; 97 } 98 99 static void dwc_pwm_remove(struct pci_dev *pci) 100 { 101 pm_runtime_forbid(&pci->dev); 102 pm_runtime_get_noresume(&pci->dev); 103 } 104 105 static int dwc_pwm_suspend(struct device *dev) 106 { 107 struct dwc_pwm_drvdata *ddata = dev_get_drvdata(dev); 108 unsigned int idx; 109 110 for (idx = 0; idx < ddata->info->nr; idx++) { 111 struct pwm_chip *chip = ddata->chips[idx]; 112 struct dwc_pwm *dwc = to_dwc_pwm(chip); 113 unsigned int i; 114 115 for (i = 0; i < DWC_TIMERS_TOTAL; i++) { 116 if (chip->pwms[i].state.enabled) { 117 dev_err(dev, "PWM %u in use by consumer (%s)\n", 118 i, chip->pwms[i].label); 119 return -EBUSY; 120 } 121 dwc->ctx[i].cnt = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i)); 122 dwc->ctx[i].cnt2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(i)); 123 dwc->ctx[i].ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(i)); 124 } 125 } 126 127 return 0; 128 } 129 130 static int dwc_pwm_resume(struct device *dev) 131 { 132 struct dwc_pwm_drvdata *ddata = dev_get_drvdata(dev); 133 unsigned int idx; 134 135 for (idx = 0; idx < ddata->info->nr; idx++) { 136 struct pwm_chip *chip = ddata->chips[idx]; 137 struct dwc_pwm *dwc = to_dwc_pwm(chip); 138 unsigned int i; 139 140 for (i = 0; i < DWC_TIMERS_TOTAL; i++) { 141 dwc_pwm_writel(dwc, dwc->ctx[i].cnt, DWC_TIM_LD_CNT(i)); 142 dwc_pwm_writel(dwc, dwc->ctx[i].cnt2, DWC_TIM_LD_CNT2(i)); 143 dwc_pwm_writel(dwc, dwc->ctx[i].ctrl, DWC_TIM_CTRL(i)); 144 } 145 } 146 147 return 0; 148 } 149 150 static DEFINE_SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume); 151 152 static const struct pci_device_id dwc_pwm_id_table[] = { 153 { PCI_VDEVICE(INTEL, 0x4bb7), (kernel_ulong_t)&ehl_pwm_info }, 154 { } /* Terminating Entry */ 155 }; 156 MODULE_DEVICE_TABLE(pci, dwc_pwm_id_table); 157 158 static struct pci_driver dwc_pwm_driver = { 159 .name = "pwm-dwc", 160 .probe = dwc_pwm_probe, 161 .remove = dwc_pwm_remove, 162 .id_table = dwc_pwm_id_table, 163 .driver = { 164 .pm = pm_sleep_ptr(&dwc_pwm_pm_ops), 165 }, 166 }; 167 168 module_pci_driver(dwc_pwm_driver); 169 170 MODULE_AUTHOR("Felipe Balbi (Intel)"); 171 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); 172 MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>"); 173 MODULE_DESCRIPTION("DesignWare PWM Controller"); 174 MODULE_LICENSE("GPL"); 175