Basic PWM driver for AVR32 and AT91

PWM device setup, and a simple PWM driver exposing a programming interface
giving access to each channel's full capabilities.  Note that this doesn't
support starting several channels in synch.

[hskinnemoen@atmel.com: allocate platform device dynamically]
[hskinnemoen@atmel.com: Kconfig fix]
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Andrew Victor <linux@maxim.org.za>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 14e61f0..7678fee 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -1186,6 +1186,59 @@
 #endif
 
 /* --------------------------------------------------------------------
+ *  PWM
+ * -------------------------------------------------------------------- */
+static struct resource atmel_pwm0_resource[] __initdata = {
+	PBMEM(0xfff01400),
+	IRQ(24),
+};
+static struct clk atmel_pwm0_mck = {
+	.name		= "mck",
+	.parent		= &pbb_clk,
+	.mode		= pbb_clk_mode,
+	.get_rate	= pbb_clk_get_rate,
+	.index		= 5,
+};
+
+struct platform_device *__init at32_add_device_pwm(u32 mask)
+{
+	struct platform_device *pdev;
+
+	if (!mask)
+		return NULL;
+
+	pdev = platform_device_alloc("atmel_pwm", 0);
+	if (!pdev)
+		return NULL;
+
+	if (platform_device_add_resources(pdev, atmel_pwm0_resource,
+				ARRAY_SIZE(atmel_pwm0_resource)))
+		goto out_free_pdev;
+
+	if (platform_device_add_data(pdev, &mask, sizeof(mask)))
+		goto out_free_pdev;
+
+	if (mask & (1 << 0))
+		select_peripheral(PA(28), PERIPH_A, 0);
+	if (mask & (1 << 1))
+		select_peripheral(PA(29), PERIPH_A, 0);
+	if (mask & (1 << 2))
+		select_peripheral(PA(21), PERIPH_B, 0);
+	if (mask & (1 << 3))
+		select_peripheral(PA(22), PERIPH_B, 0);
+
+	atmel_pwm0_mck.dev = &pdev->dev;
+
+	platform_device_add(pdev);
+
+	return pdev;
+
+out_free_pdev:
+	platform_device_put(pdev);
+	return NULL;
+}
+
+/* --------------------------------------------------------------------
  *  SSC
  * -------------------------------------------------------------------- */
 static struct resource ssc0_resource[] = {
@@ -1646,6 +1699,7 @@
 	&atmel_usart1_usart,
 	&atmel_usart2_usart,
 	&atmel_usart3_usart,
+	&atmel_pwm0_mck,
 #if defined(CONFIG_CPU_AT32AP7000)
 	&macb0_hclk,
 	&macb0_pclk,