diff options
author | Bruno Prémont <bonbons@linux-vserver.org> | 2010-03-30 16:35:27 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-03-31 05:32:11 -0400 |
commit | f1c21761408c968ed1deb8f54fd60be9471999c1 (patch) | |
tree | 62897258cdefa707faf0dcddee988f14711b62da | |
parent | b8c21cf697d165999cc21a90e6caa73690ac6190 (diff) |
HID: add backlight support to PicoLCD device
Add backlight support to PicoLCD device.
Backlight support depends on backlight class and is only being
compiled if backlight class has been selected.
Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/Kconfig | 2 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd.c | 115 |
2 files changed, 115 insertions, 2 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a813ea9c792d..588b9acecb7a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -278,8 +278,8 @@ config HID_PICOLCD | |||
278 | - Keypad | 278 | - Keypad |
279 | - Switching between Firmware and Flash mode | 279 | - Switching between Firmware and Flash mode |
280 | - Framebuffer for monochrome 256x64 display | 280 | - Framebuffer for monochrome 256x64 display |
281 | - Backlight control (needs CONFIG_BACKLIGHT_CLASS_DEVICE) | ||
281 | Features that are not (yet) supported: | 282 | Features that are not (yet) supported: |
282 | - Backlight control | ||
283 | - Contrast control | 283 | - Contrast control |
284 | - IR | 284 | - IR |
285 | - General purpose outputs | 285 | - General purpose outputs |
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index e14464789e10..0ea7a3f44bb5 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <linux/fb.h> | 27 | #include <linux/fb.h> |
28 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
29 | #include <linux/backlight.h> | ||
29 | 30 | ||
30 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
31 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
@@ -183,6 +184,11 @@ struct picolcd_data { | |||
183 | struct fb_info *fb_info; | 184 | struct fb_info *fb_info; |
184 | struct fb_deferred_io fb_defio; | 185 | struct fb_deferred_io fb_defio; |
185 | #endif /* CONFIG_FB */ | 186 | #endif /* CONFIG_FB */ |
187 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) | ||
188 | struct backlight_device *backlight; | ||
189 | u8 lcd_brightness; | ||
190 | u8 lcd_power; | ||
191 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ | ||
186 | 192 | ||
187 | /* Housekeeping stuff */ | 193 | /* Housekeeping stuff */ |
188 | spinlock_t lock; | 194 | spinlock_t lock; |
@@ -729,7 +735,7 @@ static void picolcd_exit_framebuffer(struct picolcd_data *data) | |||
729 | kfree(fb_vbitmap); | 735 | kfree(fb_vbitmap); |
730 | } | 736 | } |
731 | 737 | ||
732 | 738 | #define picolcd_fbinfo(d) ((d)->fb_info) | |
733 | #else | 739 | #else |
734 | static inline int picolcd_fb_reset(struct picolcd_data *data, int clear) | 740 | static inline int picolcd_fb_reset(struct picolcd_data *data, int clear) |
735 | { | 741 | { |
@@ -742,8 +748,107 @@ static inline int picolcd_init_framebuffer(struct picolcd_data *data) | |||
742 | static void picolcd_exit_framebuffer(struct picolcd_data *data) | 748 | static void picolcd_exit_framebuffer(struct picolcd_data *data) |
743 | { | 749 | { |
744 | } | 750 | } |
751 | #define picolcd_fbinfo(d) NULL | ||
745 | #endif /* CONFIG_FB */ | 752 | #endif /* CONFIG_FB */ |
746 | 753 | ||
754 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) | ||
755 | /* | ||
756 | * backlight class device | ||
757 | */ | ||
758 | static int picolcd_get_brightness(struct backlight_device *bdev) | ||
759 | { | ||
760 | struct picolcd_data *data = bl_get_data(bdev); | ||
761 | return data->lcd_brightness; | ||
762 | } | ||
763 | |||
764 | static int picolcd_set_brightness(struct backlight_device *bdev) | ||
765 | { | ||
766 | struct picolcd_data *data = bl_get_data(bdev); | ||
767 | struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); | ||
768 | unsigned long flags; | ||
769 | |||
770 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
771 | return -ENODEV; | ||
772 | |||
773 | data->lcd_brightness = bdev->props.brightness & 0x0ff; | ||
774 | data->lcd_power = bdev->props.power; | ||
775 | spin_lock_irqsave(&data->lock, flags); | ||
776 | hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); | ||
777 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
778 | spin_unlock_irqrestore(&data->lock, flags); | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb) | ||
783 | { | ||
784 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev)); | ||
785 | } | ||
786 | |||
787 | static const struct backlight_ops picolcd_blops = { | ||
788 | .update_status = picolcd_set_brightness, | ||
789 | .get_brightness = picolcd_get_brightness, | ||
790 | .check_fb = picolcd_check_bl_fb, | ||
791 | }; | ||
792 | |||
793 | static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) | ||
794 | { | ||
795 | struct device *dev = &data->hdev->dev; | ||
796 | struct backlight_device *bdev; | ||
797 | struct backlight_properties props; | ||
798 | if (!report) | ||
799 | return -ENODEV; | ||
800 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
801 | report->field[0]->report_size != 8) { | ||
802 | dev_err(dev, "unsupported BRIGHTNESS report"); | ||
803 | return -EINVAL; | ||
804 | } | ||
805 | |||
806 | memset(&props, 0, sizeof(props)); | ||
807 | props.max_brightness = 0xff; | ||
808 | bdev = backlight_device_register(dev_name(dev), dev, data, | ||
809 | &picolcd_blops, &props); | ||
810 | if (IS_ERR(bdev)) { | ||
811 | dev_err(dev, "failed to register backlight\n"); | ||
812 | return PTR_ERR(bdev); | ||
813 | } | ||
814 | bdev->props.brightness = 0xff; | ||
815 | data->lcd_brightness = 0xff; | ||
816 | data->backlight = bdev; | ||
817 | picolcd_set_brightness(bdev); | ||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | static void picolcd_exit_backlight(struct picolcd_data *data) | ||
822 | { | ||
823 | struct backlight_device *bdev = data->backlight; | ||
824 | |||
825 | data->backlight = NULL; | ||
826 | if (bdev) | ||
827 | backlight_device_unregister(bdev); | ||
828 | } | ||
829 | |||
830 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
831 | { | ||
832 | if (!data->backlight) | ||
833 | return 0; | ||
834 | return picolcd_set_brightness(data->backlight); | ||
835 | } | ||
836 | |||
837 | #else | ||
838 | static inline int picolcd_init_backlight(struct picolcd_data *data, | ||
839 | struct hid_report *report) | ||
840 | { | ||
841 | return 0; | ||
842 | } | ||
843 | static inline void picolcd_exit_backlight(struct picolcd_data *data) | ||
844 | { | ||
845 | } | ||
846 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
847 | { | ||
848 | return 0; | ||
849 | } | ||
850 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ | ||
851 | |||
747 | /* | 852 | /* |
748 | * input class device | 853 | * input class device |
749 | */ | 854 | */ |
@@ -879,6 +984,7 @@ static int picolcd_reset(struct hid_device *hdev) | |||
879 | if (error) | 984 | if (error) |
880 | return error; | 985 | return error; |
881 | 986 | ||
987 | picolcd_resume_backlight(data); | ||
882 | #if defined(CONFIG_FB) || defined(CONFIG_FB_MODULE) | 988 | #if defined(CONFIG_FB) || defined(CONFIG_FB_MODULE) |
883 | if (data->fb_info) | 989 | if (data->fb_info) |
884 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | 990 | schedule_delayed_work(&data->fb_info->deferred_work, 0); |
@@ -1567,6 +1673,11 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | |||
1567 | if (error) | 1673 | if (error) |
1568 | goto err; | 1674 | goto err; |
1569 | 1675 | ||
1676 | /* Setup backlight class device */ | ||
1677 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); | ||
1678 | if (error) | ||
1679 | goto err; | ||
1680 | |||
1570 | #ifdef CONFIG_DEBUG_FS | 1681 | #ifdef CONFIG_DEBUG_FS |
1571 | report = picolcd_out_report(REPORT_READ_MEMORY, hdev); | 1682 | report = picolcd_out_report(REPORT_READ_MEMORY, hdev); |
1572 | if (report && report->maxfield == 1 && report->field[0]->report_size == 8) | 1683 | if (report && report->maxfield == 1 && report->field[0]->report_size == 8) |
@@ -1576,6 +1687,7 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | |||
1576 | #endif | 1687 | #endif |
1577 | return 0; | 1688 | return 0; |
1578 | err: | 1689 | err: |
1690 | picolcd_exit_backlight(data); | ||
1579 | picolcd_exit_framebuffer(data); | 1691 | picolcd_exit_framebuffer(data); |
1580 | picolcd_exit_cir(data); | 1692 | picolcd_exit_cir(data); |
1581 | picolcd_exit_keys(data); | 1693 | picolcd_exit_keys(data); |
@@ -1707,6 +1819,7 @@ static void picolcd_remove(struct hid_device *hdev) | |||
1707 | spin_unlock_irqrestore(&data->lock, flags); | 1819 | spin_unlock_irqrestore(&data->lock, flags); |
1708 | 1820 | ||
1709 | /* Clean up the framebuffer */ | 1821 | /* Clean up the framebuffer */ |
1822 | picolcd_exit_backlight(data); | ||
1710 | picolcd_exit_framebuffer(data); | 1823 | picolcd_exit_framebuffer(data); |
1711 | /* Cleanup input */ | 1824 | /* Cleanup input */ |
1712 | picolcd_exit_cir(data); | 1825 | picolcd_exit_cir(data); |