9
0
Fork 0

Add pwm core support

This patch adds framework support for PWM (pulse width modulation)
devices.
A new pwm can be registered from a hardware driver using
pwmchip_add(). It can then be requested from a client driver using
pwm_request(). A string is used as a unique identifier for the
pwms. It should usually be initialized by the hardware drivers
using dev_name(dev). The client API is the same as currently
in the Linux Kernel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2012-01-31 10:19:50 +01:00
parent c20952a621
commit f917e6f866
6 changed files with 242 additions and 0 deletions

View File

@ -15,4 +15,6 @@ source "drivers/mfd/Kconfig"
source "drivers/led/Kconfig"
source "drivers/eeprom/Kconfig"
source "drivers/pwm/Kconfig"
endmenu

View File

@ -13,3 +13,4 @@ obj-y += clk/
obj-y += mfd/
obj-$(CONFIG_LED) += led/
obj-y += eeprom/
obj-$(CONFIG_PWM) += pwm/

12
drivers/pwm/Kconfig Normal file
View File

@ -0,0 +1,12 @@
menuconfig PWM
bool "PWM Support"
help
This enables PWM support through the generic PWM framework.
You only need to enable this, if you also want to enable
one or more of the PWM drivers below.
If unsure, say N.
if PWM
endif

1
drivers/pwm/Makefile Normal file
View File

@ -0,0 +1 @@
obj-$(CONFIG_PWM) += core.o

163
drivers/pwm/core.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Generic pwmlib implementation
*
* Copyright (C) 2011 Sascha Hauer <s.hauer@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <pwm.h>
#include <linux/list.h>
struct pwm_device {
struct pwm_chip *chip;
unsigned long flags;
#define FLAG_REQUESTED 0
#define FLAG_ENABLED 1
struct list_head node;
};
static LIST_HEAD(pwm_list);
static struct pwm_device *_find_pwm(const char *devname)
{
struct pwm_device *pwm;
list_for_each_entry(pwm, &pwm_list, node) {
if (!strcmp(pwm->chip->devname, devname))
return pwm;
}
return NULL;
}
/**
* pwmchip_add() - register a new pwm
* @chip: the pwm
*
* register a new pwm. pwm->devname must be initialized, usually
* from dev_name(dev) from the hardware driver.
*/
int pwmchip_add(struct pwm_chip *chip)
{
struct pwm_device *pwm;
int ret = 0;
if (_find_pwm(chip->devname))
return -EBUSY;
pwm = xzalloc(sizeof(*pwm));
pwm->chip = chip;
list_add_tail(&pwm->node, &pwm_list);
return ret;
}
EXPORT_SYMBOL_GPL(pwmchip_add);
/**
* pwmchip_remove() - remove a pwm
* @chip: the pwm
*
* remove a pwm. This function may return busy if the pwm is still requested.
*/
int pwmchip_remove(struct pwm_chip *chip)
{
struct pwm_device *pwm;
pwm = _find_pwm(chip->devname);
if (!pwm)
return -ENOENT;
if (test_bit(FLAG_REQUESTED, &pwm->flags))
return -EBUSY;
list_del(&pwm->node);
kfree(pwm);
return 0;
}
EXPORT_SYMBOL_GPL(pwmchip_remove);
/*
* pwm_request - request a PWM device
*/
struct pwm_device *pwm_request(const char *devname)
{
struct pwm_device *pwm;
int ret;
pwm = _find_pwm(devname);
if (!pwm)
return NULL;
if (test_bit(FLAG_REQUESTED, &pwm->flags))
return NULL;
if (pwm->chip->ops->request) {
ret = pwm->chip->ops->request(pwm->chip);
if (ret)
return NULL;
}
set_bit(FLAG_REQUESTED, &pwm->flags);
return pwm;
}
EXPORT_SYMBOL_GPL(pwm_request);
/*
* pwm_free - free a PWM device
*/
void pwm_free(struct pwm_device *pwm)
{
if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags))
return;
}
EXPORT_SYMBOL_GPL(pwm_free);
/*
* pwm_config - change a PWM device configuration
*/
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
{
return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns);
}
EXPORT_SYMBOL_GPL(pwm_config);
/*
* pwm_enable - start a PWM output toggling
*/
int pwm_enable(struct pwm_device *pwm)
{
if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags))
return pwm->chip->ops->enable(pwm->chip);
return 0;
}
EXPORT_SYMBOL_GPL(pwm_enable);
/*
* pwm_disable - stop a PWM output toggling
*/
void pwm_disable(struct pwm_device *pwm)
{
if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags))
pwm->chip->ops->disable(pwm->chip);
}
EXPORT_SYMBOL_GPL(pwm_disable);

63
include/pwm.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef __PWM_H
#define __PWM_H
struct pwm_device;
/*
* pwm_request - request a PWM device
*/
struct pwm_device *pwm_request(const char *pwmname);
/*
* pwm_free - free a PWM device
*/
void pwm_free(struct pwm_device *pwm);
/*
* pwm_config - change a PWM device configuration
*/
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
/*
* pwm_enable - start a PWM output toggling
*/
int pwm_enable(struct pwm_device *pwm);
/*
* pwm_disable - stop a PWM output toggling
*/
void pwm_disable(struct pwm_device *pwm);
struct pwm_chip;
/**
* struct pwm_ops - PWM operations
* @request: optional hook for requesting a PWM
* @free: optional hook for freeing a PWM
* @config: configure duty cycles and period length for this PWM
* @enable: enable PWM output toggling
* @disable: disable PWM output toggling
*/
struct pwm_ops {
int (*request)(struct pwm_chip *chip);
void (*free)(struct pwm_chip *chip);
int (*config)(struct pwm_chip *chip, int duty_ns,
int period_ns);
int (*enable)(struct pwm_chip *chip);
void (*disable)(struct pwm_chip *chip);
};
/**
* struct pwm_chip - abstract a PWM
* @devname: unique identifier for this pwm
* @ops: The callbacks for this PWM
*/
struct pwm_chip {
const char *devname;
struct pwm_ops *ops;
};
int pwmchip_add(struct pwm_chip *chip);
int pwmchip_remove(struct pwm_chip *chip);
#endif /* __PWM_H */