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");