162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2015 Neil Armstrong <narmstrong@baylibre.com>
462306a36Sopenharmony_ci * Copyright (c) 2014 Joachim Eastwood <manabian@gmail.com>
562306a36Sopenharmony_ci * Copyright (c) 2012 NeilBrown <neilb@suse.de>
662306a36Sopenharmony_ci * Heavily based on earlier code which is:
762306a36Sopenharmony_ci * Copyright (c) 2010 Grant Erickson <marathon96@gmail.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Also based on pwm-samsung.c
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Description:
1262306a36Sopenharmony_ci *   This file is the core OMAP support for the generic, Linux
1362306a36Sopenharmony_ci *   PWM driver / controller, using the OMAP's dual-mode timers
1462306a36Sopenharmony_ci *   with a timer counter that goes up. When it overflows it gets
1562306a36Sopenharmony_ci *   reloaded with the load value and the pwm output goes up.
1662306a36Sopenharmony_ci *   When counter matches with match register, the output goes down.
1762306a36Sopenharmony_ci *   Reference Manual: https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Limitations:
2062306a36Sopenharmony_ci * - When PWM is stopped, timer counter gets stopped immediately. This
2162306a36Sopenharmony_ci *   doesn't allow the current PWM period to complete and stops abruptly.
2262306a36Sopenharmony_ci * - When PWM is running and changing both duty cycle and period,
2362306a36Sopenharmony_ci *   we cannot prevent in software that the output might produce
2462306a36Sopenharmony_ci *   a period with mixed settings. Especially when period/duty_cyle
2562306a36Sopenharmony_ci *   is updated while the pwm pin is high, current pwm period/duty_cycle
2662306a36Sopenharmony_ci *   can get updated as below based on the current timer counter:
2762306a36Sopenharmony_ci *   	- period for current cycle =  current_period + new period
2862306a36Sopenharmony_ci *   	- duty_cycle for current period = current period + new duty_cycle.
2962306a36Sopenharmony_ci * - PWM OMAP DM timer cannot change the polarity when pwm is active. When
3062306a36Sopenharmony_ci *   user requests a change in polarity when in active state:
3162306a36Sopenharmony_ci *	- PWM is stopped abruptly(without completing the current cycle)
3262306a36Sopenharmony_ci *	- Polarity is changed
3362306a36Sopenharmony_ci *	- A fresh cycle is started.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/clk.h>
3762306a36Sopenharmony_ci#include <linux/err.h>
3862306a36Sopenharmony_ci#include <linux/kernel.h>
3962306a36Sopenharmony_ci#include <linux/module.h>
4062306a36Sopenharmony_ci#include <linux/mutex.h>
4162306a36Sopenharmony_ci#include <linux/of.h>
4262306a36Sopenharmony_ci#include <linux/of_platform.h>
4362306a36Sopenharmony_ci#include <clocksource/timer-ti-dm.h>
4462306a36Sopenharmony_ci#include <linux/platform_data/dmtimer-omap.h>
4562306a36Sopenharmony_ci#include <linux/platform_device.h>
4662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
4762306a36Sopenharmony_ci#include <linux/pwm.h>
4862306a36Sopenharmony_ci#include <linux/slab.h>
4962306a36Sopenharmony_ci#include <linux/time.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define DM_TIMER_LOAD_MIN 0xfffffffe
5262306a36Sopenharmony_ci#define DM_TIMER_MAX      0xffffffff
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/**
5562306a36Sopenharmony_ci * struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
5662306a36Sopenharmony_ci *				  corresponding to omap dmtimer.
5762306a36Sopenharmony_ci * @chip:		PWM chip structure representing PWM controller
5862306a36Sopenharmony_ci * @mutex:		Mutex to protect pwm apply state
5962306a36Sopenharmony_ci * @dm_timer:		Pointer to omap dm timer.
6062306a36Sopenharmony_ci * @pdata:		Pointer to omap dm timer ops.
6162306a36Sopenharmony_ci * @dm_timer_pdev:	Pointer to omap dm timer platform device
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistruct pwm_omap_dmtimer_chip {
6462306a36Sopenharmony_ci	struct pwm_chip chip;
6562306a36Sopenharmony_ci	/* Mutex to protect pwm apply state */
6662306a36Sopenharmony_ci	struct mutex mutex;
6762306a36Sopenharmony_ci	struct omap_dm_timer *dm_timer;
6862306a36Sopenharmony_ci	const struct omap_dm_timer_ops *pdata;
6962306a36Sopenharmony_ci	struct platform_device *dm_timer_pdev;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic inline struct pwm_omap_dmtimer_chip *
7362306a36Sopenharmony_cito_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame
8062306a36Sopenharmony_ci * @clk_rate:	pwm timer clock rate
8162306a36Sopenharmony_ci * @ns:		time frame in nano seconds.
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * Return number of clock cycles in a given period(ins ns).
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_cistatic u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode
9262306a36Sopenharmony_ci * @omap:	Pointer to pwm omap dm timer chip
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * According to OMAP 4 TRM section 22.2.4.10 the counter should be
9862306a36Sopenharmony_ci	 * started at 0xFFFFFFFE when overflow and match is used to ensure
9962306a36Sopenharmony_ci	 * that the PWM line is toggled on the first event.
10062306a36Sopenharmony_ci	 *
10162306a36Sopenharmony_ci	 * Note that omap_dm_timer_enable/disable is for register access and
10262306a36Sopenharmony_ci	 * not the timer counter itself.
10362306a36Sopenharmony_ci	 */
10462306a36Sopenharmony_ci	omap->pdata->enable(omap->dm_timer);
10562306a36Sopenharmony_ci	omap->pdata->write_counter(omap->dm_timer, DM_TIMER_LOAD_MIN);
10662306a36Sopenharmony_ci	omap->pdata->disable(omap->dm_timer);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	omap->pdata->start(omap->dm_timer);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/**
11262306a36Sopenharmony_ci * pwm_omap_dmtimer_is_enabled() -  Detect if the pwm is enabled.
11362306a36Sopenharmony_ci * @omap:	Pointer to pwm omap dm timer chip
11462306a36Sopenharmony_ci *
11562306a36Sopenharmony_ci * Return true if pwm is enabled else false.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_cistatic bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	u32 status;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	status = omap->pdata->get_pwm_status(omap->dm_timer);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return !!(status & OMAP_TIMER_CTRL_ST);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/**
12762306a36Sopenharmony_ci * pwm_omap_dmtimer_polarity() -  Detect the polarity of pwm.
12862306a36Sopenharmony_ci * @omap:	Pointer to pwm omap dm timer chip
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Return the polarity of pwm.
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_cistatic int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	u32 status;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	status = omap->pdata->get_pwm_status(omap->dm_timer);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return !!(status & OMAP_TIMER_CTRL_SCPWM);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/**
14262306a36Sopenharmony_ci * pwm_omap_dmtimer_config() - Update the configuration of pwm omap dm timer
14362306a36Sopenharmony_ci * @chip:	Pointer to PWM controller
14462306a36Sopenharmony_ci * @pwm:	Pointer to PWM channel
14562306a36Sopenharmony_ci * @duty_ns:	New duty cycle in nano seconds
14662306a36Sopenharmony_ci * @period_ns:	New period in nano seconds
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * Return 0 if successfully changed the period/duty_cycle else appropriate
14962306a36Sopenharmony_ci * error.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_cistatic int pwm_omap_dmtimer_config(struct pwm_chip *chip,
15262306a36Sopenharmony_ci				   struct pwm_device *pwm,
15362306a36Sopenharmony_ci				   int duty_ns, int period_ns)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
15662306a36Sopenharmony_ci	u32 period_cycles, duty_cycles;
15762306a36Sopenharmony_ci	u32 load_value, match_value;
15862306a36Sopenharmony_ci	unsigned long clk_rate;
15962306a36Sopenharmony_ci	struct clk *fclk;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
16262306a36Sopenharmony_ci		duty_ns, period_ns);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (duty_ns == pwm_get_duty_cycle(pwm) &&
16562306a36Sopenharmony_ci	    period_ns == pwm_get_period(pwm))
16662306a36Sopenharmony_ci		return 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	fclk = omap->pdata->get_fclk(omap->dm_timer);
16962306a36Sopenharmony_ci	if (!fclk) {
17062306a36Sopenharmony_ci		dev_err(chip->dev, "invalid pmtimer fclk\n");
17162306a36Sopenharmony_ci		return -EINVAL;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	clk_rate = clk_get_rate(fclk);
17562306a36Sopenharmony_ci	if (!clk_rate) {
17662306a36Sopenharmony_ci		dev_err(chip->dev, "invalid pmtimer fclk rate\n");
17762306a36Sopenharmony_ci		return -EINVAL;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/*
18362306a36Sopenharmony_ci	 * Calculate the appropriate load and match values based on the
18462306a36Sopenharmony_ci	 * specified period and duty cycle. The load value determines the
18562306a36Sopenharmony_ci	 * period time and the match value determines the duty time.
18662306a36Sopenharmony_ci	 *
18762306a36Sopenharmony_ci	 * The period lasts for (DM_TIMER_MAX-load_value+1) clock cycles.
18862306a36Sopenharmony_ci	 * Similarly, the active time lasts (match_value-load_value+1) cycles.
18962306a36Sopenharmony_ci	 * The non-active time is the remainder: (DM_TIMER_MAX-match_value)
19062306a36Sopenharmony_ci	 * clock cycles.
19162306a36Sopenharmony_ci	 *
19262306a36Sopenharmony_ci	 * NOTE: It is required that: load_value <= match_value < DM_TIMER_MAX
19362306a36Sopenharmony_ci	 *
19462306a36Sopenharmony_ci	 * References:
19562306a36Sopenharmony_ci	 *   OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11
19662306a36Sopenharmony_ci	 *   AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6
19762306a36Sopenharmony_ci	 */
19862306a36Sopenharmony_ci	period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns);
19962306a36Sopenharmony_ci	duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (period_cycles < 2) {
20262306a36Sopenharmony_ci		dev_info(chip->dev,
20362306a36Sopenharmony_ci			 "period %d ns too short for clock rate %lu Hz\n",
20462306a36Sopenharmony_ci			 period_ns, clk_rate);
20562306a36Sopenharmony_ci		return -EINVAL;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (duty_cycles < 1) {
20962306a36Sopenharmony_ci		dev_dbg(chip->dev,
21062306a36Sopenharmony_ci			"duty cycle %d ns is too short for clock rate %lu Hz\n",
21162306a36Sopenharmony_ci			duty_ns, clk_rate);
21262306a36Sopenharmony_ci		dev_dbg(chip->dev, "using minimum of 1 clock cycle\n");
21362306a36Sopenharmony_ci		duty_cycles = 1;
21462306a36Sopenharmony_ci	} else if (duty_cycles >= period_cycles) {
21562306a36Sopenharmony_ci		dev_dbg(chip->dev,
21662306a36Sopenharmony_ci			"duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n",
21762306a36Sopenharmony_ci			duty_ns, period_ns, clk_rate);
21862306a36Sopenharmony_ci		dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n");
21962306a36Sopenharmony_ci		duty_cycles = period_cycles - 1;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n",
22362306a36Sopenharmony_ci		DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * duty_cycles,
22462306a36Sopenharmony_ci				      clk_rate),
22562306a36Sopenharmony_ci		DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * period_cycles,
22662306a36Sopenharmony_ci				      clk_rate));
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	load_value = (DM_TIMER_MAX - period_cycles) + 1;
22962306a36Sopenharmony_ci	match_value = load_value + duty_cycles - 1;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	omap->pdata->set_load(omap->dm_timer, load_value);
23262306a36Sopenharmony_ci	omap->pdata->set_match(omap->dm_timer, true, match_value);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
23562306a36Sopenharmony_ci		load_value, load_value,	match_value, match_value);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return 0;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/**
24162306a36Sopenharmony_ci * pwm_omap_dmtimer_set_polarity() - Changes the polarity of the pwm dm timer.
24262306a36Sopenharmony_ci * @chip:	Pointer to PWM controller
24362306a36Sopenharmony_ci * @pwm:	Pointer to PWM channel
24462306a36Sopenharmony_ci * @polarity:	New pwm polarity to be set
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistatic void pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
24762306a36Sopenharmony_ci					  struct pwm_device *pwm,
24862306a36Sopenharmony_ci					  enum pwm_polarity polarity)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
25162306a36Sopenharmony_ci	bool enabled;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Disable the PWM before changing the polarity. */
25462306a36Sopenharmony_ci	enabled = pwm_omap_dmtimer_is_enabled(omap);
25562306a36Sopenharmony_ci	if (enabled)
25662306a36Sopenharmony_ci		omap->pdata->stop(omap->dm_timer);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	omap->pdata->set_pwm(omap->dm_timer,
25962306a36Sopenharmony_ci			     polarity == PWM_POLARITY_INVERSED,
26062306a36Sopenharmony_ci			     true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
26162306a36Sopenharmony_ci			     true);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (enabled)
26462306a36Sopenharmony_ci		pwm_omap_dmtimer_start(omap);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/**
26862306a36Sopenharmony_ci * pwm_omap_dmtimer_apply() - Changes the state of the pwm omap dm timer.
26962306a36Sopenharmony_ci * @chip:	Pointer to PWM controller
27062306a36Sopenharmony_ci * @pwm:	Pointer to PWM channel
27162306a36Sopenharmony_ci * @state:	New state to apply
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * Return 0 if successfully changed the state else appropriate error.
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_cistatic int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
27662306a36Sopenharmony_ci				  struct pwm_device *pwm,
27762306a36Sopenharmony_ci				  const struct pwm_state *state)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
28062306a36Sopenharmony_ci	int ret = 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	mutex_lock(&omap->mutex);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
28562306a36Sopenharmony_ci		omap->pdata->stop(omap->dm_timer);
28662306a36Sopenharmony_ci		goto unlock_mutex;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
29062306a36Sopenharmony_ci		pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
29362306a36Sopenharmony_ci				      state->period);
29462306a36Sopenharmony_ci	if (ret)
29562306a36Sopenharmony_ci		goto unlock_mutex;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
29862306a36Sopenharmony_ci		omap->pdata->set_pwm(omap->dm_timer,
29962306a36Sopenharmony_ci				     state->polarity == PWM_POLARITY_INVERSED,
30062306a36Sopenharmony_ci				     true,
30162306a36Sopenharmony_ci				     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
30262306a36Sopenharmony_ci				     true);
30362306a36Sopenharmony_ci		pwm_omap_dmtimer_start(omap);
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ciunlock_mutex:
30762306a36Sopenharmony_ci	mutex_unlock(&omap->mutex);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	return ret;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic const struct pwm_ops pwm_omap_dmtimer_ops = {
31362306a36Sopenharmony_ci	.apply = pwm_omap_dmtimer_apply,
31462306a36Sopenharmony_ci	.owner = THIS_MODULE,
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int pwm_omap_dmtimer_probe(struct platform_device *pdev)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
32062306a36Sopenharmony_ci	struct dmtimer_platform_data *timer_pdata;
32162306a36Sopenharmony_ci	const struct omap_dm_timer_ops *pdata;
32262306a36Sopenharmony_ci	struct platform_device *timer_pdev;
32362306a36Sopenharmony_ci	struct pwm_omap_dmtimer_chip *omap;
32462306a36Sopenharmony_ci	struct omap_dm_timer *dm_timer;
32562306a36Sopenharmony_ci	struct device_node *timer;
32662306a36Sopenharmony_ci	int ret = 0;
32762306a36Sopenharmony_ci	u32 v;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	timer = of_parse_phandle(np, "ti,timers", 0);
33062306a36Sopenharmony_ci	if (!timer)
33162306a36Sopenharmony_ci		return -ENODEV;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	timer_pdev = of_find_device_by_node(timer);
33462306a36Sopenharmony_ci	if (!timer_pdev) {
33562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to find Timer pdev\n");
33662306a36Sopenharmony_ci		ret = -ENODEV;
33762306a36Sopenharmony_ci		goto err_find_timer_pdev;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	timer_pdata = dev_get_platdata(&timer_pdev->dev);
34162306a36Sopenharmony_ci	if (!timer_pdata) {
34262306a36Sopenharmony_ci		dev_dbg(&pdev->dev,
34362306a36Sopenharmony_ci			 "dmtimer pdata structure NULL, deferring probe\n");
34462306a36Sopenharmony_ci		ret = -EPROBE_DEFER;
34562306a36Sopenharmony_ci		goto err_platdata;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	pdata = timer_pdata->timer_ops;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (!pdata || !pdata->request_by_node ||
35162306a36Sopenharmony_ci	    !pdata->free ||
35262306a36Sopenharmony_ci	    !pdata->enable ||
35362306a36Sopenharmony_ci	    !pdata->disable ||
35462306a36Sopenharmony_ci	    !pdata->get_fclk ||
35562306a36Sopenharmony_ci	    !pdata->start ||
35662306a36Sopenharmony_ci	    !pdata->stop ||
35762306a36Sopenharmony_ci	    !pdata->set_load ||
35862306a36Sopenharmony_ci	    !pdata->set_match ||
35962306a36Sopenharmony_ci	    !pdata->set_pwm ||
36062306a36Sopenharmony_ci	    !pdata->get_pwm_status ||
36162306a36Sopenharmony_ci	    !pdata->set_prescaler ||
36262306a36Sopenharmony_ci	    !pdata->write_counter) {
36362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
36462306a36Sopenharmony_ci		ret = -EINVAL;
36562306a36Sopenharmony_ci		goto err_platdata;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (!of_get_property(timer, "ti,timer-pwm", NULL)) {
36962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n");
37062306a36Sopenharmony_ci		ret = -ENODEV;
37162306a36Sopenharmony_ci		goto err_timer_property;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	dm_timer = pdata->request_by_node(timer);
37562306a36Sopenharmony_ci	if (!dm_timer) {
37662306a36Sopenharmony_ci		ret = -EPROBE_DEFER;
37762306a36Sopenharmony_ci		goto err_request_timer;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
38162306a36Sopenharmony_ci	if (!omap) {
38262306a36Sopenharmony_ci		ret = -ENOMEM;
38362306a36Sopenharmony_ci		goto err_alloc_omap;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	omap->pdata = pdata;
38762306a36Sopenharmony_ci	omap->dm_timer = dm_timer;
38862306a36Sopenharmony_ci	omap->dm_timer_pdev = timer_pdev;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/*
39162306a36Sopenharmony_ci	 * Ensure that the timer is stopped before we allow PWM core to call
39262306a36Sopenharmony_ci	 * pwm_enable.
39362306a36Sopenharmony_ci	 */
39462306a36Sopenharmony_ci	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
39562306a36Sopenharmony_ci		omap->pdata->stop(omap->dm_timer);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v))
39862306a36Sopenharmony_ci		omap->pdata->set_prescaler(omap->dm_timer, v);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* setup dmtimer clock source */
40162306a36Sopenharmony_ci	if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
40262306a36Sopenharmony_ci		omap->pdata->set_source(omap->dm_timer, v);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	omap->chip.dev = &pdev->dev;
40562306a36Sopenharmony_ci	omap->chip.ops = &pwm_omap_dmtimer_ops;
40662306a36Sopenharmony_ci	omap->chip.npwm = 1;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	mutex_init(&omap->mutex);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	ret = pwmchip_add(&omap->chip);
41162306a36Sopenharmony_ci	if (ret < 0) {
41262306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to register PWM\n");
41362306a36Sopenharmony_ci		goto err_pwmchip_add;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	of_node_put(timer);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	platform_set_drvdata(pdev, omap);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cierr_pwmchip_add:
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/*
42562306a36Sopenharmony_ci	 * *omap is allocated using devm_kzalloc,
42662306a36Sopenharmony_ci	 * so no free necessary here
42762306a36Sopenharmony_ci	 */
42862306a36Sopenharmony_cierr_alloc_omap:
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	pdata->free(dm_timer);
43162306a36Sopenharmony_cierr_request_timer:
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cierr_timer_property:
43462306a36Sopenharmony_cierr_platdata:
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	put_device(&timer_pdev->dev);
43762306a36Sopenharmony_cierr_find_timer_pdev:
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	of_node_put(timer);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return ret;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic void pwm_omap_dmtimer_remove(struct platform_device *pdev)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	pwmchip_remove(&omap->chip);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
45162306a36Sopenharmony_ci		omap->pdata->stop(omap->dm_timer);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	omap->pdata->free(omap->dm_timer);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	put_device(&omap->dm_timer_pdev->dev);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	mutex_destroy(&omap->mutex);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic const struct of_device_id pwm_omap_dmtimer_of_match[] = {
46162306a36Sopenharmony_ci	{.compatible = "ti,omap-dmtimer-pwm"},
46262306a36Sopenharmony_ci	{}
46362306a36Sopenharmony_ci};
46462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pwm_omap_dmtimer_of_match);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic struct platform_driver pwm_omap_dmtimer_driver = {
46762306a36Sopenharmony_ci	.driver = {
46862306a36Sopenharmony_ci		.name = "omap-dmtimer-pwm",
46962306a36Sopenharmony_ci		.of_match_table = of_match_ptr(pwm_omap_dmtimer_of_match),
47062306a36Sopenharmony_ci	},
47162306a36Sopenharmony_ci	.probe = pwm_omap_dmtimer_probe,
47262306a36Sopenharmony_ci	.remove_new = pwm_omap_dmtimer_remove,
47362306a36Sopenharmony_ci};
47462306a36Sopenharmony_cimodule_platform_driver(pwm_omap_dmtimer_driver);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ciMODULE_AUTHOR("Grant Erickson <marathon96@gmail.com>");
47762306a36Sopenharmony_ciMODULE_AUTHOR("NeilBrown <neilb@suse.de>");
47862306a36Sopenharmony_ciMODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
47962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
48062306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP PWM Driver using Dual-mode Timers");
481