aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBruno Prémont <bonbons@linux-vserver.org>2010-03-30 16:36:07 -0400
committerJiri Kosina <jkosina@suse.cz>2010-03-31 05:32:26 -0400
commite8d931bb5977a5b36cc8e9b0fd2f26cb80a6c207 (patch)
tree03b72db7f27226893e8362946a2ccb088d2e7b50 /drivers
parentf1c21761408c968ed1deb8f54fd60be9471999c1 (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')
-rw-r--r--drivers/hid/Kconfig2
-rw-r--r--drivers/hid/hid-picolcd.c106
2 files changed, 107 insertions, 1 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 588b9acecb7a..399edc53963e 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -279,8 +279,8 @@ config HID_PICOLCD
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 - Backlight control (needs CONFIG_BACKLIGHT_CLASS_DEVICE)
282 - Contrast control (needs CONFIG_LCD_CLASS_DEVICE)
282 Features that are not (yet) supported: 283 Features that are not (yet) supported:
283 - Contrast control
284 - IR 284 - IR
285 - General purpose outputs 285 - General purpose outputs
286 - EEProm / Flash access 286 - EEProm / Flash access
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 */
861static 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
867static 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
884static 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
889static 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
895static 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
920static 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
929static 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
936static inline int picolcd_init_lcd(struct picolcd_data *data,
937 struct hid_report *report)
938{
939 return 0;
940}
941static inline void picolcd_exit_lcd(struct picolcd_data *data)
942{
943}
944static 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;
1689err: 1793err:
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);