diff options
| author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2024-05-28 22:21:34 +0200 | 
|---|---|---|
| committer | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2024-05-28 22:21:34 +0200 | 
| commit | f73a058be5d70dd81a43f16b2bbff4b1576a7af8 (patch) | |
| tree | b7959c01cf7a5d95c7c4d5b61929ff9123370322 /drivers/pwm/pwm-meson.c | |
| parent | 6cb05d89fd62a76a9b74bd16211fb0930e89fea8 (diff) | |
| parent | 3e049b6b8f32f25c6967f4cffd8eac6e1e5316f6 (diff) | |
Merge remote-tracking branch 'drm/drm-fixes' into drm-misc-fixes
v6.10-rc1 is released, forward from v6.9
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'drivers/pwm/pwm-meson.c')
| -rw-r--r-- | drivers/pwm/pwm-meson.c | 213 | 
1 files changed, 129 insertions, 84 deletions
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index a02fdbc61256..b2f97dfb01bb 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -98,6 +98,7 @@ struct meson_pwm_channel {  struct meson_pwm_data {  	const char *const parent_names[MESON_NUM_MUX_PARENTS]; +	int (*channels_init)(struct pwm_chip *chip);  };  struct meson_pwm { @@ -147,7 +148,7 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,  	struct meson_pwm *meson = to_meson_pwm(chip);  	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];  	unsigned int cnt, duty_cnt; -	unsigned long fin_freq; +	long fin_freq;  	u64 duty, period, freq;  	duty = state->duty_cycle; @@ -167,14 +168,15 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,  		freq = ULONG_MAX;  	fin_freq = clk_round_rate(channel->clk, freq); -	if (fin_freq == 0) { -		dev_err(pwmchip_parent(chip), "invalid source clock frequency\n"); -		return -EINVAL; +	if (fin_freq <= 0) { +		dev_err(pwmchip_parent(chip), +			"invalid source clock frequency %llu\n", freq); +		return fin_freq ? fin_freq : -EINVAL;  	} -	dev_dbg(pwmchip_parent(chip), "fin_freq: %lu Hz\n", fin_freq); +	dev_dbg(pwmchip_parent(chip), "fin_freq: %ld Hz\n", fin_freq); -	cnt = div_u64(fin_freq * period, NSEC_PER_SEC); +	cnt = mul_u64_u64_div_u64(fin_freq, period, NSEC_PER_SEC);  	if (cnt > 0xffff) {  		dev_err(pwmchip_parent(chip), "unable to get period cnt\n");  		return -EINVAL; @@ -189,7 +191,7 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,  		channel->hi = 0;  		channel->lo = cnt;  	} else { -		duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC); +		duty_cnt = mul_u64_u64_div_u64(fin_freq, duty, NSEC_PER_SEC);  		dev_dbg(pwmchip_parent(chip), "duty=%llu duty_cnt=%u\n", duty, duty_cnt); @@ -310,9 +312,6 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,  	struct meson_pwm_channel *channel;  	u32 value; -	if (!state) -		return 0; -  	channel = &meson->channels[pwm->hwpwm];  	channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; @@ -338,86 +337,16 @@ static const struct pwm_ops meson_pwm_ops = {  	.get_state = meson_pwm_get_state,  }; -static const struct meson_pwm_data pwm_meson8b_data = { -	.parent_names = { "xtal", NULL, "fclk_div4", "fclk_div3" }, -}; - -/* - * Only the 2 first inputs of the GXBB AO PWMs are valid - * The last 2 are grounded - */ -static const struct meson_pwm_data pwm_gxbb_ao_data = { -	.parent_names = { "xtal", "clk81", NULL, NULL }, -}; - -static const struct meson_pwm_data pwm_axg_ee_data = { -	.parent_names = { "xtal", "fclk_div5", "fclk_div4", "fclk_div3" }, -}; - -static const struct meson_pwm_data pwm_axg_ao_data = { -	.parent_names = { "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5" }, -}; - -static const struct meson_pwm_data pwm_g12a_ao_ab_data = { -	.parent_names = { "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5" }, -}; - -static const struct meson_pwm_data pwm_g12a_ao_cd_data = { -	.parent_names = { "xtal", "g12a_ao_clk81", NULL, NULL }, -}; - -static const struct of_device_id meson_pwm_matches[] = { -	{ -		.compatible = "amlogic,meson8b-pwm", -		.data = &pwm_meson8b_data -	}, -	{ -		.compatible = "amlogic,meson-gxbb-pwm", -		.data = &pwm_meson8b_data -	}, -	{ -		.compatible = "amlogic,meson-gxbb-ao-pwm", -		.data = &pwm_gxbb_ao_data -	}, -	{ -		.compatible = "amlogic,meson-axg-ee-pwm", -		.data = &pwm_axg_ee_data -	}, -	{ -		.compatible = "amlogic,meson-axg-ao-pwm", -		.data = &pwm_axg_ao_data -	}, -	{ -		.compatible = "amlogic,meson-g12a-ee-pwm", -		.data = &pwm_meson8b_data -	}, -	{ -		.compatible = "amlogic,meson-g12a-ao-pwm-ab", -		.data = &pwm_g12a_ao_ab_data -	}, -	{ -		.compatible = "amlogic,meson-g12a-ao-pwm-cd", -		.data = &pwm_g12a_ao_cd_data -	}, -	{}, -}; -MODULE_DEVICE_TABLE(of, meson_pwm_matches); - -static int meson_pwm_init_channels(struct pwm_chip *chip) +static int meson_pwm_init_clocks_meson8b(struct pwm_chip *chip, +					 struct clk_parent_data *mux_parent_data)  {  	struct meson_pwm *meson = to_meson_pwm(chip); -	struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {};  	struct device *dev = pwmchip_parent(chip);  	unsigned int i;  	char name[255];  	int err; -	for (i = 0; i < MESON_NUM_MUX_PARENTS; i++) { -		mux_parent_data[i].index = -1; -		mux_parent_data[i].name = meson->data->parent_names[i]; -	} - -	for (i = 0; i < chip->npwm; i++) { +	for (i = 0; i < MESON_NUM_PWMS; i++) {  		struct meson_pwm_channel *channel = &meson->channels[i];  		struct clk_parent_data div_parent = {}, gate_parent = {};  		struct clk_init_data init = {}; @@ -495,6 +424,122 @@ static int meson_pwm_init_channels(struct pwm_chip *chip)  	return 0;  } +static int meson_pwm_init_channels_meson8b_legacy(struct pwm_chip *chip) +{ +	struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {}; +	struct meson_pwm *meson = to_meson_pwm(chip); +	int i; + +	dev_warn_once(pwmchip_parent(chip), +		      "using obsolete compatible, please consider updating dt\n"); + +	for (i = 0; i < MESON_NUM_MUX_PARENTS; i++) { +		mux_parent_data[i].index = -1; +		mux_parent_data[i].name = meson->data->parent_names[i]; +	} + +	return meson_pwm_init_clocks_meson8b(chip, mux_parent_data); +} + +static int meson_pwm_init_channels_meson8b_v2(struct pwm_chip *chip) +{ +	struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {}; +	int i; + +	/* +	 * NOTE: Instead of relying on the hard coded names in the driver +	 * as the legacy version, this relies on DT to provide the list of +	 * clocks. +	 * For once, using input numbers actually makes more sense than names. +	 * Also DT requires clock-names to be explicitly ordered, so there is +	 * no point bothering with clock names in this case. +	 */ +	for (i = 0; i < MESON_NUM_MUX_PARENTS; i++) +		mux_parent_data[i].index = i; + +	return meson_pwm_init_clocks_meson8b(chip, mux_parent_data); +} + +static const struct meson_pwm_data pwm_meson8b_data = { +	.parent_names = { "xtal", NULL, "fclk_div4", "fclk_div3" }, +	.channels_init = meson_pwm_init_channels_meson8b_legacy, +}; + +/* + * Only the 2 first inputs of the GXBB AO PWMs are valid + * The last 2 are grounded + */ +static const struct meson_pwm_data pwm_gxbb_ao_data = { +	.parent_names = { "xtal", "clk81", NULL, NULL }, +	.channels_init = meson_pwm_init_channels_meson8b_legacy, +}; + +static const struct meson_pwm_data pwm_axg_ee_data = { +	.parent_names = { "xtal", "fclk_div5", "fclk_div4", "fclk_div3" }, +	.channels_init = meson_pwm_init_channels_meson8b_legacy, +}; + +static const struct meson_pwm_data pwm_axg_ao_data = { +	.parent_names = { "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5" }, +	.channels_init = meson_pwm_init_channels_meson8b_legacy, +}; + +static const struct meson_pwm_data pwm_g12a_ao_ab_data = { +	.parent_names = { "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5" }, +	.channels_init = meson_pwm_init_channels_meson8b_legacy, +}; + +static const struct meson_pwm_data pwm_g12a_ao_cd_data = { +	.parent_names = { "xtal", "g12a_ao_clk81", NULL, NULL }, +	.channels_init = meson_pwm_init_channels_meson8b_legacy, +}; + +static const struct meson_pwm_data pwm_meson8_v2_data = { +	.channels_init = meson_pwm_init_channels_meson8b_v2, +}; + +static const struct of_device_id meson_pwm_matches[] = { +	{ +		.compatible = "amlogic,meson8-pwm-v2", +		.data = &pwm_meson8_v2_data +	}, +	/* The following compatibles are obsolete */ +	{ +		.compatible = "amlogic,meson8b-pwm", +		.data = &pwm_meson8b_data +	}, +	{ +		.compatible = "amlogic,meson-gxbb-pwm", +		.data = &pwm_meson8b_data +	}, +	{ +		.compatible = "amlogic,meson-gxbb-ao-pwm", +		.data = &pwm_gxbb_ao_data +	}, +	{ +		.compatible = "amlogic,meson-axg-ee-pwm", +		.data = &pwm_axg_ee_data +	}, +	{ +		.compatible = "amlogic,meson-axg-ao-pwm", +		.data = &pwm_axg_ao_data +	}, +	{ +		.compatible = "amlogic,meson-g12a-ee-pwm", +		.data = &pwm_meson8b_data +	}, +	{ +		.compatible = "amlogic,meson-g12a-ao-pwm-ab", +		.data = &pwm_g12a_ao_ab_data +	}, +	{ +		.compatible = "amlogic,meson-g12a-ao-pwm-cd", +		.data = &pwm_g12a_ao_cd_data +	}, +	{}, +}; +MODULE_DEVICE_TABLE(of, meson_pwm_matches); +  static int meson_pwm_probe(struct platform_device *pdev)  {  	struct pwm_chip *chip; @@ -515,7 +560,7 @@ static int meson_pwm_probe(struct platform_device *pdev)  	meson->data = of_device_get_match_data(&pdev->dev); -	err = meson_pwm_init_channels(chip); +	err = meson->data->channels_init(chip);  	if (err < 0)  		return err;  | 
