mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
d54ad83f3d
This patchset adds early fb blank feature that a callback of lcd panel driver is called prior to specific fb driver's one. In the case of MIPI-DSI based video mode LCD Panel, for lcd power off, the power off commands should be transferred to lcd panel with display and mipi-dsi controller enabled because the commands is set to lcd panel at vsync porch period. and in opposite case, the callback of fb driver should be called prior to lcd panel driver's one because of same issue. Also if fb_blank mode is changed to FB_BLANK_POWERDOWN then display controller would be off(clock disable) but lcd panel would be still on. at this time, you could see some issue like sparkling on lcd panel because video clock to be delivered to ldi module of lcd panel was disabled. this issue could occurs for all lcd panels. The callback order is as the following: at fb_blank function of fbmem.c -> fb_notifier_call_chain(FB_EARLY_EVENT_BLANK) -> lcd panel driver's early_set_power() -> info->fbops->fb_blank() -> spcefic fb driver's fb_blank() -> fb_notifier_call_chain(FB_EVENT_BLANK) -> lcd panel driver's set_power() -> fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK) if info->fops->fb_blank() was failed. fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK) would be called to revert the effects of previous FB_EARLY_EVENT_BLANK call. and note that if early_set_power() of lcd_ops is NULL then early fb blank callback would be ignored. This patch: Add early_set_power and r_early_set_power callbacks. early_set_power callback is called prior to fb_blank() of fbmem.c and r_early_set_power callback is called if fb_blank() was failed to revert the effects of the early_set_power call of lcd panel driver. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Cc: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
125 lines
3.9 KiB
C
125 lines
3.9 KiB
C
/*
|
|
* LCD Lowlevel Control Abstraction
|
|
*
|
|
* Copyright (C) 2003,2004 Hewlett-Packard Company
|
|
*
|
|
*/
|
|
|
|
#ifndef _LINUX_LCD_H
|
|
#define _LINUX_LCD_H
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/fb.h>
|
|
|
|
/* Notes on locking:
|
|
*
|
|
* lcd_device->ops_lock is an internal backlight lock protecting the ops
|
|
* field and no code outside the core should need to touch it.
|
|
*
|
|
* Access to set_power() is serialised by the update_lock mutex since
|
|
* most drivers seem to need this and historically get it wrong.
|
|
*
|
|
* Most drivers don't need locking on their get_power() method.
|
|
* If yours does, you need to implement it in the driver. You can use the
|
|
* update_lock mutex if appropriate.
|
|
*
|
|
* Any other use of the locks below is probably wrong.
|
|
*/
|
|
|
|
struct lcd_device;
|
|
struct fb_info;
|
|
|
|
struct lcd_properties {
|
|
/* The maximum value for contrast (read-only) */
|
|
int max_contrast;
|
|
};
|
|
|
|
struct lcd_ops {
|
|
/* Get the LCD panel power status (0: full on, 1..3: controller
|
|
power on, flat panel power off, 4: full off), see FB_BLANK_XXX */
|
|
int (*get_power)(struct lcd_device *);
|
|
/*
|
|
* Enable or disable power to the LCD(0: on; 4: off, see FB_BLANK_XXX)
|
|
* and this callback would be called proir to fb driver's callback.
|
|
*
|
|
* P.S. note that if early_set_power is not NULL then early fb notifier
|
|
* would be registered.
|
|
*/
|
|
int (*early_set_power)(struct lcd_device *, int power);
|
|
/* revert the effects of the early blank event. */
|
|
int (*r_early_set_power)(struct lcd_device *, int power);
|
|
/* Enable or disable power to the LCD (0: on; 4: off, see FB_BLANK_XXX) */
|
|
int (*set_power)(struct lcd_device *, int power);
|
|
/* Get the current contrast setting (0-max_contrast) */
|
|
int (*get_contrast)(struct lcd_device *);
|
|
/* Set LCD panel contrast */
|
|
int (*set_contrast)(struct lcd_device *, int contrast);
|
|
/* Set LCD panel mode (resolutions ...) */
|
|
int (*set_mode)(struct lcd_device *, struct fb_videomode *);
|
|
/* Check if given framebuffer device is the one LCD is bound to;
|
|
return 0 if not, !=0 if it is. If NULL, lcd always matches the fb. */
|
|
int (*check_fb)(struct lcd_device *, struct fb_info *);
|
|
};
|
|
|
|
struct lcd_device {
|
|
struct lcd_properties props;
|
|
/* This protects the 'ops' field. If 'ops' is NULL, the driver that
|
|
registered this device has been unloaded, and if class_get_devdata()
|
|
points to something in the body of that driver, it is also invalid. */
|
|
struct mutex ops_lock;
|
|
/* If this is NULL, the backing module is unloaded */
|
|
struct lcd_ops *ops;
|
|
/* Serialise access to set_power method */
|
|
struct mutex update_lock;
|
|
/* The framebuffer notifier block */
|
|
struct notifier_block fb_notif;
|
|
|
|
struct device dev;
|
|
};
|
|
|
|
struct lcd_platform_data {
|
|
/* reset lcd panel device. */
|
|
int (*reset)(struct lcd_device *ld);
|
|
/* on or off to lcd panel. if 'enable' is 0 then
|
|
lcd power off and 1, lcd power on. */
|
|
int (*power_on)(struct lcd_device *ld, int enable);
|
|
|
|
/* it indicates whether lcd panel was enabled
|
|
from bootloader or not. */
|
|
int lcd_enabled;
|
|
/* it means delay for stable time when it becomes low to high
|
|
or high to low that is dependent on whether reset gpio is
|
|
low active or high active. */
|
|
unsigned int reset_delay;
|
|
/* stable time needing to become lcd power on. */
|
|
unsigned int power_on_delay;
|
|
/* stable time needing to become lcd power off. */
|
|
unsigned int power_off_delay;
|
|
|
|
/* it could be used for any purpose. */
|
|
void *pdata;
|
|
};
|
|
|
|
static inline void lcd_set_power(struct lcd_device *ld, int power)
|
|
{
|
|
mutex_lock(&ld->update_lock);
|
|
if (ld->ops && ld->ops->set_power)
|
|
ld->ops->set_power(ld, power);
|
|
mutex_unlock(&ld->update_lock);
|
|
}
|
|
|
|
extern struct lcd_device *lcd_device_register(const char *name,
|
|
struct device *parent, void *devdata, struct lcd_ops *ops);
|
|
extern void lcd_device_unregister(struct lcd_device *ld);
|
|
|
|
#define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
|
|
|
|
static inline void * lcd_get_data(struct lcd_device *ld_dev)
|
|
{
|
|
return dev_get_drvdata(&ld_dev->dev);
|
|
}
|
|
|
|
|
|
#endif
|