diff options
author | Bruno Prémont <bonbons@linux-vserver.org> | 2010-03-30 16:36:07 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-03-31 05:32:26 -0400 |
commit | e8d931bb5977a5b36cc8e9b0fd2f26cb80a6c207 (patch) | |
tree | 03b72db7f27226893e8362946a2ccb088d2e7b50 /drivers/hid/hid-picolcd.c | |
parent | f1c21761408c968ed1deb8f54fd60be9471999c1 (diff) |
HID: add lcd support to PicoLCD device
Add lcd support to PicoLCD device.
LCD support depends on lcd class and is only being
compiled if lcd class has been selected.
Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-picolcd.c')
-rw-r--r-- | drivers/hid/hid-picolcd.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 0ea7a3f44bb5..99a488363a4e 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c | |||
@@ -27,6 +27,7 @@ | |||
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 | #include <linux/backlight.h> |
30 | #include <linux/lcd.h> | ||
30 | 31 | ||
31 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
32 | #include <linux/debugfs.h> | 33 | #include <linux/debugfs.h> |
@@ -184,6 +185,10 @@ struct picolcd_data { | |||
184 | struct fb_info *fb_info; | 185 | struct fb_info *fb_info; |
185 | struct fb_deferred_io fb_defio; | 186 | struct fb_deferred_io fb_defio; |
186 | #endif /* CONFIG_FB */ | 187 | #endif /* CONFIG_FB */ |
188 | #if defined(CONFIG_LCD_CLASS_DEVICE) || defined(CONFIG_LCD_CLASS_DEVICE_MODULE) | ||
189 | struct lcd_device *lcd; | ||
190 | u8 lcd_contrast; | ||
191 | #endif | ||
187 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) | 192 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) |
188 | struct backlight_device *backlight; | 193 | struct backlight_device *backlight; |
189 | u8 lcd_brightness; | 194 | u8 lcd_brightness; |
@@ -849,6 +854,99 @@ static inline int picolcd_resume_backlight(struct picolcd_data *data) | |||
849 | } | 854 | } |
850 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ | 855 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
851 | 856 | ||
857 | #if defined(CONFIG_LCD_CLASS_DEVICE) || defined(CONFIG_LCD_CLASS_DEVICE_MODULE) | ||
858 | /* | ||
859 | * lcd class device | ||
860 | */ | ||
861 | static int picolcd_get_contrast(struct lcd_device *ldev) | ||
862 | { | ||
863 | struct picolcd_data *data = lcd_get_data(ldev); | ||
864 | return data->lcd_contrast; | ||
865 | } | ||
866 | |||
867 | static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) | ||
868 | { | ||
869 | struct picolcd_data *data = lcd_get_data(ldev); | ||
870 | struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); | ||
871 | unsigned long flags; | ||
872 | |||
873 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
874 | return -ENODEV; | ||
875 | |||
876 | data->lcd_contrast = contrast & 0x0ff; | ||
877 | spin_lock_irqsave(&data->lock, flags); | ||
878 | hid_set_field(report->field[0], 0, data->lcd_contrast); | ||
879 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
880 | spin_unlock_irqrestore(&data->lock, flags); | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) | ||
885 | { | ||
886 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); | ||
887 | } | ||
888 | |||
889 | static struct lcd_ops picolcd_lcdops = { | ||
890 | .get_contrast = picolcd_get_contrast, | ||
891 | .set_contrast = picolcd_set_contrast, | ||
892 | .check_fb = picolcd_check_lcd_fb, | ||
893 | }; | ||
894 | |||
895 | static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) | ||
896 | { | ||
897 | struct device *dev = &data->hdev->dev; | ||
898 | struct lcd_device *ldev; | ||
899 | |||
900 | if (!report) | ||
901 | return -ENODEV; | ||
902 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
903 | report->field[0]->report_size != 8) { | ||
904 | dev_err(dev, "unsupported CONTRAST report"); | ||
905 | return -EINVAL; | ||
906 | } | ||
907 | |||
908 | ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops); | ||
909 | if (IS_ERR(ldev)) { | ||
910 | dev_err(dev, "failed to register LCD\n"); | ||
911 | return PTR_ERR(ldev); | ||
912 | } | ||
913 | ldev->props.max_contrast = 0x0ff; | ||
914 | data->lcd_contrast = 0xe5; | ||
915 | data->lcd = ldev; | ||
916 | picolcd_set_contrast(ldev, 0xe5); | ||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | static void picolcd_exit_lcd(struct picolcd_data *data) | ||
921 | { | ||
922 | struct lcd_device *ldev = data->lcd; | ||
923 | |||
924 | data->lcd = NULL; | ||
925 | if (ldev) | ||
926 | lcd_device_unregister(ldev); | ||
927 | } | ||
928 | |||
929 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
930 | { | ||
931 | if (!data->lcd) | ||
932 | return 0; | ||
933 | return picolcd_set_contrast(data->lcd, data->lcd_contrast); | ||
934 | } | ||
935 | #else | ||
936 | static inline int picolcd_init_lcd(struct picolcd_data *data, | ||
937 | struct hid_report *report) | ||
938 | { | ||
939 | return 0; | ||
940 | } | ||
941 | static inline void picolcd_exit_lcd(struct picolcd_data *data) | ||
942 | { | ||
943 | } | ||
944 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
945 | { | ||
946 | return 0; | ||
947 | } | ||
948 | #endif /* CONFIG_LCD_CLASS_DEVICE */ | ||
949 | |||
852 | /* | 950 | /* |
853 | * input class device | 951 | * input class device |
854 | */ | 952 | */ |
@@ -984,6 +1082,7 @@ static int picolcd_reset(struct hid_device *hdev) | |||
984 | if (error) | 1082 | if (error) |
985 | return error; | 1083 | return error; |
986 | 1084 | ||
1085 | picolcd_resume_lcd(data); | ||
987 | picolcd_resume_backlight(data); | 1086 | picolcd_resume_backlight(data); |
988 | #if defined(CONFIG_FB) || defined(CONFIG_FB_MODULE) | 1087 | #if defined(CONFIG_FB) || defined(CONFIG_FB_MODULE) |
989 | if (data->fb_info) | 1088 | if (data->fb_info) |
@@ -1673,6 +1772,11 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | |||
1673 | if (error) | 1772 | if (error) |
1674 | goto err; | 1773 | goto err; |
1675 | 1774 | ||
1775 | /* Setup lcd class device */ | ||
1776 | error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev)); | ||
1777 | if (error) | ||
1778 | goto err; | ||
1779 | |||
1676 | /* Setup backlight class device */ | 1780 | /* Setup backlight class device */ |
1677 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); | 1781 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); |
1678 | if (error) | 1782 | if (error) |
@@ -1688,6 +1792,7 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | |||
1688 | return 0; | 1792 | return 0; |
1689 | err: | 1793 | err: |
1690 | picolcd_exit_backlight(data); | 1794 | picolcd_exit_backlight(data); |
1795 | picolcd_exit_lcd(data); | ||
1691 | picolcd_exit_framebuffer(data); | 1796 | picolcd_exit_framebuffer(data); |
1692 | picolcd_exit_cir(data); | 1797 | picolcd_exit_cir(data); |
1693 | picolcd_exit_keys(data); | 1798 | picolcd_exit_keys(data); |
@@ -1820,6 +1925,7 @@ static void picolcd_remove(struct hid_device *hdev) | |||
1820 | 1925 | ||
1821 | /* Clean up the framebuffer */ | 1926 | /* Clean up the framebuffer */ |
1822 | picolcd_exit_backlight(data); | 1927 | picolcd_exit_backlight(data); |
1928 | picolcd_exit_lcd(data); | ||
1823 | picolcd_exit_framebuffer(data); | 1929 | picolcd_exit_framebuffer(data); |
1824 | /* Cleanup input */ | 1930 | /* Cleanup input */ |
1825 | picolcd_exit_cir(data); | 1931 | picolcd_exit_cir(data); |