diff options
| -rw-r--r-- | drivers/hid/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/hid/hid-picolcd.c | 106 |
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 | */ | ||
| 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); |
