diff options
Diffstat (limited to 'drivers/pwm/pwm-imx.c')
-rw-r--r-- | drivers/pwm/pwm-imx.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 6cd3b72fbbc1..55a3a363d5be 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -87,6 +87,8 @@ | |||
87 | #define MX3_PWMPR_MAX 0xfffe | 87 | #define MX3_PWMPR_MAX 0xfffe |
88 | 88 | ||
89 | struct imx_chip { | 89 | struct imx_chip { |
90 | struct clk *clk_ipg; | ||
91 | |||
90 | struct clk *clk_per; | 92 | struct clk *clk_per; |
91 | 93 | ||
92 | void __iomem *mmio_base; | 94 | void __iomem *mmio_base; |
@@ -96,6 +98,32 @@ struct imx_chip { | |||
96 | 98 | ||
97 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) | 99 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) |
98 | 100 | ||
101 | static int imx_pwm_clk_prepare_enable(struct pwm_chip *chip) | ||
102 | { | ||
103 | struct imx_chip *imx = to_imx_chip(chip); | ||
104 | int ret; | ||
105 | |||
106 | ret = clk_prepare_enable(imx->clk_ipg); | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | ret = clk_prepare_enable(imx->clk_per); | ||
111 | if (ret) { | ||
112 | clk_disable_unprepare(imx->clk_ipg); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void imx_pwm_clk_disable_unprepare(struct pwm_chip *chip) | ||
120 | { | ||
121 | struct imx_chip *imx = to_imx_chip(chip); | ||
122 | |||
123 | clk_disable_unprepare(imx->clk_per); | ||
124 | clk_disable_unprepare(imx->clk_ipg); | ||
125 | } | ||
126 | |||
99 | static void imx_pwm_get_state(struct pwm_chip *chip, | 127 | static void imx_pwm_get_state(struct pwm_chip *chip, |
100 | struct pwm_device *pwm, struct pwm_state *state) | 128 | struct pwm_device *pwm, struct pwm_state *state) |
101 | { | 129 | { |
@@ -103,11 +131,15 @@ static void imx_pwm_get_state(struct pwm_chip *chip, | |||
103 | u32 period, prescaler, pwm_clk, ret, val; | 131 | u32 period, prescaler, pwm_clk, ret, val; |
104 | u64 tmp; | 132 | u64 tmp; |
105 | 133 | ||
134 | ret = imx_pwm_clk_prepare_enable(chip); | ||
135 | if (ret < 0) | ||
136 | return; | ||
137 | |||
106 | val = readl(imx->mmio_base + MX3_PWMCR); | 138 | val = readl(imx->mmio_base + MX3_PWMCR); |
107 | 139 | ||
108 | if (val & MX3_PWMCR_EN) { | 140 | if (val & MX3_PWMCR_EN) { |
109 | state->enabled = true; | 141 | state->enabled = true; |
110 | ret = clk_prepare_enable(imx->clk_per); | 142 | ret = imx_pwm_clk_prepare_enable(chip); |
111 | if (ret) | 143 | if (ret) |
112 | return; | 144 | return; |
113 | } else { | 145 | } else { |
@@ -143,6 +175,8 @@ static void imx_pwm_get_state(struct pwm_chip *chip, | |||
143 | } else { | 175 | } else { |
144 | state->duty_cycle = 0; | 176 | state->duty_cycle = 0; |
145 | } | 177 | } |
178 | |||
179 | imx_pwm_clk_disable_unprepare(chip); | ||
146 | } | 180 | } |
147 | 181 | ||
148 | static int imx_pwm_config_v1(struct pwm_chip *chip, | 182 | static int imx_pwm_config_v1(struct pwm_chip *chip, |
@@ -180,7 +214,7 @@ static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm) | |||
180 | u32 val; | 214 | u32 val; |
181 | int ret; | 215 | int ret; |
182 | 216 | ||
183 | ret = clk_prepare_enable(imx->clk_per); | 217 | ret = imx_pwm_clk_prepare_enable(chip); |
184 | if (ret < 0) | 218 | if (ret < 0) |
185 | return ret; | 219 | return ret; |
186 | 220 | ||
@@ -200,7 +234,7 @@ static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm) | |||
200 | val &= ~MX1_PWMC_EN; | 234 | val &= ~MX1_PWMC_EN; |
201 | writel(val, imx->mmio_base + MX1_PWMC); | 235 | writel(val, imx->mmio_base + MX1_PWMC); |
202 | 236 | ||
203 | clk_disable_unprepare(imx->clk_per); | 237 | imx_pwm_clk_disable_unprepare(chip); |
204 | } | 238 | } |
205 | 239 | ||
206 | static void imx_pwm_sw_reset(struct pwm_chip *chip) | 240 | static void imx_pwm_sw_reset(struct pwm_chip *chip) |
@@ -286,7 +320,7 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, | |||
286 | if (cstate.enabled) { | 320 | if (cstate.enabled) { |
287 | imx_pwm_wait_fifo_slot(chip, pwm); | 321 | imx_pwm_wait_fifo_slot(chip, pwm); |
288 | } else { | 322 | } else { |
289 | ret = clk_prepare_enable(imx->clk_per); | 323 | ret = imx_pwm_clk_prepare_enable(chip); |
290 | if (ret) | 324 | if (ret) |
291 | return ret; | 325 | return ret; |
292 | 326 | ||
@@ -309,7 +343,7 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, | |||
309 | } else if (cstate.enabled) { | 343 | } else if (cstate.enabled) { |
310 | writel(0, imx->mmio_base + MX3_PWMCR); | 344 | writel(0, imx->mmio_base + MX3_PWMCR); |
311 | 345 | ||
312 | clk_disable_unprepare(imx->clk_per); | 346 | imx_pwm_clk_disable_unprepare(chip); |
313 | } | 347 | } |
314 | 348 | ||
315 | return 0; | 349 | return 0; |
@@ -367,6 +401,13 @@ static int imx_pwm_probe(struct platform_device *pdev) | |||
367 | if (imx == NULL) | 401 | if (imx == NULL) |
368 | return -ENOMEM; | 402 | return -ENOMEM; |
369 | 403 | ||
404 | imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); | ||
405 | if (IS_ERR(imx->clk_ipg)) { | ||
406 | dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", | ||
407 | PTR_ERR(imx->clk_ipg)); | ||
408 | return PTR_ERR(imx->clk_ipg); | ||
409 | } | ||
410 | |||
370 | imx->clk_per = devm_clk_get(&pdev->dev, "per"); | 411 | imx->clk_per = devm_clk_get(&pdev->dev, "per"); |
371 | if (IS_ERR(imx->clk_per)) { | 412 | if (IS_ERR(imx->clk_per)) { |
372 | dev_err(&pdev->dev, "getting per clock failed with %ld\n", | 413 | dev_err(&pdev->dev, "getting per clock failed with %ld\n", |
@@ -406,6 +447,8 @@ static int imx_pwm_remove(struct platform_device *pdev) | |||
406 | if (imx == NULL) | 447 | if (imx == NULL) |
407 | return -ENODEV; | 448 | return -ENODEV; |
408 | 449 | ||
450 | imx_pwm_clk_disable_unprepare(&imx->chip); | ||
451 | |||
409 | return pwmchip_remove(&imx->chip); | 452 | return pwmchip_remove(&imx->chip); |
410 | } | 453 | } |
411 | 454 | ||