Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79c11b6f authored by Thierry Reding's avatar Thierry Reding
Browse files

pwm: Move PUV3 PWM driver to PWM framework



This commit moves the driver to drivers/pwm and converts it to the new
PWM framework.

Signed-off-by: default avatarThierry Reding <thierry.reding@avionic-design.de>
Tested-by: default avatarQin Rui <qinrui@mprc.pku.edu.cn>
Acked-by: default avatarGuan Xuetao <gxt@mprc.pku.edu.cn>
parent 5384e273
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -20,9 +20,6 @@ config UNICORE32
	  designs licensed by PKUnity Ltd.
	  Please see web page at <http://www.pkunity.com/>.

config HAVE_PWM
	bool

config GENERIC_GPIO
	def_bool y

@@ -105,7 +102,8 @@ config PUV3_DB0913

config PUV3_NB0916
	bool "NetBook board (0916)"
	select HAVE_PWM
	select PWM
	select PWM_PUV3

config PUV3_SMW0919
	bool "Security Mini-Workstation board (0919)"
@@ -219,12 +217,6 @@ config PUV3_GPIO
	select GPIO_SYSFS if EXPERIMENTAL
	default y

config PUV3_PWM
	tristate
	default BACKLIGHT_PWM
	help
	  Enable support for NB0916 PWM controllers

if PUV3_NB0916

menu "PKUnity NetBook-0916 Features"
+0 −1
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
obj-$(CONFIG_ARCH_PUV3)		+= clock.o irq.o time.o

obj-$(CONFIG_PUV3_GPIO)		+= gpio.o
obj-$(CONFIG_PUV3_PWM)		+= pwm.o
obj-$(CONFIG_PUV3_PM)		+= pm.o sleep.o
obj-$(CONFIG_HIBERNATION)	+= hibernate.o hibernate_asm.o

+10 −1
Original line number Diff line number Diff line
menuconfig PWM
	bool "Pulse-Width Modulation (PWM) Support"
	depends on !MACH_JZ4740 && !PUV3_PWM
	depends on !MACH_JZ4740
	help
	  Generic Pulse-Width Modulation (PWM) support.

@@ -76,6 +76,15 @@ config PWM_MXS
	  To compile this driver as a module, choose M here: the module
	  will be called pwm-mxs.

config PWM_PUV3
	tristate "PKUnity NetBook-0916 PWM support"
	depends on ARCH_PUV3
	help
	  Generic PWM framework driver for PKUnity NetBook-0916.

	  To compile this driver as a module, choose M here: the module
	  will be called pwm-puv3.

config PWM_PXA
	tristate "PXA PWM support"
	depends on ARCH_PXA
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
obj-$(CONFIG_PWM_IMX)		+= pwm-imx.o
obj-$(CONFIG_PWM_LPC32XX)	+= pwm-lpc32xx.o
obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
obj-$(CONFIG_PWM_PUV3)		+= pwm-puv3.o
obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
+161 −0
Original line number Diff line number Diff line
@@ -23,39 +23,37 @@
#include <asm/div64.h>
#include <mach/hardware.h>

struct pwm_device {
	struct list_head	node;
	struct platform_device *pdev;

struct puv3_pwm_chip {
	struct pwm_chip chip;
	void __iomem *base;

	const char	*label;
	struct clk *clk;
	int		clk_enabled;

	unsigned int	use_count;
	unsigned int	pwm_id;
	bool enabled;
};

static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip)
{
	return container_of(chip, struct puv3_pwm_chip, chip);
}

/*
 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
 * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
 */
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
			   int duty_ns, int period_ns)
{
	unsigned long long c;
	unsigned long period_cycles, prescale, pv, dc;
	struct puv3_pwm_chip *puv3 = to_puv3(chip);
	unsigned long long c;

	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
		return -EINVAL;

	c = clk_get_rate(pwm->clk);
	c = clk_get_rate(puv3->clk);
	c = c * period_ns;
	do_div(c, 1000000000);
	period_cycles = c;

	if (period_cycles < 1)
		period_cycles = 1;

	prescale = (period_cycles - 1) / 1024;
	pv = period_cycles / (prescale + 1) - 1;

@@ -67,115 +65,57 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
	else
		dc = (pv + 1) * duty_ns / period_ns;

	/* NOTE: the clock to PWM has to be enabled first
	/*
	 * NOTE: the clock to PWM has to be enabled first
	 * before writing to the registers
	 */
	clk_enable(pwm->clk);
	clk_prepare_enable(puv3->clk);

	writel(prescale, pwm->base + OST_PWM_PWCR);
	writel(pv - dc, pwm->base + OST_PWM_DCCR);
	writel(pv, pwm->base + OST_PWM_PCR);
	writel(prescale, puv3->base + OST_PWM_PWCR);
	writel(pv - dc, puv3->base + OST_PWM_DCCR);
	writel(pv, puv3->base + OST_PWM_PCR);

	clk_disable(pwm->clk);
	clk_disable_unprepare(puv3->clk);

	return 0;
}
EXPORT_SYMBOL(pwm_config);

