1 // SPDX-License-Identifier: GPL-2.0-only 2 /*************************************************************************** 3 * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * 4 * * 5 * Based on Logitech G13 driver (v0.4) * 6 * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * 7 * * 8 ***************************************************************************/ 9 10 #include <linux/hid.h> 11 12 #include <linux/backlight.h> 13 14 #include "hid-picolcd.h" 15 16 static int picolcd_get_brightness(struct backlight_device *bdev) 17 { 18 struct picolcd_data *data = bl_get_data(bdev); 19 return data->lcd_brightness; 20 } 21 22 static int picolcd_set_brightness(struct backlight_device *bdev) 23 { 24 struct picolcd_data *data = bl_get_data(bdev); 25 struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); 26 unsigned long flags; 27 28 if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) 29 return -ENODEV; 30 31 data->lcd_brightness = bdev->props.brightness & 0x0ff; 32 data->lcd_power = bdev->props.power; 33 spin_lock_irqsave(&data->lock, flags); 34 hid_set_field(report->field[0], 0, 35 data->lcd_power == BACKLIGHT_POWER_ON ? data->lcd_brightness : 0); 36 if (!(data->status & PICOLCD_FAILED)) 37 hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT); 38 spin_unlock_irqrestore(&data->lock, flags); 39 return 0; 40 } 41 42 static const struct backlight_ops picolcd_blops = { 43 .update_status = picolcd_set_brightness, 44 .get_brightness = picolcd_get_brightness, 45 }; 46 47 int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) 48 { 49 struct device *dev = &data->hdev->dev; 50 struct backlight_device *bdev; 51 struct backlight_properties props; 52 if (!report) 53 return -ENODEV; 54 if (report->maxfield != 1 || report->field[0]->report_count != 1 || 55 report->field[0]->report_size != 8) { 56 dev_err(dev, "unsupported BRIGHTNESS report"); 57 return -EINVAL; 58 } 59 60 memset(&props, 0, sizeof(props)); 61 props.type = BACKLIGHT_RAW; 62 props.max_brightness = 0xff; 63 bdev = backlight_device_register(dev_name(dev), dev, data, 64 &picolcd_blops, &props); 65 if (IS_ERR(bdev)) { 66 dev_err(dev, "failed to register backlight\n"); 67 return PTR_ERR(bdev); 68 } 69 bdev->props.brightness = 0xff; 70 data->lcd_brightness = 0xff; 71 data->backlight = bdev; 72 picolcd_set_brightness(bdev); 73 return 0; 74 } 75 76 void picolcd_exit_backlight(struct picolcd_data *data) 77 { 78 struct backlight_device *bdev = data->backlight; 79 80 data->backlight = NULL; 81 backlight_device_unregister(bdev); 82 } 83 84 int picolcd_resume_backlight(struct picolcd_data *data) 85 { 86 if (!data->backlight) 87 return 0; 88 return picolcd_set_brightness(data->backlight); 89 } 90 91 #ifdef CONFIG_PM 92 void picolcd_suspend_backlight(struct picolcd_data *data) 93 { 94 int bl_power = data->lcd_power; 95 if (!data->backlight) 96 return; 97 98 data->backlight->props.power = BACKLIGHT_POWER_OFF; 99 picolcd_set_brightness(data->backlight); 100 data->lcd_power = data->backlight->props.power = bl_power; 101 } 102 #endif /* CONFIG_PM */ 103 104