diff options
author | Thierry Reding <thierry.reding@gmail.com> | 2017-02-10 09:15:56 -0500 |
---|---|---|
committer | Thierry Reding <thierry.reding@gmail.com> | 2017-02-10 09:15:56 -0500 |
commit | 38b0a526ec33314ee1d9926e3a347078f63eac8e (patch) | |
tree | 7deea94e326a36567ccdf9a35188657305d1b5cc /drivers/pwm/pwm-imx.c | |
parent | 776906ff0350de74441a2e2387a2a69f55f0f71c (diff) | |
parent | 326ed314fefebb259563926c8c6110a009562e07 (diff) |
Merge branch 'for-4.11/drivers' into for-next
Diffstat (limited to 'drivers/pwm/pwm-imx.c')
-rw-r--r-- | drivers/pwm/pwm-imx.c | 271 |
1 files changed, 129 insertions, 142 deletions
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 1223187ad354..2ba5c3a398ff 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #define MX3_PWMCR_DOZEEN (1 << 24) | 38 | #define MX3_PWMCR_DOZEEN (1 << 24) |
39 | #define MX3_PWMCR_WAITEN (1 << 23) | 39 | #define MX3_PWMCR_WAITEN (1 << 23) |
40 | #define MX3_PWMCR_DBGEN (1 << 22) | 40 | #define MX3_PWMCR_DBGEN (1 << 22) |
41 | #define MX3_PWMCR_POUTC (1 << 18) | ||
41 | #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) | 42 | #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) |
42 | #define MX3_PWMCR_CLKSRC_IPG (1 << 16) | 43 | #define MX3_PWMCR_CLKSRC_IPG (1 << 16) |
43 | #define MX3_PWMCR_SWR (1 << 3) | 44 | #define MX3_PWMCR_SWR (1 << 3) |
@@ -49,15 +50,10 @@ | |||
49 | 50 | ||
50 | struct imx_chip { | 51 | struct imx_chip { |
51 | struct clk *clk_per; | 52 | struct clk *clk_per; |
52 | struct clk *clk_ipg; | ||
53 | 53 | ||
54 | void __iomem *mmio_base; | 54 | void __iomem *mmio_base; |
55 | 55 | ||
56 | struct pwm_chip chip; | 56 | struct pwm_chip chip; |
57 | |||
58 | int (*config)(struct pwm_chip *chip, | ||
59 | struct pwm_device *pwm, int duty_ns, int period_ns); | ||
60 | void (*set_enable)(struct pwm_chip *chip, bool enable); | ||
61 | }; | 57 | }; |
62 | 58 | ||
63 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) | 59 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) |
@@ -91,176 +87,170 @@ static int imx_pwm_config_v1(struct pwm_chip *chip, | |||
91 | return 0; | 87 | return 0; |
92 | } | 88 | } |
93 | 89 | ||
94 | static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) | 90 | static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm) |
95 | { | 91 | { |
96 | struct imx_chip *imx = to_imx_chip(chip); | 92 | struct imx_chip *imx = to_imx_chip(chip); |
97 | u32 val; | 93 | u32 val; |
94 | int ret; | ||
98 | 95 | ||
99 | val = readl(imx->mmio_base + MX1_PWMC); | 96 | ret = clk_prepare_enable(imx->clk_per); |
100 | 97 | if (ret < 0) | |
101 | if (enable) | 98 | return ret; |
102 | val |= MX1_PWMC_EN; | ||
103 | else | ||
104 | val &= ~MX1_PWMC_EN; | ||
105 | 99 | ||
100 | val = readl(imx->mmio_base + MX1_PWMC); | ||
101 | val |= MX1_PWMC_EN; | ||
106 | writel(val, imx->mmio_base + MX1_PWMC); | 102 | writel(val, imx->mmio_base + MX1_PWMC); |
107 | } | ||
108 | |||
109 | static int imx_pwm_config_v2(struct pwm_chip *chip, | ||
110 | struct pwm_device *pwm, int duty_ns, int period_ns) | ||
111 | { | ||
112 | struct imx_chip *imx = to_imx_chip(chip); | ||
113 | struct device *dev = chip->dev; | ||
114 | unsigned long long c; | ||
115 | unsigned long period_cycles, duty_cycles, prescale; | ||
116 | unsigned int period_ms; | ||
117 | bool enable = pwm_is_enabled(pwm); | ||
118 | int wait_count = 0, fifoav; | ||
119 | u32 cr, sr; | ||
120 | |||
121 | /* | ||
122 | * i.MX PWMv2 has a 4-word sample FIFO. | ||
123 | * In order to avoid FIFO overflow issue, we do software reset | ||
124 | * to clear all sample FIFO if the controller is disabled or | ||
125 | * wait for a full PWM cycle to get a relinquished FIFO slot | ||
126 | * when the controller is enabled and the FIFO is fully loaded. | ||
127 | */ | ||
128 | if (enable) { | ||
129 | sr = readl(imx->mmio_base + MX3_PWMSR); | ||
130 | fifoav = sr & MX3_PWMSR_FIFOAV_MASK; | ||
131 | if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { | ||
132 | period_ms = DIV_ROUND_UP(pwm_get_period(pwm), | ||
133 | NSEC_PER_MSEC); | ||
134 | msleep(period_ms); | ||
135 | |||
136 | sr = readl(imx->mmio_base + MX3_PWMSR); | ||
137 | if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK)) | ||
138 | dev_warn(dev, "there is no free FIFO slot\n"); | ||
139 | } | ||
140 | } else { | ||
141 | writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); | ||
142 | do { | ||
143 | usleep_range(200, 1000); | ||
144 | cr = readl(imx->mmio_base + MX3_PWMCR); | ||
145 | } while ((cr & MX3_PWMCR_SWR) && | ||
146 | (wait_count++ < MX3_PWM_SWR_LOOP)); | ||
147 | |||
148 | if (cr & MX3_PWMCR_SWR) | ||
149 | dev_warn(dev, "software reset timeout\n"); | ||
150 | } | ||
151 | |||
152 | c = clk_get_rate(imx->clk_per); | ||
153 | c = c * period_ns; | ||
154 | do_div(c, 1000000000); | ||
155 | period_cycles = c; | ||
156 | |||
157 | prescale = period_cycles / 0x10000 + 1; | ||
158 | |||
159 | period_cycles /= prescale; | ||
160 | c = (unsigned long long)period_cycles * duty_ns; | ||
161 | do_div(c, period_ns); | ||
162 | duty_cycles = c; | ||
163 | |||
164 | /* | ||
165 | * according to imx pwm RM, the real period value should be | ||
166 | * PERIOD value in PWMPR plus 2. | ||
167 | */ | ||
168 | if (period_cycles > 2) | ||
169 | period_cycles -= 2; | ||
170 | else | ||
171 | period_cycles = 0; | ||
172 | |||
173 | writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); | ||
174 | writel(period_cycles, imx->mmio_base + MX3_PWMPR); | ||
175 | |||
176 | cr = MX3_PWMCR_PRESCALER(prescale) | | ||
177 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | ||
178 | MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; | ||
179 | |||
180 | if (enable) | ||
181 | cr |= MX3_PWMCR_EN; | ||
182 | |||
183 | writel(cr, imx->mmio_base + MX3_PWMCR); | ||
184 | 103 | ||
185 | return 0; | 104 | return 0; |
186 | } | 105 | } |
187 | 106 | ||
188 | static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) | 107 | static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm) |
189 | { | 108 | { |
190 | struct imx_chip *imx = to_imx_chip(chip); | 109 | struct imx_chip *imx = to_imx_chip(chip); |
191 | u32 val; | 110 | u32 val; |
192 | 111 | ||
193 | val = readl(imx->mmio_base + MX3_PWMCR); | 112 | val = readl(imx->mmio_base + MX1_PWMC); |
194 | 113 | val &= ~MX1_PWMC_EN; | |
195 | if (enable) | 114 | writel(val, imx->mmio_base + MX1_PWMC); |
196 | val |= MX3_PWMCR_EN; | ||
197 | else | ||
198 | val &= ~MX3_PWMCR_EN; | ||
199 | 115 | ||
200 | writel(val, imx->mmio_base + MX3_PWMCR); | 116 | clk_disable_unprepare(imx->clk_per); |
201 | } | 117 | } |
202 | 118 | ||
203 | static int imx_pwm_config(struct pwm_chip *chip, | 119 | static void imx_pwm_sw_reset(struct pwm_chip *chip) |
204 | struct pwm_device *pwm, int duty_ns, int period_ns) | ||
205 | { | 120 | { |
206 | struct imx_chip *imx = to_imx_chip(chip); | 121 | struct imx_chip *imx = to_imx_chip(chip); |
207 | int ret; | 122 | struct device *dev = chip->dev; |
208 | 123 | int wait_count = 0; | |
209 | ret = clk_prepare_enable(imx->clk_ipg); | 124 | u32 cr; |
210 | if (ret) | 125 | |
211 | return ret; | 126 | writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); |
127 | do { | ||
128 | usleep_range(200, 1000); | ||
129 | cr = readl(imx->mmio_base + MX3_PWMCR); | ||
130 | } while ((cr & MX3_PWMCR_SWR) && | ||
131 | (wait_count++ < MX3_PWM_SWR_LOOP)); | ||
132 | |||
133 | if (cr & MX3_PWMCR_SWR) | ||
134 | dev_warn(dev, "software reset timeout\n"); | ||
135 | } | ||
212 | 136 | ||
213 | ret = imx->config(chip, pwm, duty_ns, period_ns); | 137 | static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip, |
138 | struct pwm_device *pwm) | ||
139 | { | ||
140 | struct imx_chip *imx = to_imx_chip(chip); | ||
141 | struct device *dev = chip->dev; | ||
142 | unsigned int period_ms; | ||
143 | int fifoav; | ||
144 | u32 sr; | ||
214 | 145 | ||
215 | clk_disable_unprepare(imx->clk_ipg); | 146 | sr = readl(imx->mmio_base + MX3_PWMSR); |
147 | fifoav = sr & MX3_PWMSR_FIFOAV_MASK; | ||
148 | if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { | ||
149 | period_ms = DIV_ROUND_UP(pwm_get_period(pwm), | ||
150 | NSEC_PER_MSEC); | ||
151 | msleep(period_ms); | ||
216 | 152 | ||
217 | return ret; | 153 | sr = readl(imx->mmio_base + MX3_PWMSR); |
154 | if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK)) | ||
155 | dev_warn(dev, "there is no free FIFO slot\n"); | ||
156 | } | ||
218 | } | 157 | } |
219 | 158 | ||
220 | static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 159 | static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, |
160 | struct pwm_state *state) | ||
221 | { | 161 | { |
162 | unsigned long period_cycles, duty_cycles, prescale; | ||
222 | struct imx_chip *imx = to_imx_chip(chip); | 163 | struct imx_chip *imx = to_imx_chip(chip); |
164 | struct pwm_state cstate; | ||
165 | unsigned long long c; | ||
223 | int ret; | 166 | int ret; |
167 | u32 cr; | ||
168 | |||
169 | pwm_get_state(pwm, &cstate); | ||
170 | |||
171 | if (state->enabled) { | ||
172 | c = clk_get_rate(imx->clk_per); | ||
173 | c *= state->period; | ||
174 | |||
175 | do_div(c, 1000000000); | ||
176 | period_cycles = c; | ||
177 | |||
178 | prescale = period_cycles / 0x10000 + 1; | ||
179 | |||
180 | period_cycles /= prescale; | ||
181 | c = (unsigned long long)period_cycles * state->duty_cycle; | ||
182 | do_div(c, state->period); | ||
183 | duty_cycles = c; | ||
184 | |||
185 | /* | ||
186 | * according to imx pwm RM, the real period value should be | ||
187 | * PERIOD value in PWMPR plus 2. | ||
188 | */ | ||
189 | if (period_cycles > 2) | ||
190 | period_cycles -= 2; | ||
191 | else | ||
192 | period_cycles = 0; | ||
193 | |||
194 | /* | ||
195 | * Wait for a free FIFO slot if the PWM is already enabled, and | ||
196 | * flush the FIFO if the PWM was disabled and is about to be | ||
197 | * enabled. | ||
198 | */ | ||
199 | if (cstate.enabled) { | ||
200 | imx_pwm_wait_fifo_slot(chip, pwm); | ||
201 | } else { | ||
202 | ret = clk_prepare_enable(imx->clk_per); | ||
203 | if (ret) | ||
204 | return ret; | ||
205 | |||
206 | imx_pwm_sw_reset(chip); | ||
207 | } | ||
224 | 208 | ||
225 | ret = clk_prepare_enable(imx->clk_per); | 209 | writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); |
226 | if (ret) | 210 | writel(period_cycles, imx->mmio_base + MX3_PWMPR); |
227 | return ret; | ||
228 | 211 | ||
229 | imx->set_enable(chip, true); | 212 | cr = MX3_PWMCR_PRESCALER(prescale) | |
213 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | ||
214 | MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH | | ||
215 | MX3_PWMCR_EN; | ||
230 | 216 | ||
231 | return 0; | 217 | if (state->polarity == PWM_POLARITY_INVERSED) |
232 | } | 218 | cr |= MX3_PWMCR_POUTC; |
233 | 219 | ||
234 | static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | 220 | writel(cr, imx->mmio_base + MX3_PWMCR); |
235 | { | 221 | } else if (cstate.enabled) { |
236 | struct imx_chip *imx = to_imx_chip(chip); | 222 | writel(0, imx->mmio_base + MX3_PWMCR); |
237 | 223 | ||
238 | imx->set_enable(chip, false); | 224 | clk_disable_unprepare(imx->clk_per); |
225 | } | ||
239 | 226 | ||
240 | clk_disable_unprepare(imx->clk_per); | 227 | return 0; |
241 | } | 228 | } |
242 | 229 | ||
243 | static struct pwm_ops imx_pwm_ops = { | 230 | static const struct pwm_ops imx_pwm_ops_v1 = { |
244 | .enable = imx_pwm_enable, | 231 | .enable = imx_pwm_enable_v1, |
245 | .disable = imx_pwm_disable, | 232 | .disable = imx_pwm_disable_v1, |
246 | .config = imx_pwm_config, | 233 | .config = imx_pwm_config_v1, |
234 | .owner = THIS_MODULE, | ||
235 | }; | ||
236 | |||
237 | static const struct pwm_ops imx_pwm_ops_v2 = { | ||
238 | .apply = imx_pwm_apply_v2, | ||
247 | .owner = THIS_MODULE, | 239 | .owner = THIS_MODULE, |
248 | }; | 240 | }; |
249 | 241 | ||
250 | struct imx_pwm_data { | 242 | struct imx_pwm_data { |
251 | int (*config)(struct pwm_chip *chip, | 243 | bool polarity_supported; |
252 | struct pwm_device *pwm, int duty_ns, int period_ns); | 244 | const struct pwm_ops *ops; |
253 | void (*set_enable)(struct pwm_chip *chip, bool enable); | ||
254 | }; | 245 | }; |
255 | 246 | ||
256 | static struct imx_pwm_data imx_pwm_data_v1 = { | 247 | static struct imx_pwm_data imx_pwm_data_v1 = { |
257 | .config = imx_pwm_config_v1, | 248 | .ops = &imx_pwm_ops_v1, |
258 | .set_enable = imx_pwm_set_enable_v1, | ||
259 | }; | 249 | }; |
260 | 250 | ||
261 | static struct imx_pwm_data imx_pwm_data_v2 = { | 251 | static struct imx_pwm_data imx_pwm_data_v2 = { |
262 | .config = imx_pwm_config_v2, | 252 | .polarity_supported = true, |
263 | .set_enable = imx_pwm_set_enable_v2, | 253 | .ops = &imx_pwm_ops_v2, |
264 | }; | 254 | }; |
265 | 255 | ||
266 | static const struct of_device_id imx_pwm_dt_ids[] = { | 256 | static const struct of_device_id imx_pwm_dt_ids[] = { |
@@ -282,6 +272,8 @@ static int imx_pwm_probe(struct platform_device *pdev) | |||
282 | if (!of_id) | 272 | if (!of_id) |
283 | return -ENODEV; | 273 | return -ENODEV; |
284 | 274 | ||
275 | data = of_id->data; | ||
276 | |||
285 | imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); | 277 | imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); |
286 | if (imx == NULL) | 278 | if (imx == NULL) |
287 | return -ENOMEM; | 279 | return -ENOMEM; |
@@ -293,27 +285,22 @@ static int imx_pwm_probe(struct platform_device *pdev) | |||
293 | return PTR_ERR(imx->clk_per); | 285 | return PTR_ERR(imx->clk_per); |
294 | } | 286 | } |
295 | 287 | ||
296 | imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); | 288 | imx->chip.ops = data->ops; |
297 | if (IS_ERR(imx->clk_ipg)) { | ||
298 | dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", | ||
299 | PTR_ERR(imx->clk_ipg)); | ||
300 | return PTR_ERR(imx->clk_ipg); | ||
301 | } | ||
302 | |||
303 | imx->chip.ops = &imx_pwm_ops; | ||
304 | imx->chip.dev = &pdev->dev; | 289 | imx->chip.dev = &pdev->dev; |
305 | imx->chip.base = -1; | 290 | imx->chip.base = -1; |
306 | imx->chip.npwm = 1; | 291 | imx->chip.npwm = 1; |
307 | 292 | ||
293 | if (data->polarity_supported) { | ||
294 | dev_dbg(&pdev->dev, "PWM supports output inversion\n"); | ||
295 | imx->chip.of_xlate = of_pwm_xlate_with_flags; | ||
296 | imx->chip.of_pwm_n_cells = 3; | ||
297 | } | ||
298 | |||
308 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 299 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
309 | imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); | 300 | imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); |
310 | if (IS_ERR(imx->mmio_base)) | 301 | if (IS_ERR(imx->mmio_base)) |
311 | return PTR_ERR(imx->mmio_base); | 302 | return PTR_ERR(imx->mmio_base); |
312 | 303 | ||
313 | data = of_id->data; | ||
314 | imx->config = data->config; | ||
315 | imx->set_enable = data->set_enable; | ||
316 | |||
317 | ret = pwmchip_add(&imx->chip); | 304 | ret = pwmchip_add(&imx->chip); |
318 | if (ret < 0) | 305 | if (ret < 0) |
319 | return ret; | 306 | return ret; |