VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   33 Branches   55 Tags
a912e80bd0bbf (Thomas Gleixner     2019-05-27 08:55:00 +0200   1) // SPDX-License-Identifier: GPL-2.0-or-later
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200   2) /*
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200   3)  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200   4)  *  JZ4740 platform PWM support
3b442c60cf976 (Uwe Kleine-König    2019-07-30 14:32:29 +0200   5)  *
3b442c60cf976 (Uwe Kleine-König    2019-07-30 14:32:29 +0200   6)  * Limitations:
3b442c60cf976 (Uwe Kleine-König    2019-07-30 14:32:29 +0200   7)  * - The .apply callback doesn't complete the currently running period before
3b442c60cf976 (Uwe Kleine-König    2019-07-30 14:32:29 +0200   8)  *   reconfiguring the hardware.
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200   9)  */
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  10) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  11) #include <linux/clk.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  12) #include <linux/err.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  13) #include <linux/gpio.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  14) #include <linux/kernel.h>
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  15) #include <linux/mfd/ingenic-tcu.h>
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  16) #include <linux/mfd/syscon.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  17) #include <linux/module.h>
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100  18) #include <linux/of_device.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  19) #include <linux/platform_device.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  20) #include <linux/pwm.h>
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  21) #include <linux/regmap.h>
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  22) 
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200  23) struct soc_info {
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200  24) 	unsigned int num_pwms;
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200  25) };
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  26) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  27) struct jz4740_pwm_chip {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  28) 	struct pwm_chip chip;
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  29) 	struct regmap *map;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  30) };
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  31) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  32) static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  33) {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  34) 	return container_of(chip, struct jz4740_pwm_chip, chip);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  35) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  36) 
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  37) static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz,
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  38) 				   unsigned int channel)
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  39) {
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  40) 	/* Enable all TCU channels for PWM use by default except channels 0/1 */
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200  41) 	u32 pwm_channels_mask = GENMASK(jz->chip.npwm - 1, 2);
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  42) 
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  43) 	device_property_read_u32(jz->chip.dev->parent,
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  44) 				 "ingenic,pwm-channels-mask",
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  45) 				 &pwm_channels_mask);
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  46) 
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  47) 	return !!(pwm_channels_mask & BIT(channel));
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  48) }
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  49) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  50) static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  51) {
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  52) 	struct jz4740_pwm_chip *jz = to_jz4740(chip);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  53) 	struct clk *clk;
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  54) 	char name[16];
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  55) 	int err;
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  56) 
a2005fc791798 (Paul Cercueil       2020-03-23 15:24:21 +0100  57) 	if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm))
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  58) 		return -EBUSY;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  59) 
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  60) 	snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  61) 
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  62) 	clk = clk_get(chip->dev, name);
c0bfe9606e036 (Krzysztof Kozlowski 2020-08-26 16:47:43 +0200  63) 	if (IS_ERR(clk))
c0bfe9606e036 (Krzysztof Kozlowski 2020-08-26 16:47:43 +0200  64) 		return dev_err_probe(chip->dev, PTR_ERR(clk),
c0bfe9606e036 (Krzysztof Kozlowski 2020-08-26 16:47:43 +0200  65) 				     "Failed to get clock\n");
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  66) 
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  67) 	err = clk_prepare_enable(clk);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  68) 	if (err < 0) {
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  69) 		clk_put(clk);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  70) 		return err;
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  71) 	}
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  72) 
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  73) 	pwm_set_chip_data(pwm, clk);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  74) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  75) 	return 0;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  76) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  77) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  78) static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  79) {
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  80) 	struct clk *clk = pwm_get_chip_data(pwm);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  81) 
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  82) 	clk_disable_unprepare(clk);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100  83) 	clk_put(clk);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  84) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  85) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  86) static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  87) {
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  88) 	struct jz4740_pwm_chip *jz = to_jz4740(chip);
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  89) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  90) 	/* Enable PWM output */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  91) 	regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  92) 			   TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  93) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  94) 	/* Start counter */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100  95) 	regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm));
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  96) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  97) 	return 0;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  98) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200  99) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 100) static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 101) {
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 102) 	struct jz4740_pwm_chip *jz = to_jz4740(chip);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 103) 
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 104) 	/*
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 105) 	 * Set duty > period. This trick allows the TCU channels in TCU2 mode to
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 106) 	 * properly return to their init level.
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 107) 	 */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 108) 	regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), 0xffff);
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 109) 	regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), 0x0);
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 110) 
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 111) 	/*
6580fd173070a (Paul Cercueil       2019-06-07 17:44:09 +0200 112) 	 * Disable PWM output.
df56b1712d578 (Maarten ter Huurne  2018-01-06 17:58:40 +0100 113) 	 * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
df56b1712d578 (Maarten ter Huurne  2018-01-06 17:58:40 +0100 114) 	 * counter is stopped, while in TCU1 mode the order does not matter.
df56b1712d578 (Maarten ter Huurne  2018-01-06 17:58:40 +0100 115) 	 */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 116) 	regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 117) 			   TCU_TCSR_PWM_EN, 0);
df56b1712d578 (Maarten ter Huurne  2018-01-06 17:58:40 +0100 118) 
df56b1712d578 (Maarten ter Huurne  2018-01-06 17:58:40 +0100 119) 	/* Stop counter */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 120) 	regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm));
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 121) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 122) 
1ac99c58bda9b (Paul Cercueil       2019-06-07 17:44:07 +0200 123) static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
71523d1812aca (Uwe Kleine-König    2019-08-24 17:37:07 +0200 124) 			    const struct pwm_state *state)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 125) {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 126) 	struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 127) 	unsigned long long tmp = 0xffffull * NSEC_PER_SEC;
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 128) 	struct clk *clk = pwm_get_chip_data(pwm);
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 129) 	unsigned long period, duty;
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 130) 	long rate;
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 131) 	int err;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 132) 
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 133) 	/*
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 134) 	 * Limit the clock to a maximum rate that still gives us a period value
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 135) 	 * which fits in 16 bits.
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 136) 	 */
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 137) 	do_div(tmp, state->period);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 138) 
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 139) 	/*
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 140) 	 * /!\ IMPORTANT NOTE:
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 141) 	 * -------------------
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 142) 	 * This code relies on the fact that clk_round_rate() will always round
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 143) 	 * down, which is not a valid assumption given by the clk API, but only
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 144) 	 * happens to be true with the clk drivers used for Ingenic SoCs.
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 145) 	 *
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 146) 	 * Right now, there is no alternative as the clk API does not have a
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 147) 	 * round-down function (and won't have one for a while), but if it ever
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 148) 	 * comes to light, a round-down function should be used instead.
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 149) 	 */
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 150) 	rate = clk_round_rate(clk, tmp);
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 151) 	if (rate < 0) {
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 152) 		dev_err(chip->dev, "Unable to round rate: %ld", rate);
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 153) 		return rate;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 154) 	}
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 155) 
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 156) 	/* Calculate period value */
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 157) 	tmp = (unsigned long long)rate * state->period;
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 158) 	do_div(tmp, NSEC_PER_SEC);
9017dc4fbd59c (Paul Cercueil       2020-05-27 13:52:23 +0200 159) 	period = tmp;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 160) 
485b56f08f334 (Paul Cercueil       2020-03-23 15:24:19 +0100 161) 	/* Calculate duty value */
9017dc4fbd59c (Paul Cercueil       2020-05-27 13:52:23 +0200 162) 	tmp = (unsigned long long)rate * state->duty_cycle;
9017dc4fbd59c (Paul Cercueil       2020-05-27 13:52:23 +0200 163) 	do_div(tmp, NSEC_PER_SEC);
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 164) 	duty = tmp;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 165) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 166) 	if (duty >= period)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 167) 		duty = period - 1;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 168) 
1ac99c58bda9b (Paul Cercueil       2019-06-07 17:44:07 +0200 169) 	jz4740_pwm_disable(chip, pwm);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 170) 
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 171) 	err = clk_set_rate(clk, rate);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 172) 	if (err) {
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 173) 		dev_err(chip->dev, "Unable to set rate: %d", err);
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 174) 		return err;
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 175) 	}
ce1f9cece0578 (Paul Cercueil       2020-03-23 15:24:18 +0100 176) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 177) 	/* Reset counter to 0 */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 178) 	regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0);
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 179) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 180) 	/* Set duty */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 181) 	regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 182) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 183) 	/* Set period */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 184) 	regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 185) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 186) 	/* Set abrupt shutdown */
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 187) 	regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 188) 			   TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD);
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 189) 
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 190) 	/*
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 191) 	 * Set polarity.
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 192) 	 *
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 193) 	 * The PWM starts in inactive state until the internal timer reaches the
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 194) 	 * duty value, then becomes active until the timer reaches the period
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 195) 	 * value. In theory, we should then use (period - duty) as the real duty
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 196) 	 * value, as a high duty value would otherwise result in the PWM pin
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 197) 	 * being inactive most of the time.
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 198) 	 *
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 199) 	 * Here, we don't do that, and instead invert the polarity of the PWM
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 200) 	 * when it is active. This trick makes the PWM start with its active
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 201) 	 * state instead of its inactive state.
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 202) 	 */
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 203) 	if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled)
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 204) 		regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 205) 				   TCU_TCSR_PWM_INITL_HIGH, 0);
a020f22a4ff55 (Paul Cercueil       2020-05-27 13:52:24 +0200 206) 	else
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 207) 		regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 208) 				   TCU_TCSR_PWM_INITL_HIGH,
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 209) 				   TCU_TCSR_PWM_INITL_HIGH);
174dcc8eaec5f (Paul Cercueil       2018-01-06 17:58:41 +0100 210) 
1ac99c58bda9b (Paul Cercueil       2019-06-07 17:44:07 +0200 211) 	if (state->enabled)
1ac99c58bda9b (Paul Cercueil       2019-06-07 17:44:07 +0200 212) 		jz4740_pwm_enable(chip, pwm);
1ac99c58bda9b (Paul Cercueil       2019-06-07 17:44:07 +0200 213) 
174dcc8eaec5f (Paul Cercueil       2018-01-06 17:58:41 +0100 214) 	return 0;
174dcc8eaec5f (Paul Cercueil       2018-01-06 17:58:41 +0100 215) }
174dcc8eaec5f (Paul Cercueil       2018-01-06 17:58:41 +0100 216) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 217) static const struct pwm_ops jz4740_pwm_ops = {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 218) 	.request = jz4740_pwm_request,
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 219) 	.free = jz4740_pwm_free,
1ac99c58bda9b (Paul Cercueil       2019-06-07 17:44:07 +0200 220) 	.apply = jz4740_pwm_apply,
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 221) 	.owner = THIS_MODULE,
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 222) };
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 223) 
3e9fe83d278cc (Bill Pemberton      2012-11-19 13:23:14 -0500 224) static int jz4740_pwm_probe(struct platform_device *pdev)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 225) {
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 226) 	struct device *dev = &pdev->dev;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 227) 	struct jz4740_pwm_chip *jz4740;
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 228) 	const struct soc_info *info;
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 229) 
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 230) 	info = device_get_match_data(dev);
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 231) 	if (!info)
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 232) 		return -EINVAL;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 233) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 234) 	jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 235) 	if (!jz4740)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 236) 		return -ENOMEM;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 237) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 238) 	jz4740->map = device_node_to_regmap(dev->parent->of_node);
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 239) 	if (IS_ERR(jz4740->map)) {
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 240) 		dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map));
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 241) 		return PTR_ERR(jz4740->map);
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 242) 	}
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 243) 
c2693514a0a1e (Paul Cercueil       2020-03-23 15:24:20 +0100 244) 	jz4740->chip.dev = dev;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 245) 	jz4740->chip.ops = &jz4740_pwm_ops;
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 246) 	jz4740->chip.npwm = info->num_pwms;
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 247) 	jz4740->chip.of_xlate = of_pwm_xlate_with_flags;
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 248) 	jz4740->chip.of_pwm_n_cells = 3;
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 249) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 250) 	platform_set_drvdata(pdev, jz4740);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 251) 
0dc1135fdf5e2 (Lars-Peter Clausen  2013-12-07 18:13:16 +0100 252) 	return pwmchip_add(&jz4740->chip);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 253) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 254) 
77f37917a6f2b (Bill Pemberton      2012-11-19 13:26:09 -0500 255) static int jz4740_pwm_remove(struct platform_device *pdev)
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 256) {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 257) 	struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 258) 
0dc1135fdf5e2 (Lars-Peter Clausen  2013-12-07 18:13:16 +0100 259) 	return pwmchip_remove(&jz4740->chip);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 260) }
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 261) 
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 262) static const struct soc_info __maybe_unused jz4740_soc_info = {
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 263) 	.num_pwms = 8,
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 264) };
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 265) 
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 266) static const struct soc_info __maybe_unused jz4725b_soc_info = {
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 267) 	.num_pwms = 6,
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 268) };
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 269) 
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 270) #ifdef CONFIG_OF
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 271) static const struct of_device_id jz4740_pwm_dt_ids[] = {
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 272) 	{ .compatible = "ingenic,jz4740-pwm", .data = &jz4740_soc_info },
74db728c0b4c7 (Paul Cercueil       2020-05-27 13:52:25 +0200 273) 	{ .compatible = "ingenic,jz4725b-pwm", .data = &jz4725b_soc_info },
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 274) 	{},
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 275) };
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 276) MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 277) #endif
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 278) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 279) static struct platform_driver jz4740_pwm_driver = {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 280) 	.driver = {
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 281) 		.name = "jz4740-pwm",
cc20173304e4f (Paul Cercueil       2018-01-06 17:58:42 +0100 282) 		.of_match_table = of_match_ptr(jz4740_pwm_dt_ids),
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 283) 	},
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 284) 	.probe = jz4740_pwm_probe,
fd1091125a1d1 (Bill Pemberton      2012-11-19 13:21:28 -0500 285) 	.remove = jz4740_pwm_remove,
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 286) };
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 287) module_platform_driver(jz4740_pwm_driver);
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 288) 
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 289) MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 290) MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver");
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 291) MODULE_ALIAS("platform:jz4740-pwm");
f6b8a5700057c (Thierry Reding      2012-08-22 10:01:24 +0200 292) MODULE_LICENSE("GPL");