Created
June 2, 2012 19:48
-
-
Save fat-tire/2859735 to your computer and use it in GitHub Desktop.
patch to new led driver for encore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ git diff | |
diff --git a/arch/arm/mach-omap2/board-encore-display.c b/arch/arm/mach-omap2/board-encore-display.c | |
index b055e71..22ecb2c 100644 | |
--- a/arch/arm/mach-omap2/board-encore-display.c | |
+++ b/arch/arm/mach-omap2/board-encore-display.c | |
@@ -31,7 +31,7 @@ | |
#define LCD_CABC1_GPIO 45 | |
#define LCD_BACKLIGHT_EN_EVT2 47 | |
-#define DEFAULT_BACKLIGHT_BRIGHTNESS 105 | |
+#define DEFAULT_BACKLIGHT_BRIGHTNESS 75 | |
/*---backlight--------------------------------------------------------------------*/ | |
static void boxer_backlight_set_power(struct omap_pwm_led_platform_data *self, int on_off) | |
@@ -46,7 +46,7 @@ static struct omap_pwm_led_platform_data boxer_backlight_data = { | |
.bkl_max = 254, | |
.bkl_min = 5, | |
.bkl_freq = 128, | |
- .invert = 1, | |
+ .invert = 0, | |
.def_brightness = DEFAULT_BACKLIGHT_BRIGHTNESS, | |
.set_power = boxer_backlight_set_power, | |
}; | |
@@ -62,17 +62,12 @@ static struct platform_device boxer_backlight_led_device = { | |
static void __init boxer_backlight_init(void) | |
{ | |
printk("Enabling backlight PWM for LCD\n"); | |
- //boxer_backlight_data.def_on = 1; // change the PWM polarity | |
- gpio_request(LCD_BACKLIGHT_EN_EVT2, "lcd backlight evt2"); | |
- | |
- gpio_request(LCD_CABC0_GPIO, "lcd CABC0"); | |
- gpio_direction_output(LCD_CABC0_GPIO,0); | |
- gpio_set_value(LCD_CABC0_GPIO,0); | |
- | |
- gpio_request(LCD_CABC1_GPIO, "lcd CABC1"); | |
- gpio_direction_output(LCD_CABC1_GPIO,0); | |
- gpio_set_value(LCD_CABC1_GPIO,0); | |
+ omap_mux_init_signal("usbb1_ulpitll_dat4.gpio_92", OMAP_MUX_MODE3); | |
+ if (gpio_request(92, "EVT1 BACKLIGHT")) | |
+ printk(KERN_ERR "ERROR: failed to request backlight gpio\n"); | |
+ else | |
+ gpio_direction_output(92, 0); | |
} | |
/*--------------------------------------------------------------------------*/ | |
@@ -132,9 +127,6 @@ void __init encore_display_init(void) | |
boxer_backlight_init(); | |
spi_register_board_info(evt_spi_board_info, | |
ARRAY_SIZE(evt_spi_board_info)); | |
- | |
- platform_add_devices(evt_panel_devices, ARRAY_SIZE(evt_panel_devices)); | |
omap_display_init(&evt_dss_data); | |
- | |
+ platform_add_devices(evt_panel_devices, ARRAY_SIZE(evt_panel_devices)); | |
} | |
- | |
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c | |
index e807a61..591d75c 100644 | |
--- a/arch/arm/plat-omap/dmtimer.c | |
+++ b/arch/arm/plat-omap/dmtimer.c | |
@@ -54,6 +54,7 @@ | |
#define _OMAP_TIMER_STAT_OFFSET 0x18 | |
#define _OMAP_TIMER_INT_EN_OFFSET 0x1c | |
#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 | |
+#define _OMAP_TIMER_INT_CLR_OFFSET 0x30 | |
#define _OMAP_TIMER_CTRL_OFFSET 0x24 | |
#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) | |
#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) | |
@@ -111,6 +112,9 @@ | |
#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ | |
| (WP_NONE << WPSHIFT)) | |
+#define OMAP_TIMER_INT_CLR_REG (_OMAP_TIMER_INT_CLR_OFFSET \ | |
+ | (WP_NONE << WPSHIFT)) | |
+ | |
#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ | |
| (WP_NONE << WPSHIFT)) | |
@@ -753,6 +757,13 @@ int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, | |
} | |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match); | |
+unsigned int omap_dm_timer_get_match(struct omap_dm_timer *timer) | |
+{ | |
+ return omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG); | |
+} | |
+ | |
+EXPORT_SYMBOL_GPL(omap_dm_timer_get_match); | |
+ | |
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, | |
int toggle, int trigger) | |
{ | |
@@ -823,6 +834,27 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, | |
} | |
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); | |
+void omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, | |
+ unsigned int value) | |
+{ | |
+ u32 l; | |
+ struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data; | |
+ | |
+ omap_dm_timer_enable(timer); | |
+ | |
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG); | |
+ if (pdata->timer_ip_type == OMAP_TIMER_IP_VERSION_2) { | |
+ l |= value; | |
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_CLR_REG, value); | |
+ } else { | |
+ l &= ~value; | |
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, l); | |
+ } | |
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l); | |
+} | |
+EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable); | |
+ | |
+ | |
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) | |
{ | |
unsigned long flags; | |
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h | |
index aaa676f..6b57180 100644 | |
--- a/arch/arm/plat-omap/include/plat/dmtimer.h | |
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h | |
@@ -155,6 +155,9 @@ int omap_dm_timer_write_counter(struct omap_dm_timer *timer, | |
unsigned int value); | |
int omap_dm_timers_active(void); | |
+void omap_dm_timer_set_int_disable(struct omap_dm_timer *, unsigned int); | |
+ | |
+unsigned int omap_dm_timer_get_match(struct omap_dm_timer *timer); | |
#endif /* __ASM_ARCH_DMTIMER_H */ | |
diff --git a/drivers/leds/leds-omap-pwm.c b/drivers/leds/leds-omap-pwm.c | |
index f01b4c8..197cb33 100644 | |
--- a/drivers/leds/leds-omap-pwm.c | |
+++ b/drivers/leds/leds-omap-pwm.c | |
@@ -9,34 +9,56 @@ | |
* it under the terms of the GNU General Public License version 2 as | |
* published by the Free Software Foundation. | |
*/ | |
-#define DEBUG | |
#include <linux/kernel.h> | |
#include <linux/init.h> | |
#include <linux/err.h> | |
+#include <linux/earlysuspend.h> | |
#include <linux/platform_device.h> | |
#include <linux/leds.h> | |
#include <linux/ctype.h> | |
#include <linux/sched.h> | |
+#include <linux/interrupt.h> | |
+#include <linux/slab.h> | |
+#include <linux/delay.h> | |
#include <linux/clk.h> | |
-#include <asm/delay.h> | |
#include <plat/board.h> | |
#include <plat/dmtimer.h> | |
-#include <linux/slab.h> | |
-#include <linux/delay.h> | |
+#include "leds-omap-pwm.h" | |
-#define MAX_GPTIMER_ID 12 | |
+/* 38400000 / (1 << (COUNTER_DEVIDER + 1)) */ | |
+#define COUNTER_DEVIDER 5 /* 600000 Hz counter in freq */ | |
+#define COUNTER_LOAD_VAL (0xFFFFFFFF - 4687 - 4) /* 128 Hz PWM out freq */ | |
+#define COUNTER_TO_MATCH_GUARD 80 | |
+ | |
+#define TIMER_INT_FLAGS (OMAP_TIMER_INT_MATCH | \ | |
+ OMAP_TIMER_INT_OVERFLOW) | |
+ | |
+#ifdef CONFIG_HAS_EARLYSUSPEND | |
+static void omap_pwm_led_early_suspend(struct early_suspend *handler); | |
+static void omap_pwm_led_late_resume(struct early_suspend *handler); | |
+#endif | |
struct omap_pwm_led { | |
struct led_classdev cdev; | |
+ struct work_struct work; | |
struct omap_pwm_led_platform_data *pdata; | |
struct omap_dm_timer *intensity_timer; | |
struct omap_dm_timer *blink_timer; | |
int powered; | |
unsigned int on_period, off_period; | |
enum led_brightness brightness; | |
+#ifdef CONFIG_HAS_EARLYSUSPEND | |
+ struct early_suspend early_suspend; | |
+#endif | |
+ atomic_t cached_match_val; | |
}; | |
+static inline unsigned int get_match_val(unsigned char index) | |
+{ | |
+ return match_data[index]; | |
+} | |
+ | |
static inline struct omap_pwm_led *pdev_to_omap_pwm_led(struct platform_device *pdev) | |
{ | |
return platform_get_drvdata(pdev); | |
@@ -47,8 +69,18 @@ static inline struct omap_pwm_led *cdev_to_omap_pwm_led(struct led_classdev *led | |
return container_of(led_cdev, struct omap_pwm_led, cdev); | |
} | |
+static inline struct omap_pwm_led *work_to_omap_pwm_led(struct work_struct *work) | |
+{ | |
+ return container_of(work, struct omap_pwm_led, work); | |
+} | |
+ | |
static void omap_pwm_led_set_blink(struct omap_pwm_led *led) | |
{ | |
+ int invert = 1; | |
+ | |
+ if (led->pdata) | |
+ invert = led->pdata->invert; | |
+ | |
if (!led->powered) | |
return; | |
@@ -56,136 +88,181 @@ static void omap_pwm_led_set_blink(struct omap_pwm_led *led) | |
unsigned long load_reg, cmp_reg; | |
load_reg = 32768 * (led->on_period + led->off_period) / 1000; | |
- cmp_reg = 32768 * (led->on_period) / 1000; | |
+ cmp_reg = 32768 * led->on_period / 1000; | |
omap_dm_timer_stop(led->blink_timer); | |
omap_dm_timer_set_load(led->blink_timer, 1, -load_reg); | |
omap_dm_timer_set_match(led->blink_timer, 1, -cmp_reg); | |
- omap_dm_timer_set_pwm(led->blink_timer, 1, 1, | |
+ omap_dm_timer_set_pwm(led->blink_timer, | |
+ invert, 1, | |
OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); | |
omap_dm_timer_write_counter(led->blink_timer, -2); | |
omap_dm_timer_start(led->blink_timer); | |
} else { | |
- omap_dm_timer_set_pwm(led->blink_timer, 1, 1, | |
+ omap_dm_timer_set_pwm(led->blink_timer, | |
+ invert, 1, | |
OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); | |
omap_dm_timer_stop(led->blink_timer); | |
} | |
} | |
-static void omap_pwm_led_pad_enable(struct omap_pwm_led *led) | |
+static inline void omap_pwm_set_match(struct omap_dm_timer *timer, | |
+ unsigned int val) | |
{ | |
- if (led->pdata->set_pad) | |
- led->pdata->set_pad(led->pdata, 1); | |
+ omap_dm_timer_set_match(timer, 1, val); | |
+ omap_dm_timer_set_int_disable(timer, TIMER_INT_FLAGS); | |
} | |
-static void omap_pwm_led_pad_disable(struct omap_pwm_led *led) | |
+static irqreturn_t intensity_timer_match_interrupt(int irq, void *arg) | |
{ | |
- if (led->pdata->set_pad) | |
- led->pdata->set_pad(led->pdata, 0); | |
+ struct omap_pwm_led *led; | |
+ struct omap_dm_timer *timer; | |
+ unsigned int counter; | |
+ unsigned int match_val; | |
+ unsigned int current_match_val; | |
+ unsigned int status; | |
+ | |
+ led = (struct omap_pwm_led *) arg; | |
+ timer = (struct omap_dm_timer *) led->intensity_timer; | |
+ match_val = atomic_read(&led->cached_match_val); | |
+ | |
+ /* disable interrupts */ | |
+ local_irq_disable(); | |
+ | |
+ /* get int status */ | |
+ status = omap_dm_timer_read_status(timer); | |
+ | |
+ /* get current match value */ | |
+ current_match_val = omap_dm_timer_get_match(timer); | |
+ | |
+ /* We must update match register only in case: | |
+ * - new match value is bigger than old one | |
+ * - when old match value is bigger than new one, current | |
+ * counter value must be bigger than old match value or | |
+ * lower than new match value. | |
+ * | |
+ * If this conditions are not met, we will write a match value, | |
+ * at moment when match event doesn't trigered yet and the new | |
+ * match value is lower than counter. This will result in missing | |
+ * the match event for this period. | |
+ */ | |
+ counter = omap_dm_timer_read_counter(timer); | |
+ | |
+ if ((counter + COUNTER_TO_MATCH_GUARD) < match_val) | |
+ omap_pwm_set_match(timer, match_val); | |
+ else if (counter > current_match_val) | |
+ omap_pwm_set_match(timer, match_val); | |
+ | |
+ /* acknowledge interrupts */ | |
+ omap_dm_timer_write_status(timer, status); | |
+ | |
+ /* enable interrupts */ | |
+ local_irq_enable(); | |
+ | |
+ return IRQ_HANDLED; | |
} | |
-static void omap_pwm_led_power_on(struct omap_pwm_led *led) | |
+static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle) | |
{ | |
- u32 val; | |
- u32 period; | |
- struct clk *timer_fclk; | |
- pr_debug("%s: start \n",__func__); | |
- if (led->powered) | |
- return; | |
- led->powered = 1; | |
+ struct omap_dm_timer *timer; | |
+ unsigned int match_val; | |
+ unsigned int current_match_val; | |
- pr_debug("%s: brightness: %i\n", | |
- __func__, led->brightness); | |
+ timer = (struct omap_dm_timer *) led->intensity_timer; | |
- /* Select clock */ | |
- omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_SYS_CLK); | |
- | |
- /* Turn voltage on */ | |
- if (led->pdata->set_power != NULL) | |
- led->pdata->set_power(led->pdata, 1); | |
+ current_match_val = atomic_read(&led->cached_match_val); | |
+ match_val = get_match_val(cycle); | |
- /* explicitly enable the timer, saves some SAR later */ | |
- omap_dm_timer_enable(led->intensity_timer); | |
- omap_dm_timer_start(led->intensity_timer); | |
+ if (current_match_val < match_val) { | |
+ omap_dm_timer_set_match(timer, 1, match_val); | |
+ atomic_set(&led->cached_match_val, match_val); | |
+ } else { | |
+ atomic_set(&led->cached_match_val, match_val); | |
+ omap_dm_timer_set_int_enable(timer, TIMER_INT_FLAGS); | |
+ } | |
+} | |
- omap_dm_timer_set_pwm(led->intensity_timer, led->pdata->invert ? 1 : 0, 1, | |
- OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); | |
+static void omap_pwm_led_power_on(struct omap_pwm_led *led) | |
+{ | |
+ int invert = 1; | |
+ unsigned int timerval; | |
+ int err; | |
- timer_fclk = omap_dm_timer_get_fclk(led->intensity_timer); | |
- period = clk_get_rate(timer_fclk) / 128; | |
+ if (led->pdata) | |
+ invert = led->pdata->invert; | |
- val = 0xFFFFFFFF+1-period; | |
- omap_dm_timer_set_load(led->intensity_timer, 1, val); | |
+ if (led->powered) | |
+ return; | |
+ led->powered = 1; | |
+ /* Select clock source */ | |
+ omap_dm_timer_enable(led->intensity_timer); | |
+ omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_SYS_CLK); | |
+ omap_dm_timer_set_prescaler(led->intensity_timer, COUNTER_DEVIDER); | |
/* Enable PWM timers */ | |
if (led->blink_timer != NULL) { | |
+ omap_dm_timer_enable(led->blink_timer); | |
omap_dm_timer_set_source(led->blink_timer, | |
OMAP_TIMER_SRC_32_KHZ); | |
omap_pwm_led_set_blink(led); | |
} | |
- pr_debug("%s: end \n",__func__); | |
+ | |
+ omap_dm_timer_set_pwm(led->intensity_timer, invert ? 0 : 1, 1, | |
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); | |
+ | |
+ omap_dm_timer_set_load(led->intensity_timer, 1, COUNTER_LOAD_VAL); | |
+ omap_dm_timer_start(led->intensity_timer); | |
+ omap_pwm_led_set_pwm_cycle(led, 0); | |
+ | |
+ timerval = omap_dm_timer_read_counter(led->intensity_timer); | |
+ if (timerval < COUNTER_LOAD_VAL) | |
+ omap_dm_timer_write_counter(led->intensity_timer, -2); | |
+ | |
+ /* Turn voltage on */ | |
+ if (led->pdata->set_power != NULL) | |
+ led->pdata->set_power(led->pdata, 1); | |
+ | |
+ /* register timer match and overflow interrupts */ | |
+ err = request_irq(omap_dm_timer_get_irq(led->intensity_timer), | |
+ intensity_timer_match_interrupt, | |
+ IRQF_DISABLED, "led intensity timer", (void *)led); | |
+ if (err) { | |
+ printk(KERN_ERR "%s(%s) : unable to get gptimer%d IRQ\n", | |
+ __func__, __FILE__, led->pdata->intensity_timer); | |
+ } | |
} | |
static void omap_pwm_led_power_off(struct omap_pwm_led *led) | |
{ | |
- | |
+ int invert = 1; | |
if (!led->powered) | |
return; | |
led->powered = 0; | |
- pr_debug("%s: brightness: %i\n", | |
- __func__, led->brightness); | |
- | |
if (led->pdata->set_power != NULL) | |
led->pdata->set_power(led->pdata, 0); | |
+ /* disable timer match interrupt */ | |
+ omap_dm_timer_set_int_disable(led->intensity_timer, | |
+ OMAP_TIMER_INT_MATCH); | |
+ free_irq(omap_dm_timer_get_irq(led->intensity_timer), (void *)led); | |
+ if (led->pdata) | |
+ invert = led->pdata->invert; | |
+ | |
/* Everything off */ | |
+ omap_dm_timer_set_pwm(led->intensity_timer, | |
+ invert ? 0 : 1, 1, | |
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); | |
omap_dm_timer_stop(led->intensity_timer); | |
+ omap_dm_timer_disable(led->intensity_timer); | |
- if (led->blink_timer != NULL) | |
+ if (led->blink_timer != NULL) { | |
omap_dm_timer_stop(led->blink_timer); | |
- pr_debug("%s: end \n",__func__); | |
-} | |
- | |
-static void pwm_set_speed(struct omap_dm_timer *gpt, | |
- int frequency, int duty_cycle) | |
-{ | |
- u32 val; | |
- u32 period; | |
- struct clk *timer_fclk; | |
- | |
- /* and you will have an overflow in 1 sec */ | |
- /* so, */ | |
- /* freq_timer -> 1s */ | |
- /* carrier_period -> 1/carrier_freq */ | |
- /* => carrier_period = freq_timer/carrier_freq */ | |
- | |
- timer_fclk = omap_dm_timer_get_fclk(gpt); | |
- period = clk_get_rate(timer_fclk) / frequency; | |
- | |
- val = 0xFFFFFFFF+1-(period*duty_cycle/256); | |
- omap_dm_timer_set_match(gpt, 1, val); | |
-} | |
- | |
-static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle) | |
-{ | |
- int pwm_frequency = 10000; | |
- | |
- pr_debug("%s: cycle: %i\n", | |
- __func__, cycle); | |
- | |
- if (led->pdata->bkl_max) | |
- cycle = ( (cycle * led->pdata->bkl_max ) / 255); | |
- | |
- if (cycle < led->pdata->bkl_min) | |
- cycle = led->pdata->bkl_min; | |
- | |
- if (led->pdata->bkl_freq) | |
- pwm_frequency = led->pdata->bkl_freq; | |
+ omap_dm_timer_disable(led->blink_timer); | |
+ } | |
- if (cycle != LED_FULL) | |
- pwm_set_speed(led->intensity_timer, pwm_frequency, 256-cycle); | |
+ atomic_set(&led->cached_match_val, 0); | |
} | |
static void omap_pwm_led_set(struct led_classdev *led_cdev, | |
@@ -193,29 +270,22 @@ static void omap_pwm_led_set(struct led_classdev *led_cdev, | |
{ | |
struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev); | |
- pr_debug("%s: brightness: %i\n", __func__, value); | |
- | |
- if (led->brightness != value) { | |
- if (led->brightness < led->pdata->bkl_min || | |
- led_cdev->flags & LED_SUSPENDED) { | |
- /* LED currently OFF */ | |
- if (value >= led->pdata->bkl_min) { | |
- omap_pwm_led_power_on(led); | |
- omap_pwm_led_set_pwm_cycle(led, value); | |
- omap_pwm_led_pad_enable(led); | |
- } | |
- } else { | |
- /* just set the new cycle */ | |
- omap_pwm_led_set_pwm_cycle(led, value); | |
- } | |
- | |
- if (value < led->pdata->bkl_min && led->brightness >= led->pdata->bkl_min) { | |
- /* LED now suspended */ | |
- omap_pwm_led_pad_disable(led); | |
- // omap_pwm_led_set_pwm_cycle(led, value); | |
- omap_pwm_led_power_off(led); | |
- } | |
+ if (value != led->brightness) { | |
led->brightness = value; | |
+ schedule_work(&led->work); | |
+ } | |
+} | |
+ | |
+static void omap_pwm_led_work(struct work_struct *work) | |
+{ | |
+ struct omap_pwm_led *led = work_to_omap_pwm_led(work); | |
+ | |
+ if (led->brightness != LED_OFF) { | |
+ omap_pwm_led_power_on(led); | |
+ omap_pwm_led_set_pwm_cycle(led, led->brightness); | |
+ } else { | |
+ omap_pwm_led_set_pwm_cycle(led, led->brightness); | |
+ omap_pwm_led_power_off(led); | |
} | |
} | |
@@ -298,12 +368,6 @@ static int omap_pwm_led_probe(struct platform_device *pdev) | |
struct omap_pwm_led *led; | |
int ret; | |
- if (pdata->intensity_timer < 1 || pdata->intensity_timer > MAX_GPTIMER_ID) | |
- return -EINVAL; | |
- | |
- if (pdata->blink_timer != 0 || pdata->blink_timer > MAX_GPTIMER_ID) | |
- return -EINVAL; | |
- | |
led = kzalloc(sizeof(struct omap_pwm_led), GFP_KERNEL); | |
if (led == NULL) { | |
dev_err(&pdev->dev, "No memory for device\n"); | |
@@ -312,14 +376,18 @@ static int omap_pwm_led_probe(struct platform_device *pdev) | |
platform_set_drvdata(pdev, led); | |
led->cdev.brightness_set = omap_pwm_led_set; | |
- led->cdev.default_trigger = pdata->default_trigger; | |
+ led->cdev.default_trigger = NULL; | |
led->cdev.name = pdata->name; | |
led->pdata = pdata; | |
- led->brightness = LED_OFF; | |
+ led->brightness = pdata->def_brightness; | |
+ INIT_WORK(&led->work, omap_pwm_led_work); | |
dev_info(&pdev->dev, "OMAP PWM LED (%s) at GP timer %d/%d\n", | |
pdata->name, pdata->intensity_timer, pdata->blink_timer); | |
+ if (pdata->def_brightness) | |
+ led->cdev.brightness = pdata->def_brightness; | |
+ | |
/* register our new led device */ | |
ret = led_classdev_register(&pdev->dev, &led->cdev); | |
if (ret < 0) { | |
@@ -334,33 +402,42 @@ static int omap_pwm_led_probe(struct platform_device *pdev) | |
ret = -ENODEV; | |
goto error_intensity; | |
} | |
- | |
- if (led->pdata->invert) | |
- omap_dm_timer_set_pwm(led->intensity_timer, 1, 1, | |
- OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); | |
+ omap_dm_timer_disable(led->intensity_timer); | |
if (pdata->blink_timer != 0) { | |
led->blink_timer = omap_dm_timer_request_specific(pdata->blink_timer); | |
if (led->blink_timer == NULL) { | |
- dev_err(&pdev->dev, "failed to request blinking pwm timer\n"); | |
+ dev_err(&pdev->dev, | |
+ "failed to request blinking pwm timer\n"); | |
ret = -ENODEV; | |
goto error_blink1; | |
} | |
+ omap_dm_timer_disable(led->blink_timer); | |
+ | |
ret = device_create_file(led->cdev.dev, | |
&dev_attr_on_period); | |
- if(ret) | |
+ if (ret) | |
goto error_blink2; | |
ret = device_create_file(led->cdev.dev, | |
&dev_attr_off_period); | |
- if(ret) | |
+ if (ret) | |
goto error_blink3; | |
} | |
+ if (led->brightness) { | |
+ schedule_work(&led->work); | |
+ } else { | |
+ omap_pwm_led_power_on(led); | |
+ omap_pwm_led_power_off(led); | |
+ } | |
- if(pdata->def_brightness) | |
- omap_pwm_led_set(&led->cdev, pdata->def_brightness); | |
- | |
+#ifdef CONFIG_HAS_EARLYSUSPEND | |
+ led->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1; | |
+ led->early_suspend.suspend = omap_pwm_led_early_suspend; | |
+ led->early_suspend.resume = omap_pwm_led_late_resume; | |
+ register_early_suspend(&led->early_suspend); | |
+#endif | |
return 0; | |
error_blink3: | |
@@ -379,8 +456,13 @@ error_classdev: | |
static int omap_pwm_led_remove(struct platform_device *pdev) | |
{ | |
+ | |
struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev); | |
+#ifdef CONFIG_HAS_EARLYSUSPEND | |
+ unregister_early_suspend(&led->early_suspend); | |
+#endif | |
+ | |
device_remove_file(led->cdev.dev, | |
&dev_attr_on_period); | |
device_remove_file(led->cdev.dev, | |
@@ -396,13 +478,36 @@ static int omap_pwm_led_remove(struct platform_device *pdev) | |
return 0; | |
} | |
-#ifdef CONFIG_PM | |
-static int omap_pwm_led_suspend(struct platform_device *pdev, pm_message_t state) | |
+#ifdef CONFIG_HAS_EARLYSUSPEND | |
+static void omap_pwm_led_early_suspend(struct early_suspend *handler) | |
+{ | |
+ struct omap_pwm_led *led; | |
+ | |
+ led = container_of(handler, struct omap_pwm_led, early_suspend); | |
+ | |
+ flush_work(&led->work); | |
+ /* Make sure the led is switched OFF NOW in this current thread!!! */ | |
+ omap_pwm_led_power_off(led); | |
+ | |
+ led_classdev_suspend(&led->cdev); | |
+} | |
+ | |
+static void omap_pwm_led_late_resume(struct early_suspend *handler) | |
+{ | |
+ struct omap_pwm_led *led; | |
+ | |
+ led = container_of(handler, struct omap_pwm_led, early_suspend); | |
+ | |
+ led_classdev_resume(&led->cdev); | |
+} | |
+#endif | |
+ | |
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) | |
+static int omap_pwm_led_suspend(struct platform_device *pdev, | |
+ pm_message_t state) | |
{ | |
struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev); | |
- pr_debug("%s: brightness: %i\n", __func__, | |
- led->brightness); | |
led_classdev_suspend(&led->cdev); | |
return 0; | |
} | |
@@ -411,8 +516,6 @@ static int omap_pwm_led_resume(struct platform_device *pdev) | |
{ | |
struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev); | |
- pr_debug("%s: brightness: %i\n", __func__, | |
- led->brightness); | |
led_classdev_resume(&led->cdev); | |
return 0; | |
} | |
@@ -424,8 +527,10 @@ static int omap_pwm_led_resume(struct platform_device *pdev) | |
static struct platform_driver omap_pwm_led_driver = { | |
.probe = omap_pwm_led_probe, | |
.remove = omap_pwm_led_remove, | |
+#ifndef CONFIG_HAS_EARLYSUSPEND | |
.suspend = omap_pwm_led_suspend, | |
.resume = omap_pwm_led_resume, | |
+#endif | |
.driver = { | |
.name = "omap_pwm_led", | |
.owner = THIS_MODULE, | |
(END) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment