2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license.
7 * Copyright (c) 2016 BayLibre, SAS.
8 * Author: Neil Armstrong <narmstrong@baylibre.com>
9 * Copyright (C) 2014 Amlogic, Inc.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 * The full GNU General Public License is included in this distribution
23 * in the file called COPYING.
27 * Copyright (c) 2016 BayLibre, SAS.
28 * Author: Neil Armstrong <narmstrong@baylibre.com>
29 * Copyright (C) 2014 Amlogic, Inc.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
41 * * Neither the name of Intel Corporation nor the names of its
42 * contributors may be used to endorse or promote products derived
43 * from this software without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
49 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
55 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 #include <linux/clk.h>
59 #include <linux/clk-provider.h>
60 #include <linux/err.h>
62 #include <linux/kernel.h>
63 #include <linux/module.h>
65 #include <linux/of_device.h>
66 #include <linux/platform_device.h>
67 #include <linux/pwm.h>
68 #include <linux/slab.h>
69 #include <linux/spinlock.h>
73 #define PWM_HIGH_SHIFT 16
75 #define REG_MISC_AB 0x8
76 #define MISC_B_CLK_EN BIT(23)
77 #define MISC_A_CLK_EN BIT(15)
78 #define MISC_CLK_DIV_MASK 0x7f
79 #define MISC_B_CLK_DIV_SHIFT 16
80 #define MISC_A_CLK_DIV_SHIFT 8
81 #define MISC_B_CLK_SEL_SHIFT 6
82 #define MISC_A_CLK_SEL_SHIFT 4
83 #define MISC_CLK_SEL_WIDTH 2
84 #define MISC_B_EN BIT(1)
85 #define MISC_A_EN BIT(0)
87 static const unsigned int mux_reg_shifts
[] = {
92 struct meson_pwm_channel
{
97 struct pwm_state state
;
99 struct clk
*clk_parent
;
104 struct meson_pwm_data
{
105 const char * const *parent_names
;
109 struct pwm_chip chip
;
110 const struct meson_pwm_data
*data
;
116 static inline struct meson_pwm
*to_meson_pwm(struct pwm_chip
*chip
)
118 return container_of(chip
, struct meson_pwm
, chip
);
121 static int meson_pwm_request(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
123 struct meson_pwm_channel
*channel
= pwm_get_chip_data(pwm
);
124 struct device
*dev
= chip
->dev
;
130 if (channel
->clk_parent
) {
131 err
= clk_set_parent(channel
->clk
, channel
->clk_parent
);
133 dev_err(dev
, "failed to set parent %s for %s: %d\n",
134 __clk_get_name(channel
->clk_parent
),
135 __clk_get_name(channel
->clk
), err
);
140 err
= clk_prepare_enable(channel
->clk
);
142 dev_err(dev
, "failed to enable clock %s: %d\n",
143 __clk_get_name(channel
->clk
), err
);
147 chip
->ops
->get_state(chip
, pwm
, &channel
->state
);
152 static void meson_pwm_free(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
154 struct meson_pwm_channel
*channel
= pwm_get_chip_data(pwm
);
157 clk_disable_unprepare(channel
->clk
);
160 static int meson_pwm_calc(struct meson_pwm
*meson
,
161 struct meson_pwm_channel
*channel
, unsigned int id
,
162 unsigned int duty
, unsigned int period
)
164 unsigned int pre_div
, cnt
, duty_cnt
;
165 unsigned long fin_freq
= -1, fin_ns
;
167 if (~(meson
->inverter_mask
>> id
) & 0x1)
168 duty
= period
- duty
;
170 if (period
== channel
->state
.period
&&
171 duty
== channel
->state
.duty_cycle
)
174 fin_freq
= clk_get_rate(channel
->clk
);
176 dev_err(meson
->chip
.dev
, "invalid source clock frequency\n");
180 dev_dbg(meson
->chip
.dev
, "fin_freq: %lu Hz\n", fin_freq
);
181 fin_ns
= NSEC_PER_SEC
/ fin_freq
;
183 /* Calc pre_div with the period */
184 for (pre_div
= 0; pre_div
< MISC_CLK_DIV_MASK
; pre_div
++) {
185 cnt
= DIV_ROUND_CLOSEST(period
, fin_ns
* (pre_div
+ 1));
186 dev_dbg(meson
->chip
.dev
, "fin_ns=%lu pre_div=%u cnt=%u\n",
187 fin_ns
, pre_div
, cnt
);
192 if (pre_div
== MISC_CLK_DIV_MASK
) {
193 dev_err(meson
->chip
.dev
, "unable to get period pre_div\n");
197 dev_dbg(meson
->chip
.dev
, "period=%u pre_div=%u cnt=%u\n", period
,
200 if (duty
== period
) {
201 channel
->pre_div
= pre_div
;
204 } else if (duty
== 0) {
205 channel
->pre_div
= pre_div
;
209 /* Then check is we can have the duty with the same pre_div */
210 duty_cnt
= DIV_ROUND_CLOSEST(duty
, fin_ns
* (pre_div
+ 1));
211 if (duty_cnt
> 0xffff) {
212 dev_err(meson
->chip
.dev
, "unable to get duty cycle\n");
216 dev_dbg(meson
->chip
.dev
, "duty=%u pre_div=%u duty_cnt=%u\n",
217 duty
, pre_div
, duty_cnt
);
219 channel
->pre_div
= pre_div
;
220 channel
->hi
= duty_cnt
;
221 channel
->lo
= cnt
- duty_cnt
;
227 static void meson_pwm_enable(struct meson_pwm
*meson
,
228 struct meson_pwm_channel
*channel
,
231 u32 value
, clk_shift
, clk_enable
, enable
;
236 clk_shift
= MISC_A_CLK_DIV_SHIFT
;
237 clk_enable
= MISC_A_CLK_EN
;
243 clk_shift
= MISC_B_CLK_DIV_SHIFT
;
244 clk_enable
= MISC_B_CLK_EN
;
253 value
= readl(meson
->base
+ REG_MISC_AB
);
254 value
&= ~(MISC_CLK_DIV_MASK
<< clk_shift
);
255 value
|= channel
->pre_div
<< clk_shift
;
257 writel(value
, meson
->base
+ REG_MISC_AB
);
259 value
= (channel
->hi
<< PWM_HIGH_SHIFT
) | channel
->lo
;
260 writel(value
, meson
->base
+ offset
);
262 value
= readl(meson
->base
+ REG_MISC_AB
);
264 writel(value
, meson
->base
+ REG_MISC_AB
);
267 static void meson_pwm_disable(struct meson_pwm
*meson
, unsigned int id
)
284 value
= readl(meson
->base
+ REG_MISC_AB
);
286 writel(value
, meson
->base
+ REG_MISC_AB
);
289 static int meson_pwm_apply(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
290 struct pwm_state
*state
)
292 struct meson_pwm_channel
*channel
= pwm_get_chip_data(pwm
);
293 struct meson_pwm
*meson
= to_meson_pwm(chip
);
300 spin_lock_irqsave(&meson
->lock
, flags
);
302 if (!state
->enabled
) {
303 meson_pwm_disable(meson
, pwm
->hwpwm
);
304 channel
->state
.enabled
= false;
309 if (state
->period
!= channel
->state
.period
||
310 state
->duty_cycle
!= channel
->state
.duty_cycle
||
311 state
->polarity
!= channel
->state
.polarity
) {
312 if (channel
->state
.enabled
) {
313 meson_pwm_disable(meson
, pwm
->hwpwm
);
314 channel
->state
.enabled
= false;
317 if (state
->polarity
!= channel
->state
.polarity
) {
318 if (state
->polarity
== PWM_POLARITY_NORMAL
)
319 meson
->inverter_mask
|= BIT(pwm
->hwpwm
);
321 meson
->inverter_mask
&= ~BIT(pwm
->hwpwm
);
324 err
= meson_pwm_calc(meson
, channel
, pwm
->hwpwm
,
325 state
->duty_cycle
, state
->period
);
329 channel
->state
.polarity
= state
->polarity
;
330 channel
->state
.period
= state
->period
;
331 channel
->state
.duty_cycle
= state
->duty_cycle
;
334 if (state
->enabled
&& !channel
->state
.enabled
) {
335 meson_pwm_enable(meson
, channel
, pwm
->hwpwm
);
336 channel
->state
.enabled
= true;
340 spin_unlock_irqrestore(&meson
->lock
, flags
);
344 static void meson_pwm_get_state(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
345 struct pwm_state
*state
)
347 struct meson_pwm
*meson
= to_meson_pwm(chip
);
353 switch (pwm
->hwpwm
) {
366 value
= readl(meson
->base
+ REG_MISC_AB
);
367 state
->enabled
= (value
& mask
) != 0;
370 static const struct pwm_ops meson_pwm_ops
= {
371 .request
= meson_pwm_request
,
372 .free
= meson_pwm_free
,
373 .apply
= meson_pwm_apply
,
374 .get_state
= meson_pwm_get_state
,
375 .owner
= THIS_MODULE
,
378 static const char * const pwm_meson8b_parent_names
[] = {
379 "xtal", "vid_pll", "fclk_div4", "fclk_div3"
382 static const struct meson_pwm_data pwm_meson8b_data
= {
383 .parent_names
= pwm_meson8b_parent_names
,
386 static const char * const pwm_gxbb_parent_names
[] = {
387 "xtal", "hdmi_pll", "fclk_div4", "fclk_div3"
390 static const struct meson_pwm_data pwm_gxbb_data
= {
391 .parent_names
= pwm_gxbb_parent_names
,
394 static const struct of_device_id meson_pwm_matches
[] = {
395 { .compatible
= "amlogic,meson8b-pwm", .data
= &pwm_meson8b_data
},
396 { .compatible
= "amlogic,meson-gxbb-pwm", .data
= &pwm_gxbb_data
},
399 MODULE_DEVICE_TABLE(of
, meson_pwm_matches
);
401 static int meson_pwm_init_channels(struct meson_pwm
*meson
,
402 struct meson_pwm_channel
*channels
)
404 struct device
*dev
= meson
->chip
.dev
;
405 struct device_node
*np
= dev
->of_node
;
406 struct clk_init_data init
;
411 for (i
= 0; i
< meson
->chip
.npwm
; i
++) {
412 struct meson_pwm_channel
*channel
= &channels
[i
];
414 snprintf(name
, sizeof(name
), "%s#mux%u", np
->full_name
, i
);
417 init
.ops
= &clk_mux_ops
;
418 init
.flags
= CLK_IS_BASIC
;
419 init
.parent_names
= meson
->data
->parent_names
;
420 init
.num_parents
= 1 << MISC_CLK_SEL_WIDTH
;
422 channel
->mux
.reg
= meson
->base
+ REG_MISC_AB
;
423 channel
->mux
.shift
= mux_reg_shifts
[i
];
424 channel
->mux
.mask
= BIT(MISC_CLK_SEL_WIDTH
) - 1;
425 channel
->mux
.flags
= 0;
426 channel
->mux
.lock
= &meson
->lock
;
427 channel
->mux
.table
= NULL
;
428 channel
->mux
.hw
.init
= &init
;
430 channel
->clk
= devm_clk_register(dev
, &channel
->mux
.hw
);
431 if (IS_ERR(channel
->clk
)) {
432 err
= PTR_ERR(channel
->clk
);
433 dev_err(dev
, "failed to register %s: %d\n", name
, err
);
437 snprintf(name
, sizeof(name
), "clkin%u", i
);
439 channel
->clk_parent
= devm_clk_get(dev
, name
);
440 if (IS_ERR(channel
->clk_parent
)) {
441 err
= PTR_ERR(channel
->clk_parent
);
442 if (err
== -EPROBE_DEFER
)
445 channel
->clk_parent
= NULL
;
452 static void meson_pwm_add_channels(struct meson_pwm
*meson
,
453 struct meson_pwm_channel
*channels
)
457 for (i
= 0; i
< meson
->chip
.npwm
; i
++)
458 pwm_set_chip_data(&meson
->chip
.pwms
[i
], &channels
[i
]);
461 static int meson_pwm_probe(struct platform_device
*pdev
)
463 struct meson_pwm_channel
*channels
;
464 struct meson_pwm
*meson
;
465 struct resource
*regs
;
468 meson
= devm_kzalloc(&pdev
->dev
, sizeof(*meson
), GFP_KERNEL
);
472 regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
473 meson
->base
= devm_ioremap_resource(&pdev
->dev
, regs
);
474 if (IS_ERR(meson
->base
))
475 return PTR_ERR(meson
->base
);
477 meson
->chip
.dev
= &pdev
->dev
;
478 meson
->chip
.ops
= &meson_pwm_ops
;
479 meson
->chip
.base
= -1;
480 meson
->chip
.npwm
= 2;
481 meson
->chip
.of_xlate
= of_pwm_xlate_with_flags
;
482 meson
->chip
.of_pwm_n_cells
= 3;
484 meson
->data
= of_device_get_match_data(&pdev
->dev
);
485 meson
->inverter_mask
= BIT(meson
->chip
.npwm
) - 1;
487 channels
= devm_kcalloc(&pdev
->dev
, meson
->chip
.npwm
, sizeof(*meson
),
492 err
= meson_pwm_init_channels(meson
, channels
);
496 err
= pwmchip_add(&meson
->chip
);
498 dev_err(&pdev
->dev
, "failed to register PWM chip: %d\n", err
);
502 meson_pwm_add_channels(meson
, channels
);
504 platform_set_drvdata(pdev
, meson
);
509 static int meson_pwm_remove(struct platform_device
*pdev
)
511 struct meson_pwm
*meson
= platform_get_drvdata(pdev
);
513 return pwmchip_remove(&meson
->chip
);
516 static struct platform_driver meson_pwm_driver
= {
519 .of_match_table
= meson_pwm_matches
,
521 .probe
= meson_pwm_probe
,
522 .remove
= meson_pwm_remove
,
524 module_platform_driver(meson_pwm_driver
);
526 MODULE_ALIAS("platform:meson-pwm");
527 MODULE_DESCRIPTION("Amlogic Meson PWM Generator driver");
528 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
529 MODULE_LICENSE("Dual BSD/GPL");