diff options
Diffstat (limited to 'drivers/pwm/pwm-imx.c')
-rw-r--r-- | drivers/pwm/pwm-imx.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 7a4907b73d7c..6cd3b72fbbc1 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -83,6 +83,9 @@ | |||
83 | 83 | ||
84 | #define MX3_PWM_SWR_LOOP 5 | 84 | #define MX3_PWM_SWR_LOOP 5 |
85 | 85 | ||
86 | /* PWMPR register value of 0xffff has the same effect as 0xfffe */ | ||
87 | #define MX3_PWMPR_MAX 0xfffe | ||
88 | |||
86 | struct imx_chip { | 89 | struct imx_chip { |
87 | struct clk *clk_per; | 90 | struct clk *clk_per; |
88 | 91 | ||
@@ -93,6 +96,55 @@ struct imx_chip { | |||
93 | 96 | ||
94 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) | 97 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) |
95 | 98 | ||
99 | static void imx_pwm_get_state(struct pwm_chip *chip, | ||
100 | struct pwm_device *pwm, struct pwm_state *state) | ||
101 | { | ||
102 | struct imx_chip *imx = to_imx_chip(chip); | ||
103 | u32 period, prescaler, pwm_clk, ret, val; | ||
104 | u64 tmp; | ||
105 | |||
106 | val = readl(imx->mmio_base + MX3_PWMCR); | ||
107 | |||
108 | if (val & MX3_PWMCR_EN) { | ||
109 | state->enabled = true; | ||
110 | ret = clk_prepare_enable(imx->clk_per); | ||
111 | if (ret) | ||
112 | return; | ||
113 | } else { | ||
114 | state->enabled = false; | ||
115 | } | ||
116 | |||
117 | switch (FIELD_GET(MX3_PWMCR_POUTC, val)) { | ||
118 | case MX3_PWMCR_POUTC_NORMAL: | ||
119 | state->polarity = PWM_POLARITY_NORMAL; | ||
120 | break; | ||
121 | case MX3_PWMCR_POUTC_INVERTED: | ||
122 | state->polarity = PWM_POLARITY_INVERSED; | ||
123 | break; | ||
124 | default: | ||
125 | dev_warn(chip->dev, "can't set polarity, output disconnected"); | ||
126 | } | ||
127 | |||
128 | prescaler = MX3_PWMCR_PRESCALER_GET(val); | ||
129 | pwm_clk = clk_get_rate(imx->clk_per); | ||
130 | pwm_clk = DIV_ROUND_CLOSEST_ULL(pwm_clk, prescaler); | ||
131 | val = readl(imx->mmio_base + MX3_PWMPR); | ||
132 | period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val; | ||
133 | |||
134 | /* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */ | ||
135 | tmp = NSEC_PER_SEC * (u64)(period + 2); | ||
136 | state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); | ||
137 | |||
138 | /* PWMSAR can be read only if PWM is enabled */ | ||
139 | if (state->enabled) { | ||
140 | val = readl(imx->mmio_base + MX3_PWMSAR); | ||
141 | tmp = NSEC_PER_SEC * (u64)(val); | ||
142 | state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); | ||
143 | } else { | ||
144 | state->duty_cycle = 0; | ||
145 | } | ||
146 | } | ||
147 | |||
96 | static int imx_pwm_config_v1(struct pwm_chip *chip, | 148 | static int imx_pwm_config_v1(struct pwm_chip *chip, |
97 | struct pwm_device *pwm, int duty_ns, int period_ns) | 149 | struct pwm_device *pwm, int duty_ns, int period_ns) |
98 | { | 150 | { |
@@ -272,6 +324,7 @@ static const struct pwm_ops imx_pwm_ops_v1 = { | |||
272 | 324 | ||
273 | static const struct pwm_ops imx_pwm_ops_v2 = { | 325 | static const struct pwm_ops imx_pwm_ops_v2 = { |
274 | .apply = imx_pwm_apply_v2, | 326 | .apply = imx_pwm_apply_v2, |
327 | .get_state = imx_pwm_get_state, | ||
275 | .owner = THIS_MODULE, | 328 | .owner = THIS_MODULE, |
276 | }; | 329 | }; |
277 | 330 | ||