diff options
Diffstat (limited to 'drivers/video/backlight/lcd.c')
| -rw-r--r-- | drivers/video/backlight/lcd.c | 167 |
1 files changed, 77 insertions, 90 deletions
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 41964a71a036..affe5c52471a 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LCD Lowlevel Control Abstraction * @@ -14,82 +15,61 @@ #include <linux/notifier.h> #include <linux/ctype.h> #include <linux/err.h> -#include <linux/fb.h> #include <linux/slab.h> -#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ - defined(CONFIG_LCD_CLASS_DEVICE_MODULE)) -/* This callback gets called when something important happens inside a - * framebuffer driver. We're looking if that important event is blanking, - * and if it is, we're switching lcd power as well ... - */ -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) +static DEFINE_MUTEX(lcd_dev_list_mutex); +static LIST_HEAD(lcd_dev_list); + +static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev, + int power) { - struct lcd_device *ld; - struct fb_event *evdata = data; - - /* If we aren't interested in this event, skip it immediately ... */ - switch (event) { - case FB_EVENT_BLANK: - case FB_EVENT_MODE_CHANGE: - case FB_EVENT_MODE_CHANGE_ALL: - case FB_EARLY_EVENT_BLANK: - case FB_R_EARLY_EVENT_BLANK: - break; - default: - return 0; - } + guard(mutex)(&ld->ops_lock); - ld = container_of(self, struct lcd_device, fb_notif); - if (!ld->ops) - return 0; + if (!ld->ops || !ld->ops->set_power) + return; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev)) + return; - mutex_lock(&ld->ops_lock); - if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { - if (event == FB_EVENT_BLANK) { - if (ld->ops->set_power) - ld->ops->set_power(ld, *(int *)evdata->data); - } else if (event == FB_EARLY_EVENT_BLANK) { - if (ld->ops->early_set_power) - ld->ops->early_set_power(ld, - *(int *)evdata->data); - } else if (event == FB_R_EARLY_EVENT_BLANK) { - if (ld->ops->r_early_set_power) - ld->ops->r_early_set_power(ld, - *(int *)evdata->data); - } else { - if (ld->ops->set_mode) - ld->ops->set_mode(ld, evdata->data); - } - } - mutex_unlock(&ld->ops_lock); - return 0; + ld->ops->set_power(ld, power); } -static int lcd_register_fb(struct lcd_device *ld) +void lcd_notify_blank_all(struct device *display_dev, int power) { - memset(&ld->fb_notif, 0, sizeof(ld->fb_notif)); - ld->fb_notif.notifier_call = fb_notifier_callback; - return fb_register_client(&ld->fb_notif); -} + struct lcd_device *ld; -static void lcd_unregister_fb(struct lcd_device *ld) -{ - fb_unregister_client(&ld->fb_notif); + guard(mutex)(&lcd_dev_list_mutex); + + list_for_each_entry(ld, &lcd_dev_list, entry) + lcd_notify_blank(ld, display_dev, power); } -#else -static int lcd_register_fb(struct lcd_device *ld) +EXPORT_SYMBOL(lcd_notify_blank_all); + +static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev, + unsigned int width, unsigned int height) { - return 0; + guard(mutex)(&ld->ops_lock); + + if (!ld->ops || !ld->ops->set_mode) + return; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev)) + return; + + ld->ops->set_mode(ld, width, height); } -static inline void lcd_unregister_fb(struct lcd_device *ld) +void lcd_notify_mode_change_all(struct device *display_dev, + unsigned int width, unsigned int height) { + struct lcd_device *ld; + + guard(mutex)(&lcd_dev_list_mutex); + + list_for_each_entry(ld, &lcd_dev_list, entry) + lcd_notify_mode_change(ld, display_dev, width, height); } -#endif /* CONFIG_FB */ +EXPORT_SYMBOL(lcd_notify_mode_change_all); -static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr, +static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc; @@ -105,7 +85,7 @@ static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr, return rc; } -static ssize_t lcd_store_power(struct device *dev, +static ssize_t lcd_power_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc; @@ -128,8 +108,9 @@ static ssize_t lcd_store_power(struct device *dev, return rc; } +static DEVICE_ATTR_RW(lcd_power); -static ssize_t lcd_show_contrast(struct device *dev, +static ssize_t contrast_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc = -ENXIO; @@ -143,7 +124,7 @@ static ssize_t lcd_show_contrast(struct device *dev, return rc; } -static ssize_t lcd_store_contrast(struct device *dev, +static ssize_t contrast_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc; @@ -166,16 +147,16 @@ static ssize_t lcd_store_contrast(struct device *dev, return rc; } +static DEVICE_ATTR_RW(contrast); -static ssize_t lcd_show_max_contrast(struct device *dev, +static ssize_t max_contrast_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lcd_device *ld = to_lcd_device(dev); return sprintf(buf, "%d\n", ld->props.max_contrast); } - -static struct class *lcd_class; +static DEVICE_ATTR_RO(max_contrast); static void lcd_device_release(struct device *dev) { @@ -183,17 +164,24 @@ static void lcd_device_release(struct device *dev) kfree(ld); } -static struct device_attribute lcd_device_attributes[] = { - __ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power), - __ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast), - __ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL), - __ATTR_NULL, +static struct attribute *lcd_device_attrs[] = { + &dev_attr_lcd_power.attr, + &dev_attr_contrast.attr, + &dev_attr_max_contrast.attr, + NULL, +}; +ATTRIBUTE_GROUPS(lcd_device); + +static const struct class lcd_class = { + .name = "lcd", + .dev_groups = lcd_device_groups, }; /** * lcd_device_register - register a new object of lcd_device class. * @name: the name of the new object(must be the same as the name of the * respective framebuffer device). + * @parent: pointer to the parent's struct device . * @devdata: an optional pointer to be stored in the device. The * methods may retrieve it by using lcd_get_data(ld). * @ops: the lcd operations structure. @@ -202,7 +190,7 @@ static struct device_attribute lcd_device_attributes[] = { * or a pointer to the newly allocated device. */ struct lcd_device *lcd_device_register(const char *name, struct device *parent, - void *devdata, struct lcd_ops *ops) + void *devdata, const struct lcd_ops *ops) { struct lcd_device *new_ld; int rc; @@ -216,25 +204,22 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent, mutex_init(&new_ld->ops_lock); mutex_init(&new_ld->update_lock); - new_ld->dev.class = lcd_class; + new_ld->dev.class = &lcd_class; new_ld->dev.parent = parent; new_ld->dev.release = lcd_device_release; dev_set_name(&new_ld->dev, "%s", name); dev_set_drvdata(&new_ld->dev, devdata); - rc = device_register(&new_ld->dev); - if (rc) { - kfree(new_ld); - return ERR_PTR(rc); - } + new_ld->ops = ops; - rc = lcd_register_fb(new_ld); + rc = device_register(&new_ld->dev); if (rc) { - device_unregister(&new_ld->dev); + put_device(&new_ld->dev); return ERR_PTR(rc); } - new_ld->ops = ops; + guard(mutex)(&lcd_dev_list_mutex); + list_add(&new_ld->entry, &lcd_dev_list); return new_ld; } @@ -251,10 +236,12 @@ void lcd_device_unregister(struct lcd_device *ld) if (!ld) return; + guard(mutex)(&lcd_dev_list_mutex); + list_del(&ld->entry); + mutex_lock(&ld->ops_lock); ld->ops = NULL; mutex_unlock(&ld->ops_lock); - lcd_unregister_fb(ld); device_unregister(&ld->dev); } @@ -290,7 +277,7 @@ static int devm_lcd_device_match(struct device *dev, void *res, void *data) */ struct lcd_device *devm_lcd_device_register(struct device *dev, const char *name, struct device *parent, - void *devdata, struct lcd_ops *ops) + void *devdata, const struct lcd_ops *ops) { struct lcd_device **ptr, *lcd; @@ -332,19 +319,19 @@ EXPORT_SYMBOL(devm_lcd_device_unregister); static void __exit lcd_class_exit(void) { - class_destroy(lcd_class); + class_unregister(&lcd_class); } static int __init lcd_class_init(void) { - lcd_class = class_create(THIS_MODULE, "lcd"); - if (IS_ERR(lcd_class)) { - pr_warn("Unable to create backlight class; errno = %ld\n", - PTR_ERR(lcd_class)); - return PTR_ERR(lcd_class); + int ret; + + ret = class_register(&lcd_class); + if (ret) { + pr_warn("Unable to create backlight class; errno = %d\n", ret); + return ret; } - lcd_class->dev_attrs = lcd_device_attributes; return 0; } |
