1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 4 * JZ4740 platform PWM support 5 * 6 * Limitations: 7 * - The .apply callback doesn't complete the currently running period before 8 * reconfiguring the hardware. 9 * - Each period starts with the inactive part. 10 */ 11 12 #include <linux/clk.h> 13 #include <linux/err.h> 14 #include <linux/gpio.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/of_device.h> 18 #include <linux/platform_device.h> 19 #include <linux/pwm.h> 20 21 #include <asm/mach-jz4740/timer.h> 22 23 #define NUM_PWM 8 24 25 struct jz4740_pwm_chip { 26 struct pwm_chip chip; 27 struct clk *clk; 28 }; 29 30 static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) 31 { 32 return container_of(chip, struct jz4740_pwm_chip, chip); 33 } 34 35 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 36 { 37 /* 38 * Timers 0 and 1 are used for system tasks, so they are unavailable 39 * for use as PWMs. 40 */ 41 if (pwm->hwpwm < 2) 42 return -EBUSY; 43 44 jz4740_timer_start(pwm->hwpwm); 45 46 return 0; 47 } 48 49 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 50 { 51 jz4740_timer_set_ctrl(pwm->hwpwm, 0); 52 53 jz4740_timer_stop(pwm->hwpwm); 54 } 55 56 static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 57 { 58 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm); 59 60 ctrl |= JZ_TIMER_CTRL_PWM_ENABLE; 61 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); 62 jz4740_timer_enable(pwm->hwpwm); 63 64 return 0; 65 } 66 67 static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 68 { 69 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm); 70 71 /* 72 * Set duty > period. This trick allows the TCU channels in TCU2 mode to 73 * properly return to their init level. 74 */ 75 jz4740_timer_set_duty(pwm->hwpwm, 0xffff); 76 jz4740_timer_set_period(pwm->hwpwm, 0x0); 77 78 /* 79 * Disable PWM output. 80 * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the 81 * counter is stopped, while in TCU1 mode the order does not matter. 82 */ 83 ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE; 84 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); 85 86 /* Stop counter */ 87 jz4740_timer_disable(pwm->hwpwm); 88 } 89 90 static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 91 const struct pwm_state *state) 92 { 93 struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); 94 unsigned long long tmp; 95 unsigned long period, duty; 96 unsigned int prescaler = 0; 97 uint16_t ctrl; 98 99 tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period; 100 do_div(tmp, 1000000000); 101 period = tmp; 102 103 while (period > 0xffff && prescaler < 6) { 104 period >>= 2; 105 ++prescaler; 106 } 107 108 if (prescaler == 6) 109 return -EINVAL; 110 111 tmp = (unsigned long long)period * state->duty_cycle; 112 do_div(tmp, state->period); 113 duty = period - tmp; 114 115 if (duty >= period) 116 duty = period - 1; 117 118 jz4740_pwm_disable(chip, pwm); 119 120 jz4740_timer_set_count(pwm->hwpwm, 0); 121 jz4740_timer_set_duty(pwm->hwpwm, duty); 122 jz4740_timer_set_period(pwm->hwpwm, period); 123 124 ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT | 125 JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN; 126 127 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); 128 129 switch (state->polarity) { 130 case PWM_POLARITY_NORMAL: 131 ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW; 132 break; 133 case PWM_POLARITY_INVERSED: 134 ctrl |= JZ_TIMER_CTRL_PWM_ACTIVE_LOW; 135 break; 136 } 137 138 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); 139 140 if (state->enabled) 141 jz4740_pwm_enable(chip, pwm); 142 143 return 0; 144 } 145 146 static const struct pwm_ops jz4740_pwm_ops = { 147 .request = jz4740_pwm_request, 148 .free = jz4740_pwm_free, 149 .apply = jz4740_pwm_apply, 150 .owner = THIS_MODULE, 151 }; 152 153 static int jz4740_pwm_probe(struct platform_device *pdev) 154 { 155 struct jz4740_pwm_chip *jz4740; 156 157 jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL); 158 if (!jz4740) 159 return -ENOMEM; 160 161 jz4740->clk = devm_clk_get(&pdev->dev, "ext"); 162 if (IS_ERR(jz4740->clk)) 163 return PTR_ERR(jz4740->clk); 164 165 jz4740->chip.dev = &pdev->dev; 166 jz4740->chip.ops = &jz4740_pwm_ops; 167 jz4740->chip.npwm = NUM_PWM; 168 jz4740->chip.base = -1; 169 jz4740->chip.of_xlate = of_pwm_xlate_with_flags; 170 jz4740->chip.of_pwm_n_cells = 3; 171 172 platform_set_drvdata(pdev, jz4740); 173 174 return pwmchip_add(&jz4740->chip); 175 } 176 177 static int jz4740_pwm_remove(struct platform_device *pdev) 178 { 179 struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev); 180 181 return pwmchip_remove(&jz4740->chip); 182 } 183 184 #ifdef CONFIG_OF 185 static const struct of_device_id jz4740_pwm_dt_ids[] = { 186 { .compatible = "ingenic,jz4740-pwm", }, 187 {}, 188 }; 189 MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); 190 #endif 191 192 static struct platform_driver jz4740_pwm_driver = { 193 .driver = { 194 .name = "jz4740-pwm", 195 .of_match_table = of_match_ptr(jz4740_pwm_dt_ids), 196 }, 197 .probe = jz4740_pwm_probe, 198 .remove = jz4740_pwm_remove, 199 }; 200 module_platform_driver(jz4740_pwm_driver); 201 202 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 203 MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver"); 204 MODULE_ALIAS("platform:jz4740-pwm"); 205 MODULE_LICENSE("GPL"); 206