| // SPDX-License-Identifier: GPL-2.0-only | 
 | /* | 
 |  * sl28cpld PWM driver | 
 |  * | 
 |  * Copyright (c) 2020 Michael Walle <michael@walle.cc> | 
 |  * | 
 |  * There is no public datasheet available for this PWM core. But it is easy | 
 |  * enough to be briefly explained. It consists of one 8-bit counter. The PWM | 
 |  * supports four distinct frequencies by selecting when to reset the counter. | 
 |  * With the prescaler setting you can select which bit of the counter is used | 
 |  * to reset it. This implies that the higher the frequency the less remaining | 
 |  * bits are available for the actual counter. | 
 |  * | 
 |  * Let cnt[7:0] be the counter, clocked at 32kHz: | 
 |  * +-----------+--------+--------------+-----------+---------------+ | 
 |  * | prescaler |  reset | counter bits | frequency | period length | | 
 |  * +-----------+--------+--------------+-----------+---------------+ | 
 |  * |         0 | cnt[7] |     cnt[6:0] |    250 Hz |    4000000 ns | | 
 |  * |         1 | cnt[6] |     cnt[5:0] |    500 Hz |    2000000 ns | | 
 |  * |         2 | cnt[5] |     cnt[4:0] |     1 kHz |    1000000 ns | | 
 |  * |         3 | cnt[4] |     cnt[3:0] |     2 kHz |     500000 ns | | 
 |  * +-----------+--------+--------------+-----------+---------------+ | 
 |  * | 
 |  * Limitations: | 
 |  * - The hardware cannot generate a 100% duty cycle if the prescaler is 0. | 
 |  * - The hardware cannot atomically set the prescaler and the counter value, | 
 |  *   which might lead to glitches and inconsistent states if a write fails. | 
 |  * - The counter is not reset if you switch the prescaler which leads | 
 |  *   to glitches, too. | 
 |  * - The duty cycle will switch immediately and not after a complete cycle. | 
 |  * - Depending on the actual implementation, disabling the PWM might have | 
 |  *   side effects. For example, if the output pin is shared with a GPIO pin | 
 |  *   it will automatically switch back to GPIO mode. | 
 |  */ | 
 |  | 
 | #include <linux/bitfield.h> | 
 | #include <linux/kernel.h> | 
 | #include <linux/mod_devicetable.h> | 
 | #include <linux/module.h> | 
 | #include <linux/platform_device.h> | 
 | #include <linux/property.h> | 
 | #include <linux/pwm.h> | 
 | #include <linux/regmap.h> | 
 |  | 
 | /* | 
 |  * PWM timer block registers. | 
 |  */ | 
 | #define SL28CPLD_PWM_CTRL			0x00 | 
 | #define   SL28CPLD_PWM_CTRL_ENABLE		BIT(7) | 
 | #define   SL28CPLD_PWM_CTRL_PRESCALER_MASK	GENMASK(1, 0) | 
 | #define SL28CPLD_PWM_CYCLE			0x01 | 
 | #define   SL28CPLD_PWM_CYCLE_MAX		GENMASK(6, 0) | 
 |  | 
 | #define SL28CPLD_PWM_CLK			32000 /* 32 kHz */ | 
 | #define SL28CPLD_PWM_MAX_DUTY_CYCLE(prescaler)	(1 << (7 - (prescaler))) | 
 | #define SL28CPLD_PWM_PERIOD(prescaler) \ | 
 | 	(NSEC_PER_SEC / SL28CPLD_PWM_CLK * SL28CPLD_PWM_MAX_DUTY_CYCLE(prescaler)) | 
 |  | 
 | /* | 
 |  * We calculate the duty cycle like this: | 
 |  *   duty_cycle_ns = pwm_cycle_reg * max_period_ns / max_duty_cycle | 
 |  * | 
 |  * With | 
 |  *   max_period_ns = 1 << (7 - prescaler) / SL28CPLD_PWM_CLK * NSEC_PER_SEC | 
 |  *   max_duty_cycle = 1 << (7 - prescaler) | 
 |  * this then simplifies to: | 
 |  *   duty_cycle_ns = pwm_cycle_reg / SL28CPLD_PWM_CLK * NSEC_PER_SEC | 
 |  *                 = NSEC_PER_SEC / SL28CPLD_PWM_CLK * pwm_cycle_reg | 
 |  * | 
 |  * NSEC_PER_SEC is a multiple of SL28CPLD_PWM_CLK, therefore we're not losing | 
 |  * precision by doing the divison first. | 
 |  */ | 
 | #define SL28CPLD_PWM_TO_DUTY_CYCLE(reg) \ | 
 | 	(NSEC_PER_SEC / SL28CPLD_PWM_CLK * (reg)) | 
 | #define SL28CPLD_PWM_FROM_DUTY_CYCLE(duty_cycle) \ | 
 | 	(DIV_ROUND_DOWN_ULL((duty_cycle), NSEC_PER_SEC / SL28CPLD_PWM_CLK)) | 
 |  | 
 | #define sl28cpld_pwm_read(priv, reg, val) \ | 
 | 	regmap_read((priv)->regmap, (priv)->offset + (reg), (val)) | 
 | #define sl28cpld_pwm_write(priv, reg, val) \ | 
 | 	regmap_write((priv)->regmap, (priv)->offset + (reg), (val)) | 
 |  | 
 | struct sl28cpld_pwm { | 
 | 	struct regmap *regmap; | 
 | 	u32 offset; | 
 | }; | 
 |  | 
 | static inline struct sl28cpld_pwm *sl28cpld_pwm_from_chip(struct pwm_chip *chip) | 
 | { | 
 | 	return pwmchip_get_drvdata(chip); | 
 | } | 
 |  | 
 | static int sl28cpld_pwm_get_state(struct pwm_chip *chip, | 
 | 				  struct pwm_device *pwm, | 
 | 				  struct pwm_state *state) | 
 | { | 
 | 	struct sl28cpld_pwm *priv = sl28cpld_pwm_from_chip(chip); | 
 | 	unsigned int reg; | 
 | 	int prescaler; | 
 |  | 
 | 	sl28cpld_pwm_read(priv, SL28CPLD_PWM_CTRL, ®); | 
 |  | 
 | 	state->enabled = reg & SL28CPLD_PWM_CTRL_ENABLE; | 
 |  | 
 | 	prescaler = FIELD_GET(SL28CPLD_PWM_CTRL_PRESCALER_MASK, reg); | 
 | 	state->period = SL28CPLD_PWM_PERIOD(prescaler); | 
 |  | 
 | 	sl28cpld_pwm_read(priv, SL28CPLD_PWM_CYCLE, ®); | 
 | 	state->duty_cycle = SL28CPLD_PWM_TO_DUTY_CYCLE(reg); | 
 | 	state->polarity = PWM_POLARITY_NORMAL; | 
 |  | 
 | 	/* | 
 | 	 * Sanitize values for the PWM core. Depending on the prescaler it | 
 | 	 * might happen that we calculate a duty_cycle greater than the actual | 
 | 	 * period. This might happen if someone (e.g. the bootloader) sets an | 
 | 	 * invalid combination of values. The behavior of the hardware is | 
 | 	 * undefined in this case. But we need to report sane values back to | 
 | 	 * the PWM core. | 
 | 	 */ | 
 | 	state->duty_cycle = min(state->duty_cycle, state->period); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | 
 | 			      const struct pwm_state *state) | 
 | { | 
 | 	struct sl28cpld_pwm *priv = sl28cpld_pwm_from_chip(chip); | 
 | 	unsigned int cycle, prescaler; | 
 | 	bool write_duty_cycle_first; | 
 | 	int ret; | 
 | 	u8 ctrl; | 
 |  | 
 | 	/* Polarity inversion is not supported */ | 
 | 	if (state->polarity != PWM_POLARITY_NORMAL) | 
 | 		return -EINVAL; | 
 |  | 
 | 	/* | 
 | 	 * Calculate the prescaler. Pick the biggest period that isn't | 
 | 	 * bigger than the requested period. | 
 | 	 */ | 
 | 	prescaler = DIV_ROUND_UP_ULL(SL28CPLD_PWM_PERIOD(0), state->period); | 
 | 	prescaler = order_base_2(prescaler); | 
 |  | 
 | 	if (prescaler > field_max(SL28CPLD_PWM_CTRL_PRESCALER_MASK)) | 
 | 		return -ERANGE; | 
 |  | 
 | 	ctrl = FIELD_PREP(SL28CPLD_PWM_CTRL_PRESCALER_MASK, prescaler); | 
 | 	if (state->enabled) | 
 | 		ctrl |= SL28CPLD_PWM_CTRL_ENABLE; | 
 |  | 
 | 	cycle = SL28CPLD_PWM_FROM_DUTY_CYCLE(state->duty_cycle); | 
 | 	cycle = min_t(unsigned int, cycle, SL28CPLD_PWM_MAX_DUTY_CYCLE(prescaler)); | 
 |  | 
 | 	/* | 
 | 	 * Work around the hardware limitation. See also above. Trap 100% duty | 
 | 	 * cycle if the prescaler is 0. Set prescaler to 1 instead. We don't | 
 | 	 * care about the frequency because its "all-one" in either case. | 
 | 	 * | 
 | 	 * We don't need to check the actual prescaler setting, because only | 
 | 	 * if the prescaler is 0 we can have this particular value. | 
 | 	 */ | 
 | 	if (cycle == SL28CPLD_PWM_MAX_DUTY_CYCLE(0)) { | 
 | 		ctrl &= ~SL28CPLD_PWM_CTRL_PRESCALER_MASK; | 
 | 		ctrl |= FIELD_PREP(SL28CPLD_PWM_CTRL_PRESCALER_MASK, 1); | 
 | 		cycle = SL28CPLD_PWM_MAX_DUTY_CYCLE(1); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * To avoid glitches when we switch the prescaler, we have to make sure | 
 | 	 * we have a valid duty cycle for the new mode. | 
 | 	 * | 
 | 	 * Take the current prescaler (or the current period length) into | 
 | 	 * account to decide whether we have to write the duty cycle or the new | 
 | 	 * prescaler first. If the period length is decreasing we have to | 
 | 	 * write the duty cycle first. | 
 | 	 */ | 
 | 	write_duty_cycle_first = pwm->state.period > state->period; | 
 |  | 
 | 	if (write_duty_cycle_first) { | 
 | 		ret = sl28cpld_pwm_write(priv, SL28CPLD_PWM_CYCLE, cycle); | 
 | 		if (ret) | 
 | 			return ret; | 
 | 	} | 
 |  | 
 | 	ret = sl28cpld_pwm_write(priv, SL28CPLD_PWM_CTRL, ctrl); | 
 | 	if (ret) | 
 | 		return ret; | 
 |  | 
 | 	if (!write_duty_cycle_first) { | 
 | 		ret = sl28cpld_pwm_write(priv, SL28CPLD_PWM_CYCLE, cycle); | 
 | 		if (ret) | 
 | 			return ret; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static const struct pwm_ops sl28cpld_pwm_ops = { | 
 | 	.apply = sl28cpld_pwm_apply, | 
 | 	.get_state = sl28cpld_pwm_get_state, | 
 | }; | 
 |  | 
 | static int sl28cpld_pwm_probe(struct platform_device *pdev) | 
 | { | 
 | 	struct sl28cpld_pwm *priv; | 
 | 	struct pwm_chip *chip; | 
 | 	int ret; | 
 |  | 
 | 	if (!pdev->dev.parent) { | 
 | 		dev_err(&pdev->dev, "no parent device\n"); | 
 | 		return -ENODEV; | 
 | 	} | 
 |  | 
 | 	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv)); | 
 | 	if (IS_ERR(chip)) | 
 | 		return PTR_ERR(chip); | 
 | 	priv = sl28cpld_pwm_from_chip(chip); | 
 |  | 
 | 	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); | 
 | 	if (!priv->regmap) { | 
 | 		dev_err(&pdev->dev, "could not get parent regmap\n"); | 
 | 		return -ENODEV; | 
 | 	} | 
 |  | 
 | 	ret = device_property_read_u32(&pdev->dev, "reg", &priv->offset); | 
 | 	if (ret) { | 
 | 		dev_err(&pdev->dev, "no 'reg' property found (%pe)\n", | 
 | 			ERR_PTR(ret)); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	/* Initialize the pwm_chip structure */ | 
 | 	chip->ops = &sl28cpld_pwm_ops; | 
 |  | 
 | 	ret = devm_pwmchip_add(&pdev->dev, chip); | 
 | 	if (ret) { | 
 | 		dev_err(&pdev->dev, "failed to add PWM chip (%pe)", | 
 | 			ERR_PTR(ret)); | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static const struct of_device_id sl28cpld_pwm_of_match[] = { | 
 | 	{ .compatible = "kontron,sl28cpld-pwm" }, | 
 | 	{} | 
 | }; | 
 | MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match); | 
 |  | 
 | static struct platform_driver sl28cpld_pwm_driver = { | 
 | 	.probe = sl28cpld_pwm_probe, | 
 | 	.driver = { | 
 | 		.name = "sl28cpld-pwm", | 
 | 		.of_match_table = sl28cpld_pwm_of_match, | 
 | 	}, | 
 | }; | 
 | module_platform_driver(sl28cpld_pwm_driver); | 
 |  | 
 | MODULE_DESCRIPTION("sl28cpld PWM Driver"); | 
 | MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); | 
 | MODULE_LICENSE("GPL"); |