int pwm_enable(struct pwm_device *pwm)
static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	int rc = 0;

	if (!pwm->clk_enabled) {
		rc = clk_enable(pwm->clk);
		if (!rc)
			pwm->clk_enabled = 1;
	}
	return rc;
}
EXPORT_SYMBOL(pwm_enable);
	struct puv3_pwm_chip *puv3 = to_puv3(chip);

void pwm_disable(struct pwm_device *pwm)
{
	if (pwm->clk_enabled) {
		clk_disable(pwm->clk);
		pwm->clk_enabled = 0;
	}
	return clk_prepare_enable(puv3->clk);
}
EXPORT_SYMBOL(pwm_disable);

static DEFINE_MUTEX(pwm_lock);
static LIST_HEAD(pwm_list);

struct pwm_device *pwm_request(int pwm_id, const char *label)
static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct pwm_device *pwm;
	int found = 0;
	struct puv3_pwm_chip *puv3 = to_puv3(chip);

	mutex_lock(&pwm_lock);

	list_for_each_entry(pwm, &pwm_list, node) {
		if (pwm->pwm_id == pwm_id) {
			found = 1;
			break;
		}
	clk_disable_unprepare(puv3->clk);
}

	if (found) {
		if (pwm->use_count == 0) {
			pwm->use_count++;
			pwm->label = label;
		} else
			pwm = ERR_PTR(-EBUSY);
	} else
		pwm = ERR_PTR(-ENOENT);

	mutex_unlock(&pwm_lock);
	return pwm;
}
EXPORT_SYMBOL(pwm_request);

void pwm_free(struct pwm_device *pwm)
{
	mutex_lock(&pwm_lock);

	if (pwm->use_count) {
		pwm->use_count--;
		pwm->label = NULL;
	} else
		pr_warning("PWM device already freed\n");

	mutex_unlock(&pwm_lock);
}
EXPORT_SYMBOL(pwm_free);

static inline void __add_pwm(struct pwm_device *pwm)
{
	mutex_lock(&pwm_lock);
	list_add_tail(&pwm->node, &pwm_list);
	mutex_unlock(&pwm_lock);
}
static const struct pwm_ops puv3_pwm_ops = {
	.config = puv3_pwm_config,
	.enable = puv3_pwm_enable,
	.disable = puv3_pwm_disable,
	.owner = THIS_MODULE,
};

static int __devinit pwm_probe(struct platform_device *pdev)
{
	struct pwm_device *pwm;
	struct puv3_pwm_chip *puv3;
	struct resource *r;
	int ret;

	pwm = devm_kzalloc(&pdev->dev, sizeof(struct pwm_device), GFP_KERNEL);
	if (pwm == NULL) {
	puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
	if (puv3 == NULL) {
		dev_err(&pdev->dev, "failed to allocate memory\n");
		return -ENOMEM;
	}

	pwm->clk = devm_clk_get(&pdev->dev, "OST_CLK");
	if (IS_ERR(pwm->clk))
		return PTR_ERR(pwm->clk);

	pwm->clk_enabled = 0;

	pwm->use_count = 0;
	pwm->pwm_id = pdev->id;
	pwm->pdev = pdev;
	puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
	if (IS_ERR(puv3->clk))
		return PTR_ERR(puv3->clk);

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (r == NULL) {
@@ -183,28 +123,30 @@ static int __devinit pwm_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	pwm->base = devm_request_and_ioremap(&pdev->dev, r);
	if (pwm->base == NULL)
	puv3->base = devm_request_and_ioremap(&pdev->dev, r);
	if (puv3->base == NULL)
		return -EADDRNOTAVAIL;

	__add_pwm(pwm);
	platform_set_drvdata(pdev, pwm);
	puv3->chip.dev = &pdev->dev;
	puv3->chip.ops = &puv3_pwm_ops;
	puv3->chip.base = -1;
	puv3->chip.npwm = 1;

	ret = pwmchip_add(&puv3->chip);
	if (ret < 0) {
		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
		return ret;
	}

	platform_set_drvdata(pdev, puv3);
	return 0;
}

static int __devexit pwm_remove(struct platform_device *pdev)
{
	struct pwm_device *pwm;
	struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev);

	pwm = platform_get_drvdata(pdev);
	if (pwm == NULL)
		return -ENODEV;

	mutex_lock(&pwm_lock);
	list_del(&pwm->node);
	mutex_unlock(&pwm_lock);

	return 0;
	return pwmchip_remove(&puv3->chip);
}

static struct platform_driver puv3_pwm_driver = {
Loading