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

Commit ef12379f authored by Hartley Sweeten's avatar Hartley Sweeten Committed by Russell King
Browse files

ARM: 5628/1: ep93xx: Introduce Pulse Width Modulator (PWM) driver



The EP93xx features two PWMs (one on the EP9307) with the following
features:

  * Configurable dual output
  * Separate input clocks for each PWM output
  * 16-bit resolution
  * Programmable pulse width (duty cycle), interval (frequency), and
    polarity

This adds the necessary core support as well as the driver.  A sysfs
interface is provided to control the PWM outputs.

Signed-off-by: default avatarMatthieu Crapet <mcrapet@gmail.com>
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Acked-by: default avatarRyan Mallon <ryan@bluewatersys.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 3aa7a9a3
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -72,6 +72,9 @@ static struct clk clk_keypad = {
	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
	.set_rate	= set_keytchclk_rate,
};
static struct clk clk_pwm = {
	.rate		= EP93XX_EXT_CLK_RATE,
};

/* DMA Clocks */
static struct clk clk_m2p0 = {
@@ -137,6 +140,7 @@ static struct clk_lookup clocks[] = {
	INIT_CK(NULL,			"pll2",		&clk_pll2),
	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
	INIT_CK(NULL,			"m2p2",		&clk_m2p2),
+85 −0
Original line number Diff line number Diff line
@@ -597,6 +597,91 @@ static struct platform_device ep93xx_leds = {
};


/*************************************************************************
 * EP93xx pwm peripheral handling
 *************************************************************************/
static struct resource ep93xx_pwm0_resource[] = {
	{
		.start	= EP93XX_PWM_PHYS_BASE,
		.end	= EP93XX_PWM_PHYS_BASE + 0x10 - 1,
		.flags	= IORESOURCE_MEM,
	},
};

static struct platform_device ep93xx_pwm0_device = {
	.name		= "ep93xx-pwm",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(ep93xx_pwm0_resource),
	.resource	= ep93xx_pwm0_resource,
};

static struct resource ep93xx_pwm1_resource[] = {
	{
		.start	= EP93XX_PWM_PHYS_BASE + 0x20,
		.end	= EP93XX_PWM_PHYS_BASE + 0x30 - 1,
		.flags	= IORESOURCE_MEM,
	},
};

static struct platform_device ep93xx_pwm1_device = {
	.name		= "ep93xx-pwm",
	.id		= 1,
	.num_resources	= ARRAY_SIZE(ep93xx_pwm1_resource),
	.resource	= ep93xx_pwm1_resource,
};

void __init ep93xx_register_pwm(int pwm0, int pwm1)
{
	if (pwm0)
		platform_device_register(&ep93xx_pwm0_device);

	/* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */
	if (pwm1)
		platform_device_register(&ep93xx_pwm1_device);
}

int ep93xx_pwm_acquire_gpio(struct platform_device *pdev)
{
	int err;

	if (pdev->id == 0) {
		err = 0;
	} else if (pdev->id == 1) {
		err = gpio_request(EP93XX_GPIO_LINE_EGPIO14,
				   dev_name(&pdev->dev));
		if (err)
			return err;
		err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0);
		if (err)
			goto fail;

		/* PWM 1 output on EGPIO[14] */
		ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG);
	} else {
		err = -ENODEV;
	}

	return err;

fail:
	gpio_free(EP93XX_GPIO_LINE_EGPIO14);
	return err;
}
EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio);

void ep93xx_pwm_release_gpio(struct platform_device *pdev)
{
	if (pdev->id == 1) {
		gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14);
		gpio_free(EP93XX_GPIO_LINE_EGPIO14);

		/* EGPIO[14] used for GPIO */
		ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG);
	}
}
EXPORT_SYMBOL(ep93xx_pwm_release_gpio);


extern void ep93xx_gpio_init(void);

void __init ep93xx_init_devices(void)
+1 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@
#define EP93XX_ADC_BASE			EP93XX_APB_IOMEM(0x00100000)
#define EP93XX_TOUCHSCREEN_BASE		EP93XX_APB_IOMEM(0x00100000)

#define EP93XX_PWM_PHYS_BASE		(EP93XX_APB_PHYS_BASE + 0x00110000)
#define EP93XX_PWM_BASE			EP93XX_APB_IOMEM(0x00110000)

#define EP93XX_RTC_PHYS_BASE		(EP93XX_APB_PHYS_BASE + 0x00120000)
+4 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__

struct i2c_board_info;
struct platform_device;

struct ep93xx_eth_data
{
@@ -32,6 +33,9 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)

void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
void ep93xx_register_pwm(int pwm0, int pwm1);
int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
void ep93xx_pwm_release_gpio(struct platform_device *pdev);

void ep93xx_init_devices(void);
extern struct sys_timer ep93xx_timer;
+13 −0
Original line number Diff line number Diff line
@@ -233,6 +233,19 @@ config ISL29003
	  This driver can also be built as a module.  If so, the module
	  will be called isl29003.

config EP93XX_PWM
	tristate "EP93xx PWM support"
	depends on ARCH_EP93XX
	help
	  This option enables device driver support for the PWM channels
	  on the Cirrus EP93xx processors.  The EP9307 chip only has one
	  PWM channel all the others have two, the second channel is an
	  alternate function of the EGPIO14 pin.  A sysfs interface is
	  provided to control the PWM channels.

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

source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
Loading