فهرست منبع

vp6500: Add backlight device

SVN-Revision: 20843
Lars-Peter Clausen 15 سال پیش
والد
کامیت
e438c665db

+ 39 - 1
target/linux/mx2/files/arch/arm/mach-mx2/mach-vp6500.c

@@ -20,9 +20,9 @@
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/gpio_keys.h>
+#include <linux/pwm_backlight.h>
 
 static unsigned int vp6500_pins[] = {
-
 	/* UART1 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -52,8 +52,14 @@ static unsigned int vp6500_pins[] = {
 	PA30_PF_CONTRAST,
 	PA31_PF_OE_ACD,
 #endif
+
+	/* LCD Backlight */
+	PE5_PF_PWMO,
+	VP6500_GPIO_BACKLIGHT_EN | GPIO_GPIO | GPIO_OUT,
 };
 
+/* Flash */
+
 static struct physmap_flash_data vp6500_flash_data = {
 	.width = 2,
 };
@@ -74,6 +80,8 @@ static struct platform_device vp6500_nor_mtd_device = {
 	.resource = &vp6500_flash_resource,
 };
 
+/* LEDs */
+
 static struct gpio_led vp6500_leds[] = {
 	{
 		.name = "vp6500:orange:keypad",
@@ -108,6 +116,8 @@ static struct platform_device vp6500_leds_device = {
 	},
 };
 
+/* Keypad */
+
 static const uint32_t vp6500_keypad_keys[] = {
 	KEY(0, 3, KEY_F2),
 	KEY(0, 4, KEY_RIGHT),
@@ -180,11 +190,38 @@ static struct platform_device vp6500_key_device = {
 	},
 };
 
+/* LCD backlight */
+
+static int vp6500_backlight_notify(struct device *dev, int brightness)
+{
+	gpio_set_value(VP6500_GPIO_BACKLIGHT_EN, !!brightness);
+
+	return brightness;
+}
+
+static struct platform_pwm_backlight_data vp6500_backlight_data = {
+	.max_brightness = 255,
+	.dft_brightness = 100,
+	.pwm_period_ns = 15000000,
+	.notify = vp6500_backlight_notify,
+};
+
+static struct platform_device vp6500_backlight_device = {
+	.name = "pwm-backlight",
+	.id = -1,
+	.dev = {
+		.parent = &mxc_pwm_device.dev,
+		.platform_data = &vp6500_backlight_data,
+	},
+};
+
+
 static struct platform_device *platform_devices[] __initdata = {
 	&vp6500_nor_mtd_device,
 	&vp6500_leds_device,
 	&vp6500_keypad_device,
 	&vp6500_key_device,
+	&vp6500_backlight_device,
 };
 
 static void __init vp6500_board_init(void)
@@ -193,6 +230,7 @@ static void __init vp6500_board_init(void)
 			"vp6500");
 
 	mxc_register_device(&mxc_uart_device0, NULL);
+	mxc_register_device(&mxc_pwm_device, NULL);
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }

+ 11 - 7
target/linux/mx2/files/arch/arm/plat-mxc/include/mach/board-vp6500.h

@@ -2,12 +2,16 @@
 #ifndef __BOARD_VP6500__
 #define __BOARD_VP6500__
 
-#define VP6500_GPIO_POWER_KEY		39
-#define VP6500_GPIO_CAMERA_DIRECTION	45
-#define VP6500_GPIO_LED_KEYPAD		82
-#define VP6500_GPIO_AMP_ENABLE		89
-#define VP6500_GPIO_LED_RED		91
-#define VP6500_GPIO_LED_GREEN		92
-#define VP6500_GPIO_LED_CAMERA		93
+#define VP6500_GPIO_POWER_KEY		GPIO_PORTB | 5
+#define VP6500_GPIO_CAMERA_DIRECTION	GPIO_PORTB | 13
+#define VP6500_GPIO_LED_KEYPAD		GPIO_PORTC | 18
+#define VP6500_GPIO_AMP_ENABLE		GPIO_PORTC | 25
+#define VP6500_GPIO_LED_RED		GPIO_PORTC | 27
+#define VP6500_GPIO_LED_GREEN		GPIO_PORTC | 28
+#define VP6500_GPIO_LED_CAMERA		GPIO_PORTC | 29
+#define VP6500_GPIO_BACKLIGHT_EN	GPIO_PORTE | 10
+
+#define VP6500_GPIO_TLV_RESET		GPIO_PORTB | 27
+#define VP6500_GPIO_TLV_ENABLE		GPIO_PORTC | 25
 
 #endif

+ 137 - 0
target/linux/mx2/patches-2.6.34/040-pwm.patch

@@ -0,0 +1,137 @@
+diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
+index c36f263..acc5dc1 100644
+--- a/arch/arm/plat-mxc/pwm.c
++++ b/arch/arm/plat-mxc/pwm.c
+@@ -25,6 +25,11 @@
+ #define MX1_PWMS    0x04   /* PWM Sample Register */
+ #define MX1_PWMP    0x08   /* PWM Period Register */
+ 
++#define MX1_PWMC_EN (1 << 4)
++#define MX1_PWMC_PRESCALER_MASK (0x7f << 8)
++#define MX1_PWMC_PRESCALER(x) ((x & 0x7f) << 8)
++#define MX1_PWMC_CLKSEL_MASK 0x3
++#define MX1_PWMC_CLKSEL(x) ((x & 0x3))
+ 
+ /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
+ 
+@@ -54,25 +59,32 @@ struct pwm_device {
+ 
+ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+ {
++	unsigned long long c;
++	unsigned long period_cycles, duty_cycles, prescale;
++
+ 	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+ 		return -EINVAL;
+ 
+-	if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
+-		unsigned long long c;
+-		unsigned long period_cycles, duty_cycles, prescale;
+-		u32 cr;
++	c = clk_get_rate(pwm->clk);
++
++	c = c * period_ns;
++
++	if (cpu_is_mx1() || cpu_is_mx2())
++		c >>= 1;
+ 
+-		c = clk_get_rate(pwm->clk);
+-		c = c * period_ns;
+-		do_div(c, 1000000000);
+-		period_cycles = c;
++	do_div(c, 1000000000);
++	period_cycles = c;
+ 
+-		prescale = period_cycles / 0x10000 + 1;
++	prescale = period_cycles / 0x10000 + 1;
+ 
+-		period_cycles /= prescale;
+-		c = (unsigned long long)period_cycles * duty_ns;
+-		do_div(c, period_ns);
+-		duty_cycles = c;
++	period_cycles /= prescale;
++	c = (unsigned long long)period_cycles * duty_ns;
++	do_div(c, period_ns);
++	duty_cycles = c;
++
++
++	if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
++		u32 cr;
+ 
+ 		writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
+ 		writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
+@@ -86,25 +98,28 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+ 
+ 		writel(cr, pwm->mmio_base + MX3_PWMCR);
+ 	} else if (cpu_is_mx1() || cpu_is_mx21()) {
+-		/* The PWM subsystem allows for exact frequencies. However,
+-		 * I cannot connect a scope on my device to the PWM line and
+-		 * thus cannot provide the program the PWM controller
+-		 * exactly. Instead, I'm relying on the fact that the
+-		 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
+-		 * function group already. So I'll just modify the PWM sample
+-		 * register to follow the ratio of duty_ns vs. period_ns
+-		 * accordingly.
+-		 *
+-		 * This is good enough for programming the brightness of
+-		 * the LCD backlight.
+-		 *
+-		 * The real implementation would divide PERCLK[0] first by
+-		 * both the prescaler (/1 .. /128) and then by CLKSEL
+-		 * (/2 .. /16).
+-		 */
+-		u32 max = readl(pwm->mmio_base + MX1_PWMP);
+-		u32 p = max * duty_ns / period_ns;
+-		writel(max - p, pwm->mmio_base + MX1_PWMS);
++		unsigned long clksel = 0;
++		u32 ctrl;
++
++		while (prescale >= 0x80 && clksel < 4) {
++			prescale >>= 1;
++			++clksel;
++		}
++
++		if (clksel > 3)
++			return -EINVAL;
++
++		ctrl = readl(pwm->mmio_base + MX1_PWMC);
++		writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
++
++		writel(duty_cycles, pwm->mmio_base + MX1_PWMS);
++		writel(period_cycles, pwm->mmio_base + MX1_PWMP);
++
++		ctrl &= ~(MX1_PWMC_PRESCALER_MASK | MX1_PWMC_CLKSEL_MASK);
++		ctrl |= MX1_PWMC_PRESCALER(prescale);
++		ctrl |= MX1_PWMC_CLKSEL(clksel);
++		writel(ctrl, pwm->mmio_base + MX1_PWMC);
++
+ 	} else {
+ 		BUG();
+ 	}
+@@ -116,6 +130,11 @@ EXPORT_SYMBOL(pwm_config);
+ int pwm_enable(struct pwm_device *pwm)
+ {
+ 	int rc = 0;
++	if (cpu_is_mx1() || cpu_is_mx2()) {
++		u32 ctrl;
++		ctrl = readl(pwm->mmio_base + MX1_PWMC);
++		writel(ctrl | MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
++	}
+ 
+ 	if (!pwm->clk_enabled) {
+ 		rc = clk_enable(pwm->clk);
+@@ -128,7 +147,13 @@ EXPORT_SYMBOL(pwm_enable);
+ 
+ void pwm_disable(struct pwm_device *pwm)
+ {
+-	writel(0, pwm->mmio_base + MX3_PWMCR);
++	if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
++		writel(0, pwm->mmio_base + MX3_PWMCR);
++	} else if (cpu_is_mx1() || cpu_is_mx2()) {
++		u32 ctrl;
++		ctrl = readl(pwm->mmio_base + MX1_PWMC);
++		writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
++	}
+ 
+ 	if (pwm->clk_enabled) {
+ 		clk_disable(pwm->clk);