18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Notes
88c2ecf20Sopenharmony_ci * =====
98c2ecf20Sopenharmony_ci * NXP LPC18xx provides a State Configurable Timer (SCT) which can be configured
108c2ecf20Sopenharmony_ci * as a Pulse Width Modulator.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * SCT supports 16 outputs, 16 events and 16 registers. Each event will be
138c2ecf20Sopenharmony_ci * triggered when its related register matches the SCT counter value, and it
148c2ecf20Sopenharmony_ci * will set or clear a selected output.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * One of the events is preselected to generate the period, thus the maximum
178c2ecf20Sopenharmony_ci * number of simultaneous channels is limited to 15. Notice that period is
188c2ecf20Sopenharmony_ci * global to all the channels, thus PWM driver will refuse setting different
198c2ecf20Sopenharmony_ci * values to it, unless there's only one channel requested.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/clk.h>
238c2ecf20Sopenharmony_ci#include <linux/err.h>
248c2ecf20Sopenharmony_ci#include <linux/io.h>
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
278c2ecf20Sopenharmony_ci#include <linux/pwm.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* LPC18xx SCT registers */
308c2ecf20Sopenharmony_ci#define LPC18XX_PWM_CONFIG		0x000
318c2ecf20Sopenharmony_ci#define LPC18XX_PWM_CONFIG_UNIFY	BIT(0)
328c2ecf20Sopenharmony_ci#define LPC18XX_PWM_CONFIG_NORELOAD	BIT(7)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define LPC18XX_PWM_CTRL		0x004
358c2ecf20Sopenharmony_ci#define LPC18XX_PWM_CTRL_HALT		BIT(2)
368c2ecf20Sopenharmony_ci#define LPC18XX_PWM_BIDIR		BIT(4)
378c2ecf20Sopenharmony_ci#define LPC18XX_PWM_PRE_SHIFT		5
388c2ecf20Sopenharmony_ci#define LPC18XX_PWM_PRE_MASK		(0xff << LPC18XX_PWM_PRE_SHIFT)
398c2ecf20Sopenharmony_ci#define LPC18XX_PWM_PRE(x)		(x << LPC18XX_PWM_PRE_SHIFT)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define LPC18XX_PWM_LIMIT		0x008
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define LPC18XX_PWM_RES_BASE		0x058
448c2ecf20Sopenharmony_ci#define LPC18XX_PWM_RES_SHIFT(_ch)	(_ch * 2)
458c2ecf20Sopenharmony_ci#define LPC18XX_PWM_RES(_ch, _action)	(_action << LPC18XX_PWM_RES_SHIFT(_ch))
468c2ecf20Sopenharmony_ci#define LPC18XX_PWM_RES_MASK(_ch)	(0x3 << LPC18XX_PWM_RES_SHIFT(_ch))
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define LPC18XX_PWM_MATCH_BASE		0x100
498c2ecf20Sopenharmony_ci#define LPC18XX_PWM_MATCH(_ch)		(LPC18XX_PWM_MATCH_BASE + _ch * 4)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define LPC18XX_PWM_MATCHREL_BASE	0x200
528c2ecf20Sopenharmony_ci#define LPC18XX_PWM_MATCHREL(_ch)	(LPC18XX_PWM_MATCHREL_BASE + _ch * 4)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVSTATEMSK_BASE	0x300
558c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVSTATEMSK(_ch)	(LPC18XX_PWM_EVSTATEMSK_BASE + _ch * 8)
568c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVSTATEMSK_ALL	0xffffffff
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVCTRL_BASE		0x304
598c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVCTRL(_ev)		(LPC18XX_PWM_EVCTRL_BASE + _ev * 8)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVCTRL_MATCH(_ch)	_ch
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVCTRL_COMB_SHIFT	12
648c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVCTRL_COMB_MATCH	(0x1 << LPC18XX_PWM_EVCTRL_COMB_SHIFT)
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define LPC18XX_PWM_OUTPUTSET_BASE	0x500
678c2ecf20Sopenharmony_ci#define LPC18XX_PWM_OUTPUTSET(_ch)	(LPC18XX_PWM_OUTPUTSET_BASE + _ch * 8)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define LPC18XX_PWM_OUTPUTCL_BASE	0x504
708c2ecf20Sopenharmony_ci#define LPC18XX_PWM_OUTPUTCL(_ch)	(LPC18XX_PWM_OUTPUTCL_BASE + _ch * 8)
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* LPC18xx SCT unified counter */
738c2ecf20Sopenharmony_ci#define LPC18XX_PWM_TIMER_MAX		0xffffffff
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* LPC18xx SCT events */
768c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVENT_PERIOD	0
778c2ecf20Sopenharmony_ci#define LPC18XX_PWM_EVENT_MAX		16
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* SCT conflict resolution */
808c2ecf20Sopenharmony_cienum lpc18xx_pwm_res_action {
818c2ecf20Sopenharmony_ci	LPC18XX_PWM_RES_NONE,
828c2ecf20Sopenharmony_ci	LPC18XX_PWM_RES_SET,
838c2ecf20Sopenharmony_ci	LPC18XX_PWM_RES_CLEAR,
848c2ecf20Sopenharmony_ci	LPC18XX_PWM_RES_TOGGLE,
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct lpc18xx_pwm_data {
888c2ecf20Sopenharmony_ci	unsigned int duty_event;
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistruct lpc18xx_pwm_chip {
928c2ecf20Sopenharmony_ci	struct device *dev;
938c2ecf20Sopenharmony_ci	struct pwm_chip chip;
948c2ecf20Sopenharmony_ci	void __iomem *base;
958c2ecf20Sopenharmony_ci	struct clk *pwm_clk;
968c2ecf20Sopenharmony_ci	unsigned long clk_rate;
978c2ecf20Sopenharmony_ci	unsigned int period_ns;
988c2ecf20Sopenharmony_ci	unsigned int min_period_ns;
998c2ecf20Sopenharmony_ci	unsigned int max_period_ns;
1008c2ecf20Sopenharmony_ci	unsigned int period_event;
1018c2ecf20Sopenharmony_ci	unsigned long event_map;
1028c2ecf20Sopenharmony_ci	struct mutex res_lock;
1038c2ecf20Sopenharmony_ci	struct mutex period_lock;
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline struct lpc18xx_pwm_chip *
1078c2ecf20Sopenharmony_cito_lpc18xx_pwm_chip(struct pwm_chip *chip)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	return container_of(chip, struct lpc18xx_pwm_chip, chip);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm,
1138c2ecf20Sopenharmony_ci				      u32 reg, u32 val)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	writel(val, lpc18xx_pwm->base + reg);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic inline u32 lpc18xx_pwm_readl(struct lpc18xx_pwm_chip *lpc18xx_pwm,
1198c2ecf20Sopenharmony_ci				    u32 reg)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	return readl(lpc18xx_pwm->base + reg);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip *lpc18xx_pwm,
1258c2ecf20Sopenharmony_ci					 struct pwm_device *pwm,
1268c2ecf20Sopenharmony_ci					 enum lpc18xx_pwm_res_action action)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	u32 val;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	mutex_lock(&lpc18xx_pwm->res_lock);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/*
1338c2ecf20Sopenharmony_ci	 * Simultaneous set and clear may happen on an output, that is the case
1348c2ecf20Sopenharmony_ci	 * when duty_ns == period_ns. LPC18xx SCT allows to set a conflict
1358c2ecf20Sopenharmony_ci	 * resolution action to be taken in such a case.
1368c2ecf20Sopenharmony_ci	 */
1378c2ecf20Sopenharmony_ci	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_RES_BASE);
1388c2ecf20Sopenharmony_ci	val &= ~LPC18XX_PWM_RES_MASK(pwm->hwpwm);
1398c2ecf20Sopenharmony_ci	val |= LPC18XX_PWM_RES(pwm->hwpwm, action);
1408c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_RES_BASE, val);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	mutex_unlock(&lpc18xx_pwm->res_lock);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void lpc18xx_pwm_config_period(struct pwm_chip *chip, int period_ns)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
1488c2ecf20Sopenharmony_ci	u64 val;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	val = (u64)period_ns * lpc18xx_pwm->clk_rate;
1518c2ecf20Sopenharmony_ci	do_div(val, NSEC_PER_SEC);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
1548c2ecf20Sopenharmony_ci			   LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event),
1558c2ecf20Sopenharmony_ci			   (u32)val - 1);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
1588c2ecf20Sopenharmony_ci			   LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event),
1598c2ecf20Sopenharmony_ci			   (u32)val - 1);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic void lpc18xx_pwm_config_duty(struct pwm_chip *chip,
1638c2ecf20Sopenharmony_ci				    struct pwm_device *pwm, int duty_ns)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
1668c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
1678c2ecf20Sopenharmony_ci	u64 val;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	val = (u64)duty_ns * lpc18xx_pwm->clk_rate;
1708c2ecf20Sopenharmony_ci	do_div(val, NSEC_PER_SEC);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
1738c2ecf20Sopenharmony_ci			   LPC18XX_PWM_MATCH(lpc18xx_data->duty_event),
1748c2ecf20Sopenharmony_ci			   (u32)val);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
1778c2ecf20Sopenharmony_ci			   LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event),
1788c2ecf20Sopenharmony_ci			   (u32)val);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
1828c2ecf20Sopenharmony_ci			      int duty_ns, int period_ns)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
1858c2ecf20Sopenharmony_ci	int requested_events, i;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (period_ns < lpc18xx_pwm->min_period_ns ||
1888c2ecf20Sopenharmony_ci	    period_ns > lpc18xx_pwm->max_period_ns) {
1898c2ecf20Sopenharmony_ci		dev_err(chip->dev, "period %d not in range\n", period_ns);
1908c2ecf20Sopenharmony_ci		return -ERANGE;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	mutex_lock(&lpc18xx_pwm->period_lock);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	requested_events = bitmap_weight(&lpc18xx_pwm->event_map,
1968c2ecf20Sopenharmony_ci					 LPC18XX_PWM_EVENT_MAX);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/*
1998c2ecf20Sopenharmony_ci	 * The PWM supports only a single period for all PWM channels.
2008c2ecf20Sopenharmony_ci	 * Once the period is set, it can only be changed if no more than one
2018c2ecf20Sopenharmony_ci	 * channel is requested at that moment.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns &&
2048c2ecf20Sopenharmony_ci	    lpc18xx_pwm->period_ns) {
2058c2ecf20Sopenharmony_ci		dev_err(chip->dev, "conflicting period requested for PWM %u\n",
2068c2ecf20Sopenharmony_ci			pwm->hwpwm);
2078c2ecf20Sopenharmony_ci		mutex_unlock(&lpc18xx_pwm->period_lock);
2088c2ecf20Sopenharmony_ci		return -EBUSY;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) ||
2128c2ecf20Sopenharmony_ci	    !lpc18xx_pwm->period_ns) {
2138c2ecf20Sopenharmony_ci		lpc18xx_pwm->period_ns = period_ns;
2148c2ecf20Sopenharmony_ci		for (i = 0; i < chip->npwm; i++)
2158c2ecf20Sopenharmony_ci			pwm_set_period(&chip->pwms[i], period_ns);
2168c2ecf20Sopenharmony_ci		lpc18xx_pwm_config_period(chip, period_ns);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	mutex_unlock(&lpc18xx_pwm->period_lock);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	lpc18xx_pwm_config_duty(chip, pwm, duty_ns);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	return 0;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic int lpc18xx_pwm_set_polarity(struct pwm_chip *chip,
2278c2ecf20Sopenharmony_ci				    struct pwm_device *pwm,
2288c2ecf20Sopenharmony_ci				    enum pwm_polarity polarity)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
2368c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
2378c2ecf20Sopenharmony_ci	enum lpc18xx_pwm_res_action res_action;
2388c2ecf20Sopenharmony_ci	unsigned int set_event, clear_event;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
2418c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event),
2428c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_data->duty_event) |
2438c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVCTRL_COMB_MATCH);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
2468c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event),
2478c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVSTATEMSK_ALL);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (pwm_get_polarity(pwm) == PWM_POLARITY_NORMAL) {
2508c2ecf20Sopenharmony_ci		set_event = lpc18xx_pwm->period_event;
2518c2ecf20Sopenharmony_ci		clear_event = lpc18xx_data->duty_event;
2528c2ecf20Sopenharmony_ci		res_action = LPC18XX_PWM_RES_SET;
2538c2ecf20Sopenharmony_ci	} else {
2548c2ecf20Sopenharmony_ci		set_event = lpc18xx_data->duty_event;
2558c2ecf20Sopenharmony_ci		clear_event = lpc18xx_pwm->period_event;
2568c2ecf20Sopenharmony_ci		res_action = LPC18XX_PWM_RES_CLEAR;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm),
2608c2ecf20Sopenharmony_ci			   BIT(set_event));
2618c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm),
2628c2ecf20Sopenharmony_ci			   BIT(clear_event));
2638c2ecf20Sopenharmony_ci	lpc18xx_pwm_set_conflict_res(lpc18xx_pwm, pwm, res_action);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return 0;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
2718c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
2748c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0);
2758c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), 0);
2768c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), 0);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
2828c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
2838c2ecf20Sopenharmony_ci	unsigned long event;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	event = find_first_zero_bit(&lpc18xx_pwm->event_map,
2868c2ecf20Sopenharmony_ci				    LPC18XX_PWM_EVENT_MAX);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (event >= LPC18XX_PWM_EVENT_MAX) {
2898c2ecf20Sopenharmony_ci		dev_err(lpc18xx_pwm->dev,
2908c2ecf20Sopenharmony_ci			"maximum number of simultaneous channels reached\n");
2918c2ecf20Sopenharmony_ci		return -EBUSY;
2928c2ecf20Sopenharmony_ci	};
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	set_bit(event, &lpc18xx_pwm->event_map);
2958c2ecf20Sopenharmony_ci	lpc18xx_data->duty_event = event;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
3038c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic const struct pwm_ops lpc18xx_pwm_ops = {
3098c2ecf20Sopenharmony_ci	.config = lpc18xx_pwm_config,
3108c2ecf20Sopenharmony_ci	.set_polarity = lpc18xx_pwm_set_polarity,
3118c2ecf20Sopenharmony_ci	.enable = lpc18xx_pwm_enable,
3128c2ecf20Sopenharmony_ci	.disable = lpc18xx_pwm_disable,
3138c2ecf20Sopenharmony_ci	.request = lpc18xx_pwm_request,
3148c2ecf20Sopenharmony_ci	.free = lpc18xx_pwm_free,
3158c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
3168c2ecf20Sopenharmony_ci};
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic const struct of_device_id lpc18xx_pwm_of_match[] = {
3198c2ecf20Sopenharmony_ci	{ .compatible = "nxp,lpc1850-sct-pwm" },
3208c2ecf20Sopenharmony_ci	{}
3218c2ecf20Sopenharmony_ci};
3228c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int lpc18xx_pwm_probe(struct platform_device *pdev)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm;
3278c2ecf20Sopenharmony_ci	struct pwm_device *pwm;
3288c2ecf20Sopenharmony_ci	int ret, i;
3298c2ecf20Sopenharmony_ci	u64 val;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm),
3328c2ecf20Sopenharmony_ci				   GFP_KERNEL);
3338c2ecf20Sopenharmony_ci	if (!lpc18xx_pwm)
3348c2ecf20Sopenharmony_ci		return -ENOMEM;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	lpc18xx_pwm->dev = &pdev->dev;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	lpc18xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
3398c2ecf20Sopenharmony_ci	if (IS_ERR(lpc18xx_pwm->base))
3408c2ecf20Sopenharmony_ci		return PTR_ERR(lpc18xx_pwm->base);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	lpc18xx_pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm");
3438c2ecf20Sopenharmony_ci	if (IS_ERR(lpc18xx_pwm->pwm_clk)) {
3448c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to get pwm clock\n");
3458c2ecf20Sopenharmony_ci		return PTR_ERR(lpc18xx_pwm->pwm_clk);
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(lpc18xx_pwm->pwm_clk);
3498c2ecf20Sopenharmony_ci	if (ret < 0) {
3508c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "could not prepare or enable pwm clock\n");
3518c2ecf20Sopenharmony_ci		return ret;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk);
3558c2ecf20Sopenharmony_ci	if (!lpc18xx_pwm->clk_rate) {
3568c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "pwm clock has no frequency\n");
3578c2ecf20Sopenharmony_ci		ret = -EINVAL;
3588c2ecf20Sopenharmony_ci		goto disable_pwmclk;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	mutex_init(&lpc18xx_pwm->res_lock);
3628c2ecf20Sopenharmony_ci	mutex_init(&lpc18xx_pwm->period_lock);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	val = (u64)NSEC_PER_SEC * LPC18XX_PWM_TIMER_MAX;
3658c2ecf20Sopenharmony_ci	do_div(val, lpc18xx_pwm->clk_rate);
3668c2ecf20Sopenharmony_ci	lpc18xx_pwm->max_period_ns = val;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
3698c2ecf20Sopenharmony_ci						  lpc18xx_pwm->clk_rate);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	lpc18xx_pwm->chip.dev = &pdev->dev;
3728c2ecf20Sopenharmony_ci	lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
3738c2ecf20Sopenharmony_ci	lpc18xx_pwm->chip.base = -1;
3748c2ecf20Sopenharmony_ci	lpc18xx_pwm->chip.npwm = 16;
3758c2ecf20Sopenharmony_ci	lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
3768c2ecf20Sopenharmony_ci	lpc18xx_pwm->chip.of_pwm_n_cells = 3;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* SCT counter must be in unify (32 bit) mode */
3798c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
3808c2ecf20Sopenharmony_ci			   LPC18XX_PWM_CONFIG_UNIFY);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/*
3838c2ecf20Sopenharmony_ci	 * Everytime the timer counter reaches the period value, the related
3848c2ecf20Sopenharmony_ci	 * event will be triggered and the counter reset to 0.
3858c2ecf20Sopenharmony_ci	 */
3868c2ecf20Sopenharmony_ci	set_bit(LPC18XX_PWM_EVENT_PERIOD, &lpc18xx_pwm->event_map);
3878c2ecf20Sopenharmony_ci	lpc18xx_pwm->period_event = LPC18XX_PWM_EVENT_PERIOD;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
3908c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVSTATEMSK(lpc18xx_pwm->period_event),
3918c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVSTATEMSK_ALL);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	val = LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_pwm->period_event) |
3948c2ecf20Sopenharmony_ci	      LPC18XX_PWM_EVCTRL_COMB_MATCH;
3958c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm,
3968c2ecf20Sopenharmony_ci			   LPC18XX_PWM_EVCTRL(lpc18xx_pwm->period_event), val);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT,
3998c2ecf20Sopenharmony_ci			   BIT(lpc18xx_pwm->period_event));
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) {
4028c2ecf20Sopenharmony_ci		struct lpc18xx_pwm_data *data;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		pwm = &lpc18xx_pwm->chip.pwms[i];
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		data = devm_kzalloc(lpc18xx_pwm->dev, sizeof(*data),
4078c2ecf20Sopenharmony_ci				    GFP_KERNEL);
4088c2ecf20Sopenharmony_ci		if (!data) {
4098c2ecf20Sopenharmony_ci			ret = -ENOMEM;
4108c2ecf20Sopenharmony_ci			goto disable_pwmclk;
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		pwm_set_chip_data(pwm, data);
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
4178c2ecf20Sopenharmony_ci	val &= ~LPC18XX_PWM_BIDIR;
4188c2ecf20Sopenharmony_ci	val &= ~LPC18XX_PWM_CTRL_HALT;
4198c2ecf20Sopenharmony_ci	val &= ~LPC18XX_PWM_PRE_MASK;
4208c2ecf20Sopenharmony_ci	val |= LPC18XX_PWM_PRE(0);
4218c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	ret = pwmchip_add(&lpc18xx_pwm->chip);
4248c2ecf20Sopenharmony_ci	if (ret < 0) {
4258c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
4268c2ecf20Sopenharmony_ci		goto disable_pwmclk;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, lpc18xx_pwm);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	return 0;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cidisable_pwmclk:
4348c2ecf20Sopenharmony_ci	clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
4358c2ecf20Sopenharmony_ci	return ret;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int lpc18xx_pwm_remove(struct platform_device *pdev)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
4418c2ecf20Sopenharmony_ci	u32 val;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
4448c2ecf20Sopenharmony_ci	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
4458c2ecf20Sopenharmony_ci			   val | LPC18XX_PWM_CTRL_HALT);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return pwmchip_remove(&lpc18xx_pwm->chip);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic struct platform_driver lpc18xx_pwm_driver = {
4538c2ecf20Sopenharmony_ci	.driver = {
4548c2ecf20Sopenharmony_ci		.name = "lpc18xx-sct-pwm",
4558c2ecf20Sopenharmony_ci		.of_match_table = lpc18xx_pwm_of_match,
4568c2ecf20Sopenharmony_ci	},
4578c2ecf20Sopenharmony_ci	.probe = lpc18xx_pwm_probe,
4588c2ecf20Sopenharmony_ci	.remove = lpc18xx_pwm_remove,
4598c2ecf20Sopenharmony_ci};
4608c2ecf20Sopenharmony_cimodule_platform_driver(lpc18xx_pwm_driver);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
4638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NXP LPC18xx PWM driver");
4648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
465