Lines Matching +full:pwm +full:- +full:0
1 // SPDX-License-Identifier: GPL-2.0-only
8 * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
15 * - The twl6030 hardware only supports two period lengths (128 clock ticks and
17 * - The hardware doesn't support ON = 0, so the active part of a period doesn't
19 * - The hardware could support inverted polarity (with a similar limitation as
21 * - The hardware emits a constant low output when disabled.
22 * - A request for .duty_cycle = 0 results in an output wave with one active
24 * - The driver only implements setting the relative duty cycle.
25 * - The driver doesn't implement .get_state().
31 #include <linux/pwm.h>
36 * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030.
38 * - LEDA uses PWMA
39 * - LEDB uses PWMB
43 #define TWL4030_LED_MAX 0x7f
44 #define TWL6030_LED_MAX 0xff
47 #define TWL4030_LEDEN_REG 0x00
48 #define TWL4030_PWMA_REG 0x01
50 #define TWL4030_LEDXON (1 << 0)
56 #define TWL6030_LED_PWM_CTRL1 0xf4
57 #define TWL6030_LED_PWM_CTRL2 0xf5
59 #define TWL6040_LED_MODE_HW 0x00
60 #define TWL6040_LED_MODE_ON 0x01
61 #define TWL6040_LED_MODE_OFF 0x02
62 #define TWL6040_LED_MODE_MASK 0x03
74 static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm, in twl4030_pwmled_config() argument
78 u8 pwm_config[2] = { 1, 0 }; in twl4030_pwmled_config()
83 * On-cycle is set to 1 (the minimum allowed value) in twl4030_pwmled_config()
84 * The off time of 0 is not configurable, so the mapping is: in twl4030_pwmled_config()
85 * 0 -> off cycle = 2, in twl4030_pwmled_config()
86 * 1 -> off cycle = 2, in twl4030_pwmled_config()
87 * 2 -> off cycle = 3, in twl4030_pwmled_config()
88 * 126 - > off cycle 127, in twl4030_pwmled_config()
89 * 127 - > off cycle 1 in twl4030_pwmled_config()
90 * When on cycle == off cycle the PWM will be always on in twl4030_pwmled_config()
97 base = pwm->hwpwm * 2 + TWL4030_PWMA_REG; in twl4030_pwmled_config()
102 if (ret < 0) in twl4030_pwmled_config()
103 dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label); in twl4030_pwmled_config()
108 static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm) in twl4030_pwmled_enable() argument
114 mutex_lock(&twl->mutex); in twl4030_pwmled_enable()
116 if (ret < 0) { in twl4030_pwmled_enable()
117 dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label); in twl4030_pwmled_enable()
121 val |= TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS); in twl4030_pwmled_enable()
124 if (ret < 0) in twl4030_pwmled_enable()
125 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); in twl4030_pwmled_enable()
128 mutex_unlock(&twl->mutex); in twl4030_pwmled_enable()
133 struct pwm_device *pwm) in twl4030_pwmled_disable() argument
139 mutex_lock(&twl->mutex); in twl4030_pwmled_disable()
141 if (ret < 0) { in twl4030_pwmled_disable()
142 dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label); in twl4030_pwmled_disable()
146 val &= ~TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS); in twl4030_pwmled_disable()
149 if (ret < 0) in twl4030_pwmled_disable()
150 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); in twl4030_pwmled_disable()
153 mutex_unlock(&twl->mutex); in twl4030_pwmled_disable()
156 static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm, in twl4030_pwmled_apply() argument
161 if (state->polarity != PWM_POLARITY_NORMAL) in twl4030_pwmled_apply()
162 return -EINVAL; in twl4030_pwmled_apply()
164 if (!state->enabled) { in twl4030_pwmled_apply()
165 if (pwm->state.enabled) in twl4030_pwmled_apply()
166 twl4030_pwmled_disable(chip, pwm); in twl4030_pwmled_apply()
168 return 0; in twl4030_pwmled_apply()
172 * We cannot skip calling ->config even if state->period == in twl4030_pwmled_apply()
173 * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle in twl4030_pwmled_apply()
175 * pwm_apply_might_sleep because of !state->enabled and so the two values in in twl4030_pwmled_apply()
176 * pwm->state might not be configured in hardware. in twl4030_pwmled_apply()
178 ret = twl4030_pwmled_config(pwm->chip, pwm, in twl4030_pwmled_apply()
179 state->duty_cycle, state->period); in twl4030_pwmled_apply()
183 if (!pwm->state.enabled) in twl4030_pwmled_apply()
184 ret = twl4030_pwmled_enable(chip, pwm); in twl4030_pwmled_apply()
195 static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm, in twl6030_pwmled_config() argument
202 on_time = duty_cycle & 0xff; in twl6030_pwmled_config()
206 if (ret < 0) in twl6030_pwmled_config()
207 dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label); in twl6030_pwmled_config()
212 static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm) in twl6030_pwmled_enable() argument
218 mutex_lock(&twl->mutex); in twl6030_pwmled_enable()
220 if (ret < 0) { in twl6030_pwmled_enable()
221 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", in twl6030_pwmled_enable()
222 pwm->label); in twl6030_pwmled_enable()
230 if (ret < 0) in twl6030_pwmled_enable()
231 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); in twl6030_pwmled_enable()
234 mutex_unlock(&twl->mutex); in twl6030_pwmled_enable()
239 struct pwm_device *pwm) in twl6030_pwmled_disable() argument
245 mutex_lock(&twl->mutex); in twl6030_pwmled_disable()
247 if (ret < 0) { in twl6030_pwmled_disable()
248 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", in twl6030_pwmled_disable()
249 pwm->label); in twl6030_pwmled_disable()
257 if (ret < 0) in twl6030_pwmled_disable()
258 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); in twl6030_pwmled_disable()
261 mutex_unlock(&twl->mutex); in twl6030_pwmled_disable()
264 static int twl6030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm, in twl6030_pwmled_apply() argument
269 if (state->polarity != pwm->state.polarity) in twl6030_pwmled_apply()
270 return -EINVAL; in twl6030_pwmled_apply()
272 if (!state->enabled) { in twl6030_pwmled_apply()
273 if (pwm->state.enabled) in twl6030_pwmled_apply()
274 twl6030_pwmled_disable(chip, pwm); in twl6030_pwmled_apply()
276 return 0; in twl6030_pwmled_apply()
279 err = twl6030_pwmled_config(pwm->chip, pwm, in twl6030_pwmled_apply()
280 state->duty_cycle, state->period); in twl6030_pwmled_apply()
284 if (!pwm->state.enabled) in twl6030_pwmled_apply()
285 err = twl6030_pwmled_enable(chip, pwm); in twl6030_pwmled_apply()
290 static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm) in twl6030_pwmled_request() argument
296 mutex_lock(&twl->mutex); in twl6030_pwmled_request()
298 if (ret < 0) { in twl6030_pwmled_request()
299 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", in twl6030_pwmled_request()
300 pwm->label); in twl6030_pwmled_request()
308 if (ret < 0) in twl6030_pwmled_request()
309 dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label); in twl6030_pwmled_request()
312 mutex_unlock(&twl->mutex); in twl6030_pwmled_request()
316 static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm) in twl6030_pwmled_free() argument
322 mutex_lock(&twl->mutex); in twl6030_pwmled_free()
324 if (ret < 0) { in twl6030_pwmled_free()
325 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", in twl6030_pwmled_free()
326 pwm->label); in twl6030_pwmled_free()
334 if (ret < 0) in twl6030_pwmled_free()
335 dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label); in twl6030_pwmled_free()
338 mutex_unlock(&twl->mutex); in twl6030_pwmled_free()
352 twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL); in twl_pwmled_probe()
354 return -ENOMEM; in twl_pwmled_probe()
357 twl->chip.ops = &twl4030_pwmled_ops; in twl_pwmled_probe()
358 twl->chip.npwm = 2; in twl_pwmled_probe()
360 twl->chip.ops = &twl6030_pwmled_ops; in twl_pwmled_probe()
361 twl->chip.npwm = 1; in twl_pwmled_probe()
364 twl->chip.dev = &pdev->dev; in twl_pwmled_probe()
366 mutex_init(&twl->mutex); in twl_pwmled_probe()
368 return devm_pwmchip_add(&pdev->dev, &twl->chip); in twl_pwmled_probe()
373 { .compatible = "ti,twl4030-pwmled" },
374 { .compatible = "ti,twl6030-pwmled" },
382 .name = "twl-pwmled",
390 MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs");
391 MODULE_ALIAS("platform:twl-pwmled");