Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * LCD Lowlevel Control Abstraction
0004  *
0005  * Copyright (C) 2003,2004 Hewlett-Packard Company
0006  *
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/device.h>
0014 #include <linux/lcd.h>
0015 #include <linux/notifier.h>
0016 #include <linux/ctype.h>
0017 #include <linux/err.h>
0018 #include <linux/fb.h>
0019 #include <linux/slab.h>
0020 
0021 #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
0022                defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
0023 /* This callback gets called when something important happens inside a
0024  * framebuffer driver. We're looking if that important event is blanking,
0025  * and if it is, we're switching lcd power as well ...
0026  */
0027 static int fb_notifier_callback(struct notifier_block *self,
0028                  unsigned long event, void *data)
0029 {
0030     struct lcd_device *ld;
0031     struct fb_event *evdata = data;
0032 
0033     ld = container_of(self, struct lcd_device, fb_notif);
0034     if (!ld->ops)
0035         return 0;
0036 
0037     mutex_lock(&ld->ops_lock);
0038     if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
0039         if (event == FB_EVENT_BLANK) {
0040             if (ld->ops->set_power)
0041                 ld->ops->set_power(ld, *(int *)evdata->data);
0042         } else {
0043             if (ld->ops->set_mode)
0044                 ld->ops->set_mode(ld, evdata->data);
0045         }
0046     }
0047     mutex_unlock(&ld->ops_lock);
0048     return 0;
0049 }
0050 
0051 static int lcd_register_fb(struct lcd_device *ld)
0052 {
0053     memset(&ld->fb_notif, 0, sizeof(ld->fb_notif));
0054     ld->fb_notif.notifier_call = fb_notifier_callback;
0055     return fb_register_client(&ld->fb_notif);
0056 }
0057 
0058 static void lcd_unregister_fb(struct lcd_device *ld)
0059 {
0060     fb_unregister_client(&ld->fb_notif);
0061 }
0062 #else
0063 static int lcd_register_fb(struct lcd_device *ld)
0064 {
0065     return 0;
0066 }
0067 
0068 static inline void lcd_unregister_fb(struct lcd_device *ld)
0069 {
0070 }
0071 #endif /* CONFIG_FB */
0072 
0073 static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr,
0074         char *buf)
0075 {
0076     int rc;
0077     struct lcd_device *ld = to_lcd_device(dev);
0078 
0079     mutex_lock(&ld->ops_lock);
0080     if (ld->ops && ld->ops->get_power)
0081         rc = sprintf(buf, "%d\n", ld->ops->get_power(ld));
0082     else
0083         rc = -ENXIO;
0084     mutex_unlock(&ld->ops_lock);
0085 
0086     return rc;
0087 }
0088 
0089 static ssize_t lcd_power_store(struct device *dev,
0090         struct device_attribute *attr, const char *buf, size_t count)
0091 {
0092     int rc;
0093     struct lcd_device *ld = to_lcd_device(dev);
0094     unsigned long power;
0095 
0096     rc = kstrtoul(buf, 0, &power);
0097     if (rc)
0098         return rc;
0099 
0100     rc = -ENXIO;
0101 
0102     mutex_lock(&ld->ops_lock);
0103     if (ld->ops && ld->ops->set_power) {
0104         pr_debug("set power to %lu\n", power);
0105         ld->ops->set_power(ld, power);
0106         rc = count;
0107     }
0108     mutex_unlock(&ld->ops_lock);
0109 
0110     return rc;
0111 }
0112 static DEVICE_ATTR_RW(lcd_power);
0113 
0114 static ssize_t contrast_show(struct device *dev,
0115         struct device_attribute *attr, char *buf)
0116 {
0117     int rc = -ENXIO;
0118     struct lcd_device *ld = to_lcd_device(dev);
0119 
0120     mutex_lock(&ld->ops_lock);
0121     if (ld->ops && ld->ops->get_contrast)
0122         rc = sprintf(buf, "%d\n", ld->ops->get_contrast(ld));
0123     mutex_unlock(&ld->ops_lock);
0124 
0125     return rc;
0126 }
0127 
0128 static ssize_t contrast_store(struct device *dev,
0129         struct device_attribute *attr, const char *buf, size_t count)
0130 {
0131     int rc;
0132     struct lcd_device *ld = to_lcd_device(dev);
0133     unsigned long contrast;
0134 
0135     rc = kstrtoul(buf, 0, &contrast);
0136     if (rc)
0137         return rc;
0138 
0139     rc = -ENXIO;
0140 
0141     mutex_lock(&ld->ops_lock);
0142     if (ld->ops && ld->ops->set_contrast) {
0143         pr_debug("set contrast to %lu\n", contrast);
0144         ld->ops->set_contrast(ld, contrast);
0145         rc = count;
0146     }
0147     mutex_unlock(&ld->ops_lock);
0148 
0149     return rc;
0150 }
0151 static DEVICE_ATTR_RW(contrast);
0152 
0153 static ssize_t max_contrast_show(struct device *dev,
0154         struct device_attribute *attr, char *buf)
0155 {
0156     struct lcd_device *ld = to_lcd_device(dev);
0157 
0158     return sprintf(buf, "%d\n", ld->props.max_contrast);
0159 }
0160 static DEVICE_ATTR_RO(max_contrast);
0161 
0162 static struct class *lcd_class;
0163 
0164 static void lcd_device_release(struct device *dev)
0165 {
0166     struct lcd_device *ld = to_lcd_device(dev);
0167     kfree(ld);
0168 }
0169 
0170 static struct attribute *lcd_device_attrs[] = {
0171     &dev_attr_lcd_power.attr,
0172     &dev_attr_contrast.attr,
0173     &dev_attr_max_contrast.attr,
0174     NULL,
0175 };
0176 ATTRIBUTE_GROUPS(lcd_device);
0177 
0178 /**
0179  * lcd_device_register - register a new object of lcd_device class.
0180  * @name: the name of the new object(must be the same as the name of the
0181  *   respective framebuffer device).
0182  * @parent: pointer to the parent's struct device .
0183  * @devdata: an optional pointer to be stored in the device. The
0184  *   methods may retrieve it by using lcd_get_data(ld).
0185  * @ops: the lcd operations structure.
0186  *
0187  * Creates and registers a new lcd device. Returns either an ERR_PTR()
0188  * or a pointer to the newly allocated device.
0189  */
0190 struct lcd_device *lcd_device_register(const char *name, struct device *parent,
0191         void *devdata, struct lcd_ops *ops)
0192 {
0193     struct lcd_device *new_ld;
0194     int rc;
0195 
0196     pr_debug("lcd_device_register: name=%s\n", name);
0197 
0198     new_ld = kzalloc(sizeof(struct lcd_device), GFP_KERNEL);
0199     if (!new_ld)
0200         return ERR_PTR(-ENOMEM);
0201 
0202     mutex_init(&new_ld->ops_lock);
0203     mutex_init(&new_ld->update_lock);
0204 
0205     new_ld->dev.class = lcd_class;
0206     new_ld->dev.parent = parent;
0207     new_ld->dev.release = lcd_device_release;
0208     dev_set_name(&new_ld->dev, "%s", name);
0209     dev_set_drvdata(&new_ld->dev, devdata);
0210 
0211     new_ld->ops = ops;
0212 
0213     rc = device_register(&new_ld->dev);
0214     if (rc) {
0215         put_device(&new_ld->dev);
0216         return ERR_PTR(rc);
0217     }
0218 
0219     rc = lcd_register_fb(new_ld);
0220     if (rc) {
0221         device_unregister(&new_ld->dev);
0222         return ERR_PTR(rc);
0223     }
0224 
0225     return new_ld;
0226 }
0227 EXPORT_SYMBOL(lcd_device_register);
0228 
0229 /**
0230  * lcd_device_unregister - unregisters a object of lcd_device class.
0231  * @ld: the lcd device object to be unregistered and freed.
0232  *
0233  * Unregisters a previously registered via lcd_device_register object.
0234  */
0235 void lcd_device_unregister(struct lcd_device *ld)
0236 {
0237     if (!ld)
0238         return;
0239 
0240     mutex_lock(&ld->ops_lock);
0241     ld->ops = NULL;
0242     mutex_unlock(&ld->ops_lock);
0243     lcd_unregister_fb(ld);
0244 
0245     device_unregister(&ld->dev);
0246 }
0247 EXPORT_SYMBOL(lcd_device_unregister);
0248 
0249 static void devm_lcd_device_release(struct device *dev, void *res)
0250 {
0251     struct lcd_device *lcd = *(struct lcd_device **)res;
0252 
0253     lcd_device_unregister(lcd);
0254 }
0255 
0256 static int devm_lcd_device_match(struct device *dev, void *res, void *data)
0257 {
0258     struct lcd_device **r = res;
0259 
0260     return *r == data;
0261 }
0262 
0263 /**
0264  * devm_lcd_device_register - resource managed lcd_device_register()
0265  * @dev: the device to register
0266  * @name: the name of the device
0267  * @parent: a pointer to the parent device
0268  * @devdata: an optional pointer to be stored for private driver use
0269  * @ops: the lcd operations structure
0270  *
0271  * @return a struct lcd on success, or an ERR_PTR on error
0272  *
0273  * Managed lcd_device_register(). The lcd_device returned from this function
0274  * are automatically freed on driver detach. See lcd_device_register()
0275  * for more information.
0276  */
0277 struct lcd_device *devm_lcd_device_register(struct device *dev,
0278         const char *name, struct device *parent,
0279         void *devdata, struct lcd_ops *ops)
0280 {
0281     struct lcd_device **ptr, *lcd;
0282 
0283     ptr = devres_alloc(devm_lcd_device_release, sizeof(*ptr), GFP_KERNEL);
0284     if (!ptr)
0285         return ERR_PTR(-ENOMEM);
0286 
0287     lcd = lcd_device_register(name, parent, devdata, ops);
0288     if (!IS_ERR(lcd)) {
0289         *ptr = lcd;
0290         devres_add(dev, ptr);
0291     } else {
0292         devres_free(ptr);
0293     }
0294 
0295     return lcd;
0296 }
0297 EXPORT_SYMBOL(devm_lcd_device_register);
0298 
0299 /**
0300  * devm_lcd_device_unregister - resource managed lcd_device_unregister()
0301  * @dev: the device to unregister
0302  * @ld: the lcd device to unregister
0303  *
0304  * Deallocated a lcd allocated with devm_lcd_device_register(). Normally
0305  * this function will not need to be called and the resource management
0306  * code will ensure that the resource is freed.
0307  */
0308 void devm_lcd_device_unregister(struct device *dev, struct lcd_device *ld)
0309 {
0310     int rc;
0311 
0312     rc = devres_release(dev, devm_lcd_device_release,
0313                 devm_lcd_device_match, ld);
0314     WARN_ON(rc);
0315 }
0316 EXPORT_SYMBOL(devm_lcd_device_unregister);
0317 
0318 
0319 static void __exit lcd_class_exit(void)
0320 {
0321     class_destroy(lcd_class);
0322 }
0323 
0324 static int __init lcd_class_init(void)
0325 {
0326     lcd_class = class_create(THIS_MODULE, "lcd");
0327     if (IS_ERR(lcd_class)) {
0328         pr_warn("Unable to create backlight class; errno = %ld\n",
0329             PTR_ERR(lcd_class));
0330         return PTR_ERR(lcd_class);
0331     }
0332 
0333     lcd_class->dev_groups = lcd_device_groups;
0334     return 0;
0335 }
0336 
0337 /*
0338  * if this is compiled into the kernel, we need to ensure that the
0339  * class is registered before users of the class try to register lcd's
0340  */
0341 postcore_initcall(lcd_class_init);
0342 module_exit(lcd_class_exit);
0343 
0344 MODULE_LICENSE("GPL");
0345 MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
0346 MODULE_DESCRIPTION("LCD Lowlevel Control Abstraction");