xref: /openbmc/linux/drivers/pwm/pwm-brcmstb.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23a9f5957SFlorian Fainelli /*
33a9f5957SFlorian Fainelli  * Broadcom BCM7038 PWM driver
43a9f5957SFlorian Fainelli  * Author: Florian Fainelli
53a9f5957SFlorian Fainelli  *
63a9f5957SFlorian Fainelli  * Copyright (C) 2015 Broadcom Corporation
73a9f5957SFlorian Fainelli  */
83a9f5957SFlorian Fainelli 
93a9f5957SFlorian Fainelli #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
103a9f5957SFlorian Fainelli 
113a9f5957SFlorian Fainelli #include <linux/clk.h>
123a9f5957SFlorian Fainelli #include <linux/export.h>
133a9f5957SFlorian Fainelli #include <linux/init.h>
143a9f5957SFlorian Fainelli #include <linux/io.h>
153a9f5957SFlorian Fainelli #include <linux/kernel.h>
163a9f5957SFlorian Fainelli #include <linux/module.h>
173a9f5957SFlorian Fainelli #include <linux/of.h>
183a9f5957SFlorian Fainelli #include <linux/platform_device.h>
193a9f5957SFlorian Fainelli #include <linux/pwm.h>
203a9f5957SFlorian Fainelli #include <linux/spinlock.h>
213a9f5957SFlorian Fainelli 
223a9f5957SFlorian Fainelli #define PWM_CTRL		0x00
233a9f5957SFlorian Fainelli #define  CTRL_START		BIT(0)
243a9f5957SFlorian Fainelli #define  CTRL_OEB		BIT(1)
253a9f5957SFlorian Fainelli #define  CTRL_FORCE_HIGH	BIT(2)
263a9f5957SFlorian Fainelli #define  CTRL_OPENDRAIN		BIT(3)
273a9f5957SFlorian Fainelli #define  CTRL_CHAN_OFFS		4
283a9f5957SFlorian Fainelli 
293a9f5957SFlorian Fainelli #define PWM_CTRL2		0x04
303a9f5957SFlorian Fainelli #define  CTRL2_OUT_SELECT	BIT(0)
313a9f5957SFlorian Fainelli 
323a9f5957SFlorian Fainelli #define PWM_CH_SIZE		0x8
333a9f5957SFlorian Fainelli 
343a9f5957SFlorian Fainelli #define PWM_CWORD_MSB(ch)	(0x08 + ((ch) * PWM_CH_SIZE))
353a9f5957SFlorian Fainelli #define PWM_CWORD_LSB(ch)	(0x0c + ((ch) * PWM_CH_SIZE))
363a9f5957SFlorian Fainelli 
373a9f5957SFlorian Fainelli /* Number of bits for the CWORD value */
383a9f5957SFlorian Fainelli #define CWORD_BIT_SIZE		16
393a9f5957SFlorian Fainelli 
403a9f5957SFlorian Fainelli /*
413a9f5957SFlorian Fainelli  * Maximum control word value allowed when variable-frequency PWM is used as a
423a9f5957SFlorian Fainelli  * clock for the constant-frequency PMW.
433a9f5957SFlorian Fainelli  */
443a9f5957SFlorian Fainelli #define CONST_VAR_F_MAX		32768
453a9f5957SFlorian Fainelli #define CONST_VAR_F_MIN		1
463a9f5957SFlorian Fainelli 
473a9f5957SFlorian Fainelli #define PWM_ON(ch)		(0x18 + ((ch) * PWM_CH_SIZE))
483a9f5957SFlorian Fainelli #define  PWM_ON_MIN		1
493a9f5957SFlorian Fainelli #define PWM_PERIOD(ch)		(0x1c + ((ch) * PWM_CH_SIZE))
503a9f5957SFlorian Fainelli #define  PWM_PERIOD_MIN		0
513a9f5957SFlorian Fainelli 
523a9f5957SFlorian Fainelli #define PWM_ON_PERIOD_MAX	0xff
533a9f5957SFlorian Fainelli 
543a9f5957SFlorian Fainelli struct brcmstb_pwm {
553a9f5957SFlorian Fainelli 	void __iomem *base;
563a9f5957SFlorian Fainelli 	struct clk *clk;
573a9f5957SFlorian Fainelli 	struct pwm_chip chip;
583a9f5957SFlorian Fainelli };
593a9f5957SFlorian Fainelli 
brcmstb_pwm_readl(struct brcmstb_pwm * p,unsigned int offset)603a9f5957SFlorian Fainelli static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
613a9f5957SFlorian Fainelli 				    unsigned int offset)
623a9f5957SFlorian Fainelli {
633a9f5957SFlorian Fainelli 	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
643a9f5957SFlorian Fainelli 		return __raw_readl(p->base + offset);
653a9f5957SFlorian Fainelli 	else
663a9f5957SFlorian Fainelli 		return readl_relaxed(p->base + offset);
673a9f5957SFlorian Fainelli }
683a9f5957SFlorian Fainelli 
brcmstb_pwm_writel(struct brcmstb_pwm * p,u32 value,unsigned int offset)693a9f5957SFlorian Fainelli static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
703a9f5957SFlorian Fainelli 				      unsigned int offset)
713a9f5957SFlorian Fainelli {
723a9f5957SFlorian Fainelli 	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
733a9f5957SFlorian Fainelli 		__raw_writel(value, p->base + offset);
743a9f5957SFlorian Fainelli 	else
753a9f5957SFlorian Fainelli 		writel_relaxed(value, p->base + offset);
763a9f5957SFlorian Fainelli }
773a9f5957SFlorian Fainelli 
to_brcmstb_pwm(struct pwm_chip * chip)783a9f5957SFlorian Fainelli static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
793a9f5957SFlorian Fainelli {
803a9f5957SFlorian Fainelli 	return container_of(chip, struct brcmstb_pwm, chip);
813a9f5957SFlorian Fainelli }
823a9f5957SFlorian Fainelli 
833a9f5957SFlorian Fainelli /*
843a9f5957SFlorian Fainelli  * Fv is derived from the variable frequency output. The variable frequency
853a9f5957SFlorian Fainelli  * output is configured using this formula:
863a9f5957SFlorian Fainelli  *
873a9f5957SFlorian Fainelli  * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword
883a9f5957SFlorian Fainelli  *
893a9f5957SFlorian Fainelli  * Fv = W x 2 ^ -16 x 27Mhz (reference clock)
903a9f5957SFlorian Fainelli  *
913a9f5957SFlorian Fainelli  * The period is: (period + 1) / Fv and "on" time is on / (period + 1)
923a9f5957SFlorian Fainelli  *
933a9f5957SFlorian Fainelli  * The PWM core framework specifies that the "duty_ns" parameter is in fact the
943a9f5957SFlorian Fainelli  * "on" time, so this translates directly into our HW programming here.
953a9f5957SFlorian Fainelli  */
brcmstb_pwm_config(struct pwm_chip * chip,struct pwm_device * pwm,u64 duty_ns,u64 period_ns)963a9f5957SFlorian Fainelli static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
970dcfafe7SUwe Kleine-König 			      u64 duty_ns, u64 period_ns)
983a9f5957SFlorian Fainelli {
993a9f5957SFlorian Fainelli 	struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
1003a9f5957SFlorian Fainelli 	unsigned long pc, dc, cword = CONST_VAR_F_MAX;
1013a9f5957SFlorian Fainelli 	unsigned int channel = pwm->hwpwm;
1023a9f5957SFlorian Fainelli 	u32 value;
1033a9f5957SFlorian Fainelli 
1043a9f5957SFlorian Fainelli 	/*
1053a9f5957SFlorian Fainelli 	 * If asking for a duty_ns equal to period_ns, we need to substract
1063a9f5957SFlorian Fainelli 	 * the period value by 1 to make it shorter than the "on" time and
1073a9f5957SFlorian Fainelli 	 * produce a flat 100% duty cycle signal, and max out the "on" time
1083a9f5957SFlorian Fainelli 	 */
1093a9f5957SFlorian Fainelli 	if (duty_ns == period_ns) {
1103a9f5957SFlorian Fainelli 		dc = PWM_ON_PERIOD_MAX;
1113a9f5957SFlorian Fainelli 		pc = PWM_ON_PERIOD_MAX - 1;
1123a9f5957SFlorian Fainelli 		goto done;
1133a9f5957SFlorian Fainelli 	}
1143a9f5957SFlorian Fainelli 
1153a9f5957SFlorian Fainelli 	while (1) {
1160dcfafe7SUwe Kleine-König 		u64 rate;
1173a9f5957SFlorian Fainelli 
1183a9f5957SFlorian Fainelli 		/*
1193a9f5957SFlorian Fainelli 		 * Calculate the base rate from base frequency and current
1203a9f5957SFlorian Fainelli 		 * cword
1213a9f5957SFlorian Fainelli 		 */
1223a9f5957SFlorian Fainelli 		rate = (u64)clk_get_rate(p->clk) * (u64)cword;
1230dcfafe7SUwe Kleine-König 		rate >>= CWORD_BIT_SIZE;
1243a9f5957SFlorian Fainelli 
1250dcfafe7SUwe Kleine-König 		pc = mul_u64_u64_div_u64(period_ns, rate, NSEC_PER_SEC);
1260dcfafe7SUwe Kleine-König 		dc = mul_u64_u64_div_u64(duty_ns + 1, rate, NSEC_PER_SEC);
1273a9f5957SFlorian Fainelli 
1283a9f5957SFlorian Fainelli 		/*
1293a9f5957SFlorian Fainelli 		 * We can be called with separate duty and period updates,
1303a9f5957SFlorian Fainelli 		 * so do not reject dc == 0 right away
1313a9f5957SFlorian Fainelli 		 */
1323a9f5957SFlorian Fainelli 		if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns))
1333a9f5957SFlorian Fainelli 			return -EINVAL;
1343a9f5957SFlorian Fainelli 
1353a9f5957SFlorian Fainelli 		/* We converged on a calculation */
1363a9f5957SFlorian Fainelli 		if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX)
1373a9f5957SFlorian Fainelli 			break;
1383a9f5957SFlorian Fainelli 
1393a9f5957SFlorian Fainelli 		/*
1403a9f5957SFlorian Fainelli 		 * The cword needs to be a power of 2 for the variable
1413a9f5957SFlorian Fainelli 		 * frequency generator to output a 50% duty cycle variable
1423a9f5957SFlorian Fainelli 		 * frequency which is used as input clock to the fixed
1433a9f5957SFlorian Fainelli 		 * frequency generator.
1443a9f5957SFlorian Fainelli 		 */
1453a9f5957SFlorian Fainelli 		cword >>= 1;
1463a9f5957SFlorian Fainelli 
1473a9f5957SFlorian Fainelli 		/*
1483a9f5957SFlorian Fainelli 		 * Desired periods are too large, we do not have a divider
1493a9f5957SFlorian Fainelli 		 * for them
1503a9f5957SFlorian Fainelli 		 */
1513a9f5957SFlorian Fainelli 		if (cword < CONST_VAR_F_MIN)
1523a9f5957SFlorian Fainelli 			return -EINVAL;
1533a9f5957SFlorian Fainelli 	}
1543a9f5957SFlorian Fainelli 
1553a9f5957SFlorian Fainelli done:
1563a9f5957SFlorian Fainelli 	/*
1573a9f5957SFlorian Fainelli 	 * Configure the defined "cword" value to have the variable frequency
1583a9f5957SFlorian Fainelli 	 * generator output a base frequency for the constant frequency
1593a9f5957SFlorian Fainelli 	 * generator to derive from.
1603a9f5957SFlorian Fainelli 	 */
1613a9f5957SFlorian Fainelli 	brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel));
1623a9f5957SFlorian Fainelli 	brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel));
1633a9f5957SFlorian Fainelli 
1643a9f5957SFlorian Fainelli 	/* Select constant frequency signal output */
1653a9f5957SFlorian Fainelli 	value = brcmstb_pwm_readl(p, PWM_CTRL2);
1663a9f5957SFlorian Fainelli 	value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS);
1673a9f5957SFlorian Fainelli 	brcmstb_pwm_writel(p, value, PWM_CTRL2);
1683a9f5957SFlorian Fainelli 
1693a9f5957SFlorian Fainelli 	/* Configure on and period value */
1703a9f5957SFlorian Fainelli 	brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel));
1713a9f5957SFlorian Fainelli 	brcmstb_pwm_writel(p, dc, PWM_ON(channel));
1723a9f5957SFlorian Fainelli 
1733a9f5957SFlorian Fainelli 	return 0;
1743a9f5957SFlorian Fainelli }
1753a9f5957SFlorian Fainelli 
brcmstb_pwm_enable_set(struct brcmstb_pwm * p,unsigned int channel,bool enable)1763a9f5957SFlorian Fainelli static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p,
1773a9f5957SFlorian Fainelli 					  unsigned int channel, bool enable)
1783a9f5957SFlorian Fainelli {
1793a9f5957SFlorian Fainelli 	unsigned int shift = channel * CTRL_CHAN_OFFS;
1803a9f5957SFlorian Fainelli 	u32 value;
1813a9f5957SFlorian Fainelli 
1823a9f5957SFlorian Fainelli 	value = brcmstb_pwm_readl(p, PWM_CTRL);
1833a9f5957SFlorian Fainelli 
1843a9f5957SFlorian Fainelli 	if (enable) {
1853a9f5957SFlorian Fainelli 		value &= ~(CTRL_OEB << shift);
1863a9f5957SFlorian Fainelli 		value |= (CTRL_START | CTRL_OPENDRAIN) << shift;
1873a9f5957SFlorian Fainelli 	} else {
1883a9f5957SFlorian Fainelli 		value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift);
1893a9f5957SFlorian Fainelli 		value |= CTRL_OEB << shift;
1903a9f5957SFlorian Fainelli 	}
1913a9f5957SFlorian Fainelli 
1923a9f5957SFlorian Fainelli 	brcmstb_pwm_writel(p, value, PWM_CTRL);
1933a9f5957SFlorian Fainelli }
1943a9f5957SFlorian Fainelli 
brcmstb_pwm_apply(struct pwm_chip * chip,struct pwm_device * pwm,const struct pwm_state * state)1950dcfafe7SUwe Kleine-König static int brcmstb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
1960dcfafe7SUwe Kleine-König 			     const struct pwm_state *state)
1973a9f5957SFlorian Fainelli {
1983a9f5957SFlorian Fainelli 	struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
1990dcfafe7SUwe Kleine-König 	int err;
2003a9f5957SFlorian Fainelli 
2010dcfafe7SUwe Kleine-König 	if (state->polarity != PWM_POLARITY_NORMAL)
2020dcfafe7SUwe Kleine-König 		return -EINVAL;
2030dcfafe7SUwe Kleine-König 
2040dcfafe7SUwe Kleine-König 	if (!state->enabled) {
2050dcfafe7SUwe Kleine-König 		if (pwm->state.enabled)
2060dcfafe7SUwe Kleine-König 			brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
2070dcfafe7SUwe Kleine-König 
2080dcfafe7SUwe Kleine-König 		return 0;
2090dcfafe7SUwe Kleine-König 	}
2100dcfafe7SUwe Kleine-König 
2110dcfafe7SUwe Kleine-König 	err = brcmstb_pwm_config(chip, pwm, state->duty_cycle, state->period);
2120dcfafe7SUwe Kleine-König 	if (err)
2130dcfafe7SUwe Kleine-König 		return err;
2140dcfafe7SUwe Kleine-König 
2150dcfafe7SUwe Kleine-König 	if (!pwm->state.enabled)
2163a9f5957SFlorian Fainelli 		brcmstb_pwm_enable_set(p, pwm->hwpwm, true);
2173a9f5957SFlorian Fainelli 
2183a9f5957SFlorian Fainelli 	return 0;
2193a9f5957SFlorian Fainelli }
2203a9f5957SFlorian Fainelli 
2213a9f5957SFlorian Fainelli static const struct pwm_ops brcmstb_pwm_ops = {
2220dcfafe7SUwe Kleine-König 	.apply = brcmstb_pwm_apply,
2233a9f5957SFlorian Fainelli 	.owner = THIS_MODULE,
2243a9f5957SFlorian Fainelli };
2253a9f5957SFlorian Fainelli 
2263a9f5957SFlorian Fainelli static const struct of_device_id brcmstb_pwm_of_match[] = {
2273a9f5957SFlorian Fainelli 	{ .compatible = "brcm,bcm7038-pwm", },
2283a9f5957SFlorian Fainelli 	{ /* sentinel */ }
2293a9f5957SFlorian Fainelli };
2303a9f5957SFlorian Fainelli MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
2313a9f5957SFlorian Fainelli 
brcmstb_pwm_probe(struct platform_device * pdev)2323a9f5957SFlorian Fainelli static int brcmstb_pwm_probe(struct platform_device *pdev)
2333a9f5957SFlorian Fainelli {
2343a9f5957SFlorian Fainelli 	struct brcmstb_pwm *p;
2353a9f5957SFlorian Fainelli 	int ret;
2363a9f5957SFlorian Fainelli 
2373a9f5957SFlorian Fainelli 	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
2383a9f5957SFlorian Fainelli 	if (!p)
2393a9f5957SFlorian Fainelli 		return -ENOMEM;
2403a9f5957SFlorian Fainelli 
2413a9f5957SFlorian Fainelli 	p->clk = devm_clk_get(&pdev->dev, NULL);
2423a9f5957SFlorian Fainelli 	if (IS_ERR(p->clk)) {
2433a9f5957SFlorian Fainelli 		dev_err(&pdev->dev, "failed to obtain clock\n");
2443a9f5957SFlorian Fainelli 		return PTR_ERR(p->clk);
2453a9f5957SFlorian Fainelli 	}
2463a9f5957SFlorian Fainelli 
2473a9f5957SFlorian Fainelli 	ret = clk_prepare_enable(p->clk);
2483a9f5957SFlorian Fainelli 	if (ret < 0) {
2493a9f5957SFlorian Fainelli 		dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
2503a9f5957SFlorian Fainelli 		return ret;
2513a9f5957SFlorian Fainelli 	}
2523a9f5957SFlorian Fainelli 
2533a9f5957SFlorian Fainelli 	platform_set_drvdata(pdev, p);
2543a9f5957SFlorian Fainelli 
2553a9f5957SFlorian Fainelli 	p->chip.dev = &pdev->dev;
2563a9f5957SFlorian Fainelli 	p->chip.ops = &brcmstb_pwm_ops;
2573a9f5957SFlorian Fainelli 	p->chip.npwm = 2;
2583a9f5957SFlorian Fainelli 
2595bec839fSYangtao Li 	p->base = devm_platform_ioremap_resource(pdev, 0);
260c5857e3fSVladimir Zapolskiy 	if (IS_ERR(p->base)) {
261c5857e3fSVladimir Zapolskiy 		ret = PTR_ERR(p->base);
2623a9f5957SFlorian Fainelli 		goto out_clk;
2633a9f5957SFlorian Fainelli 	}
2643a9f5957SFlorian Fainelli 
2653a9f5957SFlorian Fainelli 	ret = pwmchip_add(&p->chip);
2663a9f5957SFlorian Fainelli 	if (ret) {
2673a9f5957SFlorian Fainelli 		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
2683a9f5957SFlorian Fainelli 		goto out_clk;
2693a9f5957SFlorian Fainelli 	}
2703a9f5957SFlorian Fainelli 
2713a9f5957SFlorian Fainelli 	return 0;
2723a9f5957SFlorian Fainelli 
2733a9f5957SFlorian Fainelli out_clk:
2743a9f5957SFlorian Fainelli 	clk_disable_unprepare(p->clk);
2753a9f5957SFlorian Fainelli 	return ret;
2763a9f5957SFlorian Fainelli }
2773a9f5957SFlorian Fainelli 
brcmstb_pwm_remove(struct platform_device * pdev)278e577bffdSUwe Kleine-König static void brcmstb_pwm_remove(struct platform_device *pdev)
2793a9f5957SFlorian Fainelli {
2803a9f5957SFlorian Fainelli 	struct brcmstb_pwm *p = platform_get_drvdata(pdev);
2813a9f5957SFlorian Fainelli 
282b4334246SUwe Kleine-König 	pwmchip_remove(&p->chip);
2833a9f5957SFlorian Fainelli 	clk_disable_unprepare(p->clk);
2843a9f5957SFlorian Fainelli }
2853a9f5957SFlorian Fainelli 
2863a9f5957SFlorian Fainelli #ifdef CONFIG_PM_SLEEP
brcmstb_pwm_suspend(struct device * dev)2873a9f5957SFlorian Fainelli static int brcmstb_pwm_suspend(struct device *dev)
2883a9f5957SFlorian Fainelli {
2893a9f5957SFlorian Fainelli 	struct brcmstb_pwm *p = dev_get_drvdata(dev);
2903a9f5957SFlorian Fainelli 
291*1498352eSFlorian Fainelli 	clk_disable_unprepare(p->clk);
2923a9f5957SFlorian Fainelli 
2933a9f5957SFlorian Fainelli 	return 0;
2943a9f5957SFlorian Fainelli }
2953a9f5957SFlorian Fainelli 
brcmstb_pwm_resume(struct device * dev)2963a9f5957SFlorian Fainelli static int brcmstb_pwm_resume(struct device *dev)
2973a9f5957SFlorian Fainelli {
2983a9f5957SFlorian Fainelli 	struct brcmstb_pwm *p = dev_get_drvdata(dev);
2993a9f5957SFlorian Fainelli 
300*1498352eSFlorian Fainelli 	clk_prepare_enable(p->clk);
3013a9f5957SFlorian Fainelli 
3023a9f5957SFlorian Fainelli 	return 0;
3033a9f5957SFlorian Fainelli }
3043a9f5957SFlorian Fainelli #endif
3053a9f5957SFlorian Fainelli 
3063a9f5957SFlorian Fainelli static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
3073a9f5957SFlorian Fainelli 			 brcmstb_pwm_resume);
3083a9f5957SFlorian Fainelli 
3093a9f5957SFlorian Fainelli static struct platform_driver brcmstb_pwm_driver = {
3103a9f5957SFlorian Fainelli 	.probe = brcmstb_pwm_probe,
311e577bffdSUwe Kleine-König 	.remove_new = brcmstb_pwm_remove,
3123a9f5957SFlorian Fainelli 	.driver = {
3133a9f5957SFlorian Fainelli 		.name = "pwm-brcmstb",
3143a9f5957SFlorian Fainelli 		.of_match_table = brcmstb_pwm_of_match,
3153a9f5957SFlorian Fainelli 		.pm = &brcmstb_pwm_pm_ops,
3163a9f5957SFlorian Fainelli 	},
3173a9f5957SFlorian Fainelli };
3183a9f5957SFlorian Fainelli module_platform_driver(brcmstb_pwm_driver);
3193a9f5957SFlorian Fainelli 
3203a9f5957SFlorian Fainelli MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
3213a9f5957SFlorian Fainelli MODULE_DESCRIPTION("Broadcom STB PWM driver");
3223a9f5957SFlorian Fainelli MODULE_ALIAS("platform:pwm-brcmstb");
3233a9f5957SFlorian Fainelli MODULE_LICENSE("GPL");
324