1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * drivers/pwm/pwm-pxa.c 4 * 5 * simple driver for PWM (Pulse Width Modulator) controller 6 * 7 * 2008-02-13 initial version 8 * eric miao <eric.miao@marvell.com> 9 */ 10 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/platform_device.h> 14 #include <linux/slab.h> 15 #include <linux/err.h> 16 #include <linux/clk.h> 17 #include <linux/io.h> 18 #include <linux/pwm.h> 19 #include <linux/of_device.h> 20 21 #include <asm/div64.h> 22 23 #define HAS_SECONDARY_PWM 0x10 24 25 static const struct platform_device_id pwm_id_table[] = { 26 /* PWM has_secondary_pwm? */ 27 { "pxa25x-pwm", 0 }, 28 { "pxa27x-pwm", HAS_SECONDARY_PWM }, 29 { "pxa168-pwm", 0 }, 30 { "pxa910-pwm", 0 }, 31 { }, 32 }; 33 MODULE_DEVICE_TABLE(platform, pwm_id_table); 34 35 /* PWM registers and bits definitions */ 36 #define PWMCR (0x00) 37 #define PWMDCR (0x04) 38 #define PWMPCR (0x08) 39 40 #define PWMCR_SD (1 << 6) 41 #define PWMDCR_FD (1 << 10) 42 43 struct pxa_pwm_chip { 44 struct pwm_chip chip; 45 struct device *dev; 46 47 struct clk *clk; 48 void __iomem *mmio_base; 49 }; 50 51 static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip) 52 { 53 return container_of(chip, struct pxa_pwm_chip, chip); 54 } 55 56 /* 57 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE 58 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE 59 */ 60 static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 61 int duty_ns, int period_ns) 62 { 63 struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); 64 unsigned long long c; 65 unsigned long period_cycles, prescale, pv, dc; 66 unsigned long offset; 67 int rc; 68 69 offset = pwm->hwpwm ? 0x10 : 0; 70 71 c = clk_get_rate(pc->clk); 72 c = c * period_ns; 73 do_div(c, 1000000000); 74 period_cycles = c; 75 76 if (period_cycles < 1) 77 period_cycles = 1; 78 prescale = (period_cycles - 1) / 1024; 79 pv = period_cycles / (prescale + 1) - 1; 80 81 if (prescale > 63) 82 return -EINVAL; 83 84 if (duty_ns == period_ns) 85 dc = PWMDCR_FD; 86 else 87 dc = (pv + 1) * duty_ns / period_ns; 88 89 /* NOTE: the clock to PWM has to be enabled first 90 * before writing to the registers 91 */ 92 rc = clk_prepare_enable(pc->clk); 93 if (rc < 0) 94 return rc; 95 96 writel(prescale, pc->mmio_base + offset + PWMCR); 97 writel(dc, pc->mmio_base + offset + PWMDCR); 98 writel(pv, pc->mmio_base + offset + PWMPCR); 99 100 clk_disable_unprepare(pc->clk); 101 return 0; 102 } 103 104 static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 105 { 106 struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); 107 108 return clk_prepare_enable(pc->clk); 109 } 110 111 static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 112 { 113 struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); 114 115 clk_disable_unprepare(pc->clk); 116 } 117 118 static const struct pwm_ops pxa_pwm_ops = { 119 .config = pxa_pwm_config, 120 .enable = pxa_pwm_enable, 121 .disable = pxa_pwm_disable, 122 .owner = THIS_MODULE, 123 }; 124 125 #ifdef CONFIG_OF 126 /* 127 * Device tree users must create one device instance for each PWM channel. 128 * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver 129 * code that this is a single channel pxa25x-pwm. Currently all devices are 130 * supported identically. 131 */ 132 static const struct of_device_id pwm_of_match[] = { 133 { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, 134 { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, 135 { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, 136 { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]}, 137 { } 138 }; 139 MODULE_DEVICE_TABLE(of, pwm_of_match); 140 #else 141 #define pwm_of_match NULL 142 #endif 143 144 static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev) 145 { 146 const struct of_device_id *id = of_match_device(pwm_of_match, dev); 147 148 return id ? id->data : NULL; 149 } 150 151 static struct pwm_device * 152 pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) 153 { 154 struct pwm_device *pwm; 155 156 pwm = pwm_request_from_chip(pc, 0, NULL); 157 if (IS_ERR(pwm)) 158 return pwm; 159 160 pwm->args.period = args->args[0]; 161 162 return pwm; 163 } 164 165 static int pwm_probe(struct platform_device *pdev) 166 { 167 const struct platform_device_id *id = platform_get_device_id(pdev); 168 struct pxa_pwm_chip *pc; 169 int ret = 0; 170 171 if (IS_ENABLED(CONFIG_OF) && id == NULL) 172 id = pxa_pwm_get_id_dt(&pdev->dev); 173 174 if (id == NULL) 175 return -EINVAL; 176 177 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 178 if (pc == NULL) 179 return -ENOMEM; 180 181 pc->clk = devm_clk_get(&pdev->dev, NULL); 182 if (IS_ERR(pc->clk)) 183 return PTR_ERR(pc->clk); 184 185 pc->chip.dev = &pdev->dev; 186 pc->chip.ops = &pxa_pwm_ops; 187 pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; 188 189 if (IS_ENABLED(CONFIG_OF)) { 190 pc->chip.of_xlate = pxa_pwm_of_xlate; 191 pc->chip.of_pwm_n_cells = 1; 192 } 193 194 pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); 195 if (IS_ERR(pc->mmio_base)) 196 return PTR_ERR(pc->mmio_base); 197 198 ret = pwmchip_add(&pc->chip); 199 if (ret < 0) { 200 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 201 return ret; 202 } 203 204 platform_set_drvdata(pdev, pc); 205 return 0; 206 } 207 208 static int pwm_remove(struct platform_device *pdev) 209 { 210 struct pxa_pwm_chip *pc; 211 212 pc = platform_get_drvdata(pdev); 213 214 return pwmchip_remove(&pc->chip); 215 } 216 217 static struct platform_driver pwm_driver = { 218 .driver = { 219 .name = "pxa25x-pwm", 220 .of_match_table = pwm_of_match, 221 }, 222 .probe = pwm_probe, 223 .remove = pwm_remove, 224 .id_table = pwm_id_table, 225 }; 226 227 module_platform_driver(pwm_driver); 228 229 MODULE_LICENSE("GPL v2"); 230