162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PWM controller driver for Amlogic Meson SoCs.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This PWM is only a set of Gates, Dividers and Counters:
662306a36Sopenharmony_ci * PWM output is achieved by calculating a clock that permits calculating
762306a36Sopenharmony_ci * two periods (low and high). The counter then has to be set to switch after
862306a36Sopenharmony_ci * N cycles for the first half period.
962306a36Sopenharmony_ci * The hardware has no "polarity" setting. This driver reverses the period
1062306a36Sopenharmony_ci * cycles (the low length is inverted with the high length) for
1162306a36Sopenharmony_ci * PWM_POLARITY_INVERSED. This means that .get_state cannot read the polarity
1262306a36Sopenharmony_ci * from the hardware.
1362306a36Sopenharmony_ci * Setting the duty cycle will disable and re-enable the PWM output.
1462306a36Sopenharmony_ci * Disabling the PWM stops the output immediately (without waiting for the
1562306a36Sopenharmony_ci * current period to complete first).
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * The public S912 (GXM) datasheet contains some documentation for this PWM
1862306a36Sopenharmony_ci * controller starting on page 543:
1962306a36Sopenharmony_ci * https://dl.khadas.com/Hardware/VIM2/Datasheet/S912_Datasheet_V0.220170314publicversion-Wesion.pdf
2062306a36Sopenharmony_ci * An updated version of this IP block is found in S922X (G12B) SoCs. The
2162306a36Sopenharmony_ci * datasheet contains the description for this IP block revision starting at
2262306a36Sopenharmony_ci * page 1084:
2362306a36Sopenharmony_ci * https://dn.odroid.com/S922X/ODROID-N2/Datasheet/S922X_Public_Datasheet_V0.2.pdf
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Copyright (c) 2016 BayLibre, SAS.
2662306a36Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
2762306a36Sopenharmony_ci * Copyright (C) 2014 Amlogic, Inc.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/bitfield.h>
3162306a36Sopenharmony_ci#include <linux/bits.h>
3262306a36Sopenharmony_ci#include <linux/clk.h>
3362306a36Sopenharmony_ci#include <linux/clk-provider.h>
3462306a36Sopenharmony_ci#include <linux/err.h>
3562306a36Sopenharmony_ci#include <linux/io.h>
3662306a36Sopenharmony_ci#include <linux/kernel.h>
3762306a36Sopenharmony_ci#include <linux/math64.h>
3862306a36Sopenharmony_ci#include <linux/module.h>
3962306a36Sopenharmony_ci#include <linux/of.h>
4062306a36Sopenharmony_ci#include <linux/platform_device.h>
4162306a36Sopenharmony_ci#include <linux/pwm.h>
4262306a36Sopenharmony_ci#include <linux/slab.h>
4362306a36Sopenharmony_ci#include <linux/spinlock.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define REG_PWM_A		0x0
4662306a36Sopenharmony_ci#define REG_PWM_B		0x4
4762306a36Sopenharmony_ci#define PWM_LOW_MASK		GENMASK(15, 0)
4862306a36Sopenharmony_ci#define PWM_HIGH_MASK		GENMASK(31, 16)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define REG_MISC_AB		0x8
5162306a36Sopenharmony_ci#define MISC_B_CLK_EN_SHIFT	23
5262306a36Sopenharmony_ci#define MISC_A_CLK_EN_SHIFT	15
5362306a36Sopenharmony_ci#define MISC_CLK_DIV_WIDTH	7
5462306a36Sopenharmony_ci#define MISC_B_CLK_DIV_SHIFT	16
5562306a36Sopenharmony_ci#define MISC_A_CLK_DIV_SHIFT	8
5662306a36Sopenharmony_ci#define MISC_B_CLK_SEL_SHIFT	6
5762306a36Sopenharmony_ci#define MISC_A_CLK_SEL_SHIFT	4
5862306a36Sopenharmony_ci#define MISC_CLK_SEL_MASK	0x3
5962306a36Sopenharmony_ci#define MISC_B_EN		BIT(1)
6062306a36Sopenharmony_ci#define MISC_A_EN		BIT(0)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define MESON_NUM_PWMS		2
6362306a36Sopenharmony_ci#define MESON_MAX_MUX_PARENTS	4
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic struct meson_pwm_channel_data {
6662306a36Sopenharmony_ci	u8		reg_offset;
6762306a36Sopenharmony_ci	u8		clk_sel_shift;
6862306a36Sopenharmony_ci	u8		clk_div_shift;
6962306a36Sopenharmony_ci	u8		clk_en_shift;
7062306a36Sopenharmony_ci	u32		pwm_en_mask;
7162306a36Sopenharmony_ci} meson_pwm_per_channel_data[MESON_NUM_PWMS] = {
7262306a36Sopenharmony_ci	{
7362306a36Sopenharmony_ci		.reg_offset	= REG_PWM_A,
7462306a36Sopenharmony_ci		.clk_sel_shift	= MISC_A_CLK_SEL_SHIFT,
7562306a36Sopenharmony_ci		.clk_div_shift	= MISC_A_CLK_DIV_SHIFT,
7662306a36Sopenharmony_ci		.clk_en_shift	= MISC_A_CLK_EN_SHIFT,
7762306a36Sopenharmony_ci		.pwm_en_mask	= MISC_A_EN,
7862306a36Sopenharmony_ci	},
7962306a36Sopenharmony_ci	{
8062306a36Sopenharmony_ci		.reg_offset	= REG_PWM_B,
8162306a36Sopenharmony_ci		.clk_sel_shift	= MISC_B_CLK_SEL_SHIFT,
8262306a36Sopenharmony_ci		.clk_div_shift	= MISC_B_CLK_DIV_SHIFT,
8362306a36Sopenharmony_ci		.clk_en_shift	= MISC_B_CLK_EN_SHIFT,
8462306a36Sopenharmony_ci		.pwm_en_mask	= MISC_B_EN,
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistruct meson_pwm_channel {
8962306a36Sopenharmony_ci	unsigned long rate;
9062306a36Sopenharmony_ci	unsigned int hi;
9162306a36Sopenharmony_ci	unsigned int lo;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	struct clk_mux mux;
9462306a36Sopenharmony_ci	struct clk_divider div;
9562306a36Sopenharmony_ci	struct clk_gate gate;
9662306a36Sopenharmony_ci	struct clk *clk;
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistruct meson_pwm_data {
10062306a36Sopenharmony_ci	const char * const *parent_names;
10162306a36Sopenharmony_ci	unsigned int num_parents;
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct meson_pwm {
10562306a36Sopenharmony_ci	struct pwm_chip chip;
10662306a36Sopenharmony_ci	const struct meson_pwm_data *data;
10762306a36Sopenharmony_ci	struct meson_pwm_channel channels[MESON_NUM_PWMS];
10862306a36Sopenharmony_ci	void __iomem *base;
10962306a36Sopenharmony_ci	/*
11062306a36Sopenharmony_ci	 * Protects register (write) access to the REG_MISC_AB register
11162306a36Sopenharmony_ci	 * that is shared between the two PWMs.
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	spinlock_t lock;
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return container_of(chip, struct meson_pwm, chip);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct meson_pwm *meson = to_meson_pwm(chip);
12462306a36Sopenharmony_ci	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
12562306a36Sopenharmony_ci	struct device *dev = chip->dev;
12662306a36Sopenharmony_ci	int err;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	err = clk_prepare_enable(channel->clk);
12962306a36Sopenharmony_ci	if (err < 0) {
13062306a36Sopenharmony_ci		dev_err(dev, "failed to enable clock %s: %d\n",
13162306a36Sopenharmony_ci			__clk_get_name(channel->clk), err);
13262306a36Sopenharmony_ci		return err;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct meson_pwm *meson = to_meson_pwm(chip);
14162306a36Sopenharmony_ci	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	clk_disable_unprepare(channel->clk);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
14762306a36Sopenharmony_ci			  const struct pwm_state *state)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
15062306a36Sopenharmony_ci	unsigned int cnt, duty_cnt;
15162306a36Sopenharmony_ci	unsigned long fin_freq;
15262306a36Sopenharmony_ci	u64 duty, period, freq;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	duty = state->duty_cycle;
15562306a36Sopenharmony_ci	period = state->period;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/*
15862306a36Sopenharmony_ci	 * Note this is wrong. The result is an output wave that isn't really
15962306a36Sopenharmony_ci	 * inverted and so is wrongly identified by .get_state as normal.
16062306a36Sopenharmony_ci	 * Fixing this needs some care however as some machines might rely on
16162306a36Sopenharmony_ci	 * this.
16262306a36Sopenharmony_ci	 */
16362306a36Sopenharmony_ci	if (state->polarity == PWM_POLARITY_INVERSED)
16462306a36Sopenharmony_ci		duty = period - duty;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	freq = div64_u64(NSEC_PER_SEC * 0xffffULL, period);
16762306a36Sopenharmony_ci	if (freq > ULONG_MAX)
16862306a36Sopenharmony_ci		freq = ULONG_MAX;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	fin_freq = clk_round_rate(channel->clk, freq);
17162306a36Sopenharmony_ci	if (fin_freq == 0) {
17262306a36Sopenharmony_ci		dev_err(meson->chip.dev, "invalid source clock frequency\n");
17362306a36Sopenharmony_ci		return -EINVAL;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	cnt = div_u64(fin_freq * period, NSEC_PER_SEC);
17962306a36Sopenharmony_ci	if (cnt > 0xffff) {
18062306a36Sopenharmony_ci		dev_err(meson->chip.dev, "unable to get period cnt\n");
18162306a36Sopenharmony_ci		return -EINVAL;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	dev_dbg(meson->chip.dev, "period=%llu cnt=%u\n", period, cnt);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (duty == period) {
18762306a36Sopenharmony_ci		channel->hi = cnt;
18862306a36Sopenharmony_ci		channel->lo = 0;
18962306a36Sopenharmony_ci	} else if (duty == 0) {
19062306a36Sopenharmony_ci		channel->hi = 0;
19162306a36Sopenharmony_ci		channel->lo = cnt;
19262306a36Sopenharmony_ci	} else {
19362306a36Sopenharmony_ci		duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		dev_dbg(meson->chip.dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		channel->hi = duty_cnt;
19862306a36Sopenharmony_ci		channel->lo = cnt - duty_cnt;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	channel->rate = fin_freq;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
20962306a36Sopenharmony_ci	struct meson_pwm_channel_data *channel_data;
21062306a36Sopenharmony_ci	unsigned long flags;
21162306a36Sopenharmony_ci	u32 value;
21262306a36Sopenharmony_ci	int err;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	err = clk_set_rate(channel->clk, channel->rate);
21762306a36Sopenharmony_ci	if (err)
21862306a36Sopenharmony_ci		dev_err(meson->chip.dev, "setting clock rate failed\n");
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	spin_lock_irqsave(&meson->lock, flags);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) |
22362306a36Sopenharmony_ci		FIELD_PREP(PWM_LOW_MASK, channel->lo);
22462306a36Sopenharmony_ci	writel(value, meson->base + channel_data->reg_offset);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	value = readl(meson->base + REG_MISC_AB);
22762306a36Sopenharmony_ci	value |= channel_data->pwm_en_mask;
22862306a36Sopenharmony_ci	writel(value, meson->base + REG_MISC_AB);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	spin_unlock_irqrestore(&meson->lock, flags);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	unsigned long flags;
23662306a36Sopenharmony_ci	u32 value;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	spin_lock_irqsave(&meson->lock, flags);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	value = readl(meson->base + REG_MISC_AB);
24162306a36Sopenharmony_ci	value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask;
24262306a36Sopenharmony_ci	writel(value, meson->base + REG_MISC_AB);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	spin_unlock_irqrestore(&meson->lock, flags);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
24862306a36Sopenharmony_ci			   const struct pwm_state *state)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct meson_pwm *meson = to_meson_pwm(chip);
25162306a36Sopenharmony_ci	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
25262306a36Sopenharmony_ci	int err = 0;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (!state->enabled) {
25562306a36Sopenharmony_ci		if (state->polarity == PWM_POLARITY_INVERSED) {
25662306a36Sopenharmony_ci			/*
25762306a36Sopenharmony_ci			 * This IP block revision doesn't have an "always high"
25862306a36Sopenharmony_ci			 * setting which we can use for "inverted disabled".
25962306a36Sopenharmony_ci			 * Instead we achieve this by setting mux parent with
26062306a36Sopenharmony_ci			 * highest rate and minimum divider value, resulting
26162306a36Sopenharmony_ci			 * in the shortest possible duration for one "count"
26262306a36Sopenharmony_ci			 * and "period == duty_cycle". This results in a signal
26362306a36Sopenharmony_ci			 * which is LOW for one "count", while being HIGH for
26462306a36Sopenharmony_ci			 * the rest of the (so the signal is HIGH for slightly
26562306a36Sopenharmony_ci			 * less than 100% of the period, but this is the best
26662306a36Sopenharmony_ci			 * we can achieve).
26762306a36Sopenharmony_ci			 */
26862306a36Sopenharmony_ci			channel->rate = ULONG_MAX;
26962306a36Sopenharmony_ci			channel->hi = ~0;
27062306a36Sopenharmony_ci			channel->lo = 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci			meson_pwm_enable(meson, pwm);
27362306a36Sopenharmony_ci		} else {
27462306a36Sopenharmony_ci			meson_pwm_disable(meson, pwm);
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci	} else {
27762306a36Sopenharmony_ci		err = meson_pwm_calc(meson, pwm, state);
27862306a36Sopenharmony_ci		if (err < 0)
27962306a36Sopenharmony_ci			return err;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		meson_pwm_enable(meson, pwm);
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return 0;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic u64 meson_pwm_cnt_to_ns(struct pwm_chip *chip, struct pwm_device *pwm,
28862306a36Sopenharmony_ci			       u32 cnt)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct meson_pwm *meson = to_meson_pwm(chip);
29162306a36Sopenharmony_ci	struct meson_pwm_channel *channel;
29262306a36Sopenharmony_ci	unsigned long fin_freq;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* to_meson_pwm() can only be used after .get_state() is called */
29562306a36Sopenharmony_ci	channel = &meson->channels[pwm->hwpwm];
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	fin_freq = clk_get_rate(channel->clk);
29862306a36Sopenharmony_ci	if (fin_freq == 0)
29962306a36Sopenharmony_ci		return 0;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return div64_ul(NSEC_PER_SEC * (u64)cnt, fin_freq);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
30562306a36Sopenharmony_ci			       struct pwm_state *state)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct meson_pwm *meson = to_meson_pwm(chip);
30862306a36Sopenharmony_ci	struct meson_pwm_channel_data *channel_data;
30962306a36Sopenharmony_ci	struct meson_pwm_channel *channel;
31062306a36Sopenharmony_ci	u32 value;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (!state)
31362306a36Sopenharmony_ci		return 0;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	channel = &meson->channels[pwm->hwpwm];
31662306a36Sopenharmony_ci	channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	value = readl(meson->base + REG_MISC_AB);
31962306a36Sopenharmony_ci	state->enabled = value & channel_data->pwm_en_mask;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	value = readl(meson->base + channel_data->reg_offset);
32262306a36Sopenharmony_ci	channel->lo = FIELD_GET(PWM_LOW_MASK, value);
32362306a36Sopenharmony_ci	channel->hi = FIELD_GET(PWM_HIGH_MASK, value);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->lo + channel->hi);
32662306a36Sopenharmony_ci	state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, channel->hi);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	state->polarity = PWM_POLARITY_NORMAL;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic const struct pwm_ops meson_pwm_ops = {
33462306a36Sopenharmony_ci	.request = meson_pwm_request,
33562306a36Sopenharmony_ci	.free = meson_pwm_free,
33662306a36Sopenharmony_ci	.apply = meson_pwm_apply,
33762306a36Sopenharmony_ci	.get_state = meson_pwm_get_state,
33862306a36Sopenharmony_ci	.owner = THIS_MODULE,
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic const char * const pwm_meson8b_parent_names[] = {
34262306a36Sopenharmony_ci	"xtal", NULL, "fclk_div4", "fclk_div3"
34362306a36Sopenharmony_ci};
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic const struct meson_pwm_data pwm_meson8b_data = {
34662306a36Sopenharmony_ci	.parent_names = pwm_meson8b_parent_names,
34762306a36Sopenharmony_ci	.num_parents = ARRAY_SIZE(pwm_meson8b_parent_names),
34862306a36Sopenharmony_ci};
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci/*
35162306a36Sopenharmony_ci * Only the 2 first inputs of the GXBB AO PWMs are valid
35262306a36Sopenharmony_ci * The last 2 are grounded
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_cistatic const char * const pwm_gxbb_ao_parent_names[] = {
35562306a36Sopenharmony_ci	"xtal", "clk81"
35662306a36Sopenharmony_ci};
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic const struct meson_pwm_data pwm_gxbb_ao_data = {
35962306a36Sopenharmony_ci	.parent_names = pwm_gxbb_ao_parent_names,
36062306a36Sopenharmony_ci	.num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_names),
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic const char * const pwm_axg_ee_parent_names[] = {
36462306a36Sopenharmony_ci	"xtal", "fclk_div5", "fclk_div4", "fclk_div3"
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic const struct meson_pwm_data pwm_axg_ee_data = {
36862306a36Sopenharmony_ci	.parent_names = pwm_axg_ee_parent_names,
36962306a36Sopenharmony_ci	.num_parents = ARRAY_SIZE(pwm_axg_ee_parent_names),
37062306a36Sopenharmony_ci};
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic const char * const pwm_axg_ao_parent_names[] = {
37362306a36Sopenharmony_ci	"xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5"
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic const struct meson_pwm_data pwm_axg_ao_data = {
37762306a36Sopenharmony_ci	.parent_names = pwm_axg_ao_parent_names,
37862306a36Sopenharmony_ci	.num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names),
37962306a36Sopenharmony_ci};
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic const char * const pwm_g12a_ao_ab_parent_names[] = {
38262306a36Sopenharmony_ci	"xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5"
38362306a36Sopenharmony_ci};
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic const struct meson_pwm_data pwm_g12a_ao_ab_data = {
38662306a36Sopenharmony_ci	.parent_names = pwm_g12a_ao_ab_parent_names,
38762306a36Sopenharmony_ci	.num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_names),
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic const char * const pwm_g12a_ao_cd_parent_names[] = {
39162306a36Sopenharmony_ci	"xtal", "g12a_ao_clk81",
39262306a36Sopenharmony_ci};
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic const struct meson_pwm_data pwm_g12a_ao_cd_data = {
39562306a36Sopenharmony_ci	.parent_names = pwm_g12a_ao_cd_parent_names,
39662306a36Sopenharmony_ci	.num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_names),
39762306a36Sopenharmony_ci};
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic const struct of_device_id meson_pwm_matches[] = {
40062306a36Sopenharmony_ci	{
40162306a36Sopenharmony_ci		.compatible = "amlogic,meson8b-pwm",
40262306a36Sopenharmony_ci		.data = &pwm_meson8b_data
40362306a36Sopenharmony_ci	},
40462306a36Sopenharmony_ci	{
40562306a36Sopenharmony_ci		.compatible = "amlogic,meson-gxbb-pwm",
40662306a36Sopenharmony_ci		.data = &pwm_meson8b_data
40762306a36Sopenharmony_ci	},
40862306a36Sopenharmony_ci	{
40962306a36Sopenharmony_ci		.compatible = "amlogic,meson-gxbb-ao-pwm",
41062306a36Sopenharmony_ci		.data = &pwm_gxbb_ao_data
41162306a36Sopenharmony_ci	},
41262306a36Sopenharmony_ci	{
41362306a36Sopenharmony_ci		.compatible = "amlogic,meson-axg-ee-pwm",
41462306a36Sopenharmony_ci		.data = &pwm_axg_ee_data
41562306a36Sopenharmony_ci	},
41662306a36Sopenharmony_ci	{
41762306a36Sopenharmony_ci		.compatible = "amlogic,meson-axg-ao-pwm",
41862306a36Sopenharmony_ci		.data = &pwm_axg_ao_data
41962306a36Sopenharmony_ci	},
42062306a36Sopenharmony_ci	{
42162306a36Sopenharmony_ci		.compatible = "amlogic,meson-g12a-ee-pwm",
42262306a36Sopenharmony_ci		.data = &pwm_meson8b_data
42362306a36Sopenharmony_ci	},
42462306a36Sopenharmony_ci	{
42562306a36Sopenharmony_ci		.compatible = "amlogic,meson-g12a-ao-pwm-ab",
42662306a36Sopenharmony_ci		.data = &pwm_g12a_ao_ab_data
42762306a36Sopenharmony_ci	},
42862306a36Sopenharmony_ci	{
42962306a36Sopenharmony_ci		.compatible = "amlogic,meson-g12a-ao-pwm-cd",
43062306a36Sopenharmony_ci		.data = &pwm_g12a_ao_cd_data
43162306a36Sopenharmony_ci	},
43262306a36Sopenharmony_ci	{},
43362306a36Sopenharmony_ci};
43462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, meson_pwm_matches);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int meson_pwm_init_channels(struct meson_pwm *meson)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	struct clk_parent_data mux_parent_data[MESON_MAX_MUX_PARENTS] = {};
43962306a36Sopenharmony_ci	struct device *dev = meson->chip.dev;
44062306a36Sopenharmony_ci	unsigned int i;
44162306a36Sopenharmony_ci	char name[255];
44262306a36Sopenharmony_ci	int err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	for (i = 0; i < meson->data->num_parents; i++) {
44562306a36Sopenharmony_ci		mux_parent_data[i].index = -1;
44662306a36Sopenharmony_ci		mux_parent_data[i].name = meson->data->parent_names[i];
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	for (i = 0; i < meson->chip.npwm; i++) {
45062306a36Sopenharmony_ci		struct meson_pwm_channel *channel = &meson->channels[i];
45162306a36Sopenharmony_ci		struct clk_parent_data div_parent = {}, gate_parent = {};
45262306a36Sopenharmony_ci		struct clk_init_data init = {};
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		init.name = name;
45762306a36Sopenharmony_ci		init.ops = &clk_mux_ops;
45862306a36Sopenharmony_ci		init.flags = 0;
45962306a36Sopenharmony_ci		init.parent_data = mux_parent_data;
46062306a36Sopenharmony_ci		init.num_parents = meson->data->num_parents;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		channel->mux.reg = meson->base + REG_MISC_AB;
46362306a36Sopenharmony_ci		channel->mux.shift =
46462306a36Sopenharmony_ci				meson_pwm_per_channel_data[i].clk_sel_shift;
46562306a36Sopenharmony_ci		channel->mux.mask = MISC_CLK_SEL_MASK;
46662306a36Sopenharmony_ci		channel->mux.flags = 0;
46762306a36Sopenharmony_ci		channel->mux.lock = &meson->lock;
46862306a36Sopenharmony_ci		channel->mux.table = NULL;
46962306a36Sopenharmony_ci		channel->mux.hw.init = &init;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		err = devm_clk_hw_register(dev, &channel->mux.hw);
47262306a36Sopenharmony_ci		if (err) {
47362306a36Sopenharmony_ci			dev_err(dev, "failed to register %s: %d\n", name, err);
47462306a36Sopenharmony_ci			return err;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		snprintf(name, sizeof(name), "%s#div%u", dev_name(dev), i);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		init.name = name;
48062306a36Sopenharmony_ci		init.ops = &clk_divider_ops;
48162306a36Sopenharmony_ci		init.flags = CLK_SET_RATE_PARENT;
48262306a36Sopenharmony_ci		div_parent.index = -1;
48362306a36Sopenharmony_ci		div_parent.hw = &channel->mux.hw;
48462306a36Sopenharmony_ci		init.parent_data = &div_parent;
48562306a36Sopenharmony_ci		init.num_parents = 1;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		channel->div.reg = meson->base + REG_MISC_AB;
48862306a36Sopenharmony_ci		channel->div.shift = meson_pwm_per_channel_data[i].clk_div_shift;
48962306a36Sopenharmony_ci		channel->div.width = MISC_CLK_DIV_WIDTH;
49062306a36Sopenharmony_ci		channel->div.hw.init = &init;
49162306a36Sopenharmony_ci		channel->div.flags = 0;
49262306a36Sopenharmony_ci		channel->div.lock = &meson->lock;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		err = devm_clk_hw_register(dev, &channel->div.hw);
49562306a36Sopenharmony_ci		if (err) {
49662306a36Sopenharmony_ci			dev_err(dev, "failed to register %s: %d\n", name, err);
49762306a36Sopenharmony_ci			return err;
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		snprintf(name, sizeof(name), "%s#gate%u", dev_name(dev), i);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		init.name = name;
50362306a36Sopenharmony_ci		init.ops = &clk_gate_ops;
50462306a36Sopenharmony_ci		init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED;
50562306a36Sopenharmony_ci		gate_parent.index = -1;
50662306a36Sopenharmony_ci		gate_parent.hw = &channel->div.hw;
50762306a36Sopenharmony_ci		init.parent_data = &gate_parent;
50862306a36Sopenharmony_ci		init.num_parents = 1;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		channel->gate.reg = meson->base + REG_MISC_AB;
51162306a36Sopenharmony_ci		channel->gate.bit_idx = meson_pwm_per_channel_data[i].clk_en_shift;
51262306a36Sopenharmony_ci		channel->gate.hw.init = &init;
51362306a36Sopenharmony_ci		channel->gate.flags = 0;
51462306a36Sopenharmony_ci		channel->gate.lock = &meson->lock;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		err = devm_clk_hw_register(dev, &channel->gate.hw);
51762306a36Sopenharmony_ci		if (err) {
51862306a36Sopenharmony_ci			dev_err(dev, "failed to register %s: %d\n", name, err);
51962306a36Sopenharmony_ci			return err;
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		channel->clk = devm_clk_hw_get_clk(dev, &channel->gate.hw, NULL);
52362306a36Sopenharmony_ci		if (IS_ERR(channel->clk)) {
52462306a36Sopenharmony_ci			err = PTR_ERR(channel->clk);
52562306a36Sopenharmony_ci			dev_err(dev, "failed to register %s: %d\n", name, err);
52662306a36Sopenharmony_ci			return err;
52762306a36Sopenharmony_ci		}
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return 0;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic int meson_pwm_probe(struct platform_device *pdev)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct meson_pwm *meson;
53662306a36Sopenharmony_ci	int err;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL);
53962306a36Sopenharmony_ci	if (!meson)
54062306a36Sopenharmony_ci		return -ENOMEM;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	meson->base = devm_platform_ioremap_resource(pdev, 0);
54362306a36Sopenharmony_ci	if (IS_ERR(meson->base))
54462306a36Sopenharmony_ci		return PTR_ERR(meson->base);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	spin_lock_init(&meson->lock);
54762306a36Sopenharmony_ci	meson->chip.dev = &pdev->dev;
54862306a36Sopenharmony_ci	meson->chip.ops = &meson_pwm_ops;
54962306a36Sopenharmony_ci	meson->chip.npwm = MESON_NUM_PWMS;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	meson->data = of_device_get_match_data(&pdev->dev);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	err = meson_pwm_init_channels(meson);
55462306a36Sopenharmony_ci	if (err < 0)
55562306a36Sopenharmony_ci		return err;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	err = devm_pwmchip_add(&pdev->dev, &meson->chip);
55862306a36Sopenharmony_ci	if (err < 0) {
55962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
56062306a36Sopenharmony_ci		return err;
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return 0;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic struct platform_driver meson_pwm_driver = {
56762306a36Sopenharmony_ci	.driver = {
56862306a36Sopenharmony_ci		.name = "meson-pwm",
56962306a36Sopenharmony_ci		.of_match_table = meson_pwm_matches,
57062306a36Sopenharmony_ci	},
57162306a36Sopenharmony_ci	.probe = meson_pwm_probe,
57262306a36Sopenharmony_ci};
57362306a36Sopenharmony_cimodule_platform_driver(meson_pwm_driver);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ciMODULE_DESCRIPTION("Amlogic Meson PWM Generator driver");
57662306a36Sopenharmony_ciMODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
57762306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
578