summaryrefslogtreecommitdiff
path: root/drivers/video/backlight/lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/backlight/lcd.c')
-rw-r--r--drivers/video/backlight/lcd.c167
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;
}