18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/***************************************************************************
38c2ecf20Sopenharmony_ci *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
48c2ecf20Sopenharmony_ci *                                                                         *
58c2ecf20Sopenharmony_ci *   Based on Logitech G13 driver (v0.4)                                   *
68c2ecf20Sopenharmony_ci *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
78c2ecf20Sopenharmony_ci *                                                                         *
88c2ecf20Sopenharmony_ci ***************************************************************************/
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define PICOLCD_NAME "PicoLCD (graphic)"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/* Report numbers */
138c2ecf20Sopenharmony_ci#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
148c2ecf20Sopenharmony_ci#define   ERR_SUCCESS            0x00
158c2ecf20Sopenharmony_ci#define   ERR_PARAMETER_MISSING  0x01
168c2ecf20Sopenharmony_ci#define   ERR_DATA_MISSING       0x02
178c2ecf20Sopenharmony_ci#define   ERR_BLOCK_READ_ONLY    0x03
188c2ecf20Sopenharmony_ci#define   ERR_BLOCK_NOT_ERASABLE 0x04
198c2ecf20Sopenharmony_ci#define   ERR_BLOCK_TOO_BIG      0x05
208c2ecf20Sopenharmony_ci#define   ERR_SECTION_OVERFLOW   0x06
218c2ecf20Sopenharmony_ci#define   ERR_INVALID_CMD_LEN    0x07
228c2ecf20Sopenharmony_ci#define   ERR_INVALID_DATA_LEN   0x08
238c2ecf20Sopenharmony_ci#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
248c2ecf20Sopenharmony_ci#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
258c2ecf20Sopenharmony_ci#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
268c2ecf20Sopenharmony_ci#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
278c2ecf20Sopenharmony_ci#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
288c2ecf20Sopenharmony_ci#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
298c2ecf20Sopenharmony_ci#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
308c2ecf20Sopenharmony_ci#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
318c2ecf20Sopenharmony_ci#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
328c2ecf20Sopenharmony_ci#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
338c2ecf20Sopenharmony_ci#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
348c2ecf20Sopenharmony_ci#define	REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
358c2ecf20Sopenharmony_ci#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
368c2ecf20Sopenharmony_ci#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
378c2ecf20Sopenharmony_ci#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
388c2ecf20Sopenharmony_ci#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
398c2ecf20Sopenharmony_ci#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
408c2ecf20Sopenharmony_ci#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
418c2ecf20Sopenharmony_ci#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
428c2ecf20Sopenharmony_ci#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
438c2ecf20Sopenharmony_ci#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
448c2ecf20Sopenharmony_ci#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
458c2ecf20Sopenharmony_ci#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
468c2ecf20Sopenharmony_ci#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
478c2ecf20Sopenharmony_ci#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
488c2ecf20Sopenharmony_ci#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Description of in-progress IO operation, used for operations
518c2ecf20Sopenharmony_ci * that trigger response from device */
528c2ecf20Sopenharmony_cistruct picolcd_pending {
538c2ecf20Sopenharmony_ci	struct hid_report *out_report;
548c2ecf20Sopenharmony_ci	struct hid_report *in_report;
558c2ecf20Sopenharmony_ci	struct completion ready;
568c2ecf20Sopenharmony_ci	int raw_size;
578c2ecf20Sopenharmony_ci	u8 raw_data[64];
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define PICOLCD_KEYS 17
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Per device data structure */
648c2ecf20Sopenharmony_cistruct picolcd_data {
658c2ecf20Sopenharmony_ci	struct hid_device *hdev;
668c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
678c2ecf20Sopenharmony_ci	struct dentry *debug_reset;
688c2ecf20Sopenharmony_ci	struct dentry *debug_eeprom;
698c2ecf20Sopenharmony_ci	struct dentry *debug_flash;
708c2ecf20Sopenharmony_ci	struct mutex mutex_flash;
718c2ecf20Sopenharmony_ci	int addr_sz;
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci	u8 version[2];
748c2ecf20Sopenharmony_ci	unsigned short opmode_delay;
758c2ecf20Sopenharmony_ci	/* input stuff */
768c2ecf20Sopenharmony_ci	u8 pressed_keys[2];
778c2ecf20Sopenharmony_ci	struct input_dev *input_keys;
788c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_CIR
798c2ecf20Sopenharmony_ci	struct rc_dev *rc_dev;
808c2ecf20Sopenharmony_ci#endif
818c2ecf20Sopenharmony_ci	unsigned short keycode[PICOLCD_KEYS];
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_FB
848c2ecf20Sopenharmony_ci	/* Framebuffer stuff */
858c2ecf20Sopenharmony_ci	struct fb_info *fb_info;
868c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_FB */
878c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_LCD
888c2ecf20Sopenharmony_ci	struct lcd_device *lcd;
898c2ecf20Sopenharmony_ci	u8 lcd_contrast;
908c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_LCD */
918c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
928c2ecf20Sopenharmony_ci	struct backlight_device *backlight;
938c2ecf20Sopenharmony_ci	u8 lcd_brightness;
948c2ecf20Sopenharmony_ci	u8 lcd_power;
958c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
968c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_LEDS
978c2ecf20Sopenharmony_ci	/* LED stuff */
988c2ecf20Sopenharmony_ci	u8 led_state;
998c2ecf20Sopenharmony_ci	struct led_classdev *led[8];
1008c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_LEDS */
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* Housekeeping stuff */
1038c2ecf20Sopenharmony_ci	spinlock_t lock;
1048c2ecf20Sopenharmony_ci	struct mutex mutex;
1058c2ecf20Sopenharmony_ci	struct picolcd_pending *pending;
1068c2ecf20Sopenharmony_ci	int status;
1078c2ecf20Sopenharmony_ci#define PICOLCD_BOOTLOADER 1
1088c2ecf20Sopenharmony_ci#define PICOLCD_FAILED 2
1098c2ecf20Sopenharmony_ci#define PICOLCD_CIR_SHUN 4
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_FB
1138c2ecf20Sopenharmony_cistruct picolcd_fb_data {
1148c2ecf20Sopenharmony_ci	/* Framebuffer stuff */
1158c2ecf20Sopenharmony_ci	spinlock_t lock;
1168c2ecf20Sopenharmony_ci	struct picolcd_data *picolcd;
1178c2ecf20Sopenharmony_ci	u8 update_rate;
1188c2ecf20Sopenharmony_ci	u8 bpp;
1198c2ecf20Sopenharmony_ci	u8 force;
1208c2ecf20Sopenharmony_ci	u8 ready;
1218c2ecf20Sopenharmony_ci	u8 *vbitmap;		/* local copy of what was sent to PicoLCD */
1228c2ecf20Sopenharmony_ci	u8 *bitmap;		/* framebuffer */
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_FB */
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* Find a given report */
1278c2ecf20Sopenharmony_ci#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
1288c2ecf20Sopenharmony_ci#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistruct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
1338c2ecf20Sopenharmony_civoid picolcd_debug_out_report(struct picolcd_data *data,
1348c2ecf20Sopenharmony_ci		struct hid_device *hdev, struct hid_report *report);
1358c2ecf20Sopenharmony_ci#define hid_hw_request(a, b, c) \
1368c2ecf20Sopenharmony_ci	do { \
1378c2ecf20Sopenharmony_ci		picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
1388c2ecf20Sopenharmony_ci		hid_hw_request(a, b, c); \
1398c2ecf20Sopenharmony_ci	} while (0)
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_civoid picolcd_debug_raw_event(struct picolcd_data *data,
1428c2ecf20Sopenharmony_ci		struct hid_device *hdev, struct hid_report *report,
1438c2ecf20Sopenharmony_ci		u8 *raw_data, int size);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_civoid picolcd_init_devfs(struct picolcd_data *data,
1468c2ecf20Sopenharmony_ci		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
1478c2ecf20Sopenharmony_ci		struct hid_report *flash_r, struct hid_report *flash_w,
1488c2ecf20Sopenharmony_ci		struct hid_report *reset);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_civoid picolcd_exit_devfs(struct picolcd_data *data);
1518c2ecf20Sopenharmony_ci#else
1528c2ecf20Sopenharmony_cistatic inline void picolcd_debug_out_report(struct picolcd_data *data,
1538c2ecf20Sopenharmony_ci		struct hid_device *hdev, struct hid_report *report)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_cistatic inline void picolcd_debug_raw_event(struct picolcd_data *data,
1578c2ecf20Sopenharmony_ci		struct hid_device *hdev, struct hid_report *report,
1588c2ecf20Sopenharmony_ci		u8 *raw_data, int size)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_cistatic inline void picolcd_init_devfs(struct picolcd_data *data,
1628c2ecf20Sopenharmony_ci		struct hid_report *eeprom_r, struct hid_report *eeprom_w,
1638c2ecf20Sopenharmony_ci		struct hid_report *flash_r, struct hid_report *flash_w,
1648c2ecf20Sopenharmony_ci		struct hid_report *reset)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_cistatic inline void picolcd_exit_devfs(struct picolcd_data *data)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_FB
1748c2ecf20Sopenharmony_ciint picolcd_fb_reset(struct picolcd_data *data, int clear);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ciint picolcd_init_framebuffer(struct picolcd_data *data);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_civoid picolcd_exit_framebuffer(struct picolcd_data *data);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_civoid picolcd_fb_refresh(struct picolcd_data *data);
1818c2ecf20Sopenharmony_ci#define picolcd_fbinfo(d) ((d)->fb_info)
1828c2ecf20Sopenharmony_ci#else
1838c2ecf20Sopenharmony_cistatic inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_cistatic inline int picolcd_init_framebuffer(struct picolcd_data *data)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_cistatic inline void picolcd_exit_framebuffer(struct picolcd_data *data)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_cistatic inline void picolcd_fb_refresh(struct picolcd_data *data)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci#define picolcd_fbinfo(d) NULL
1988c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_FB */
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
2028c2ecf20Sopenharmony_ciint picolcd_init_backlight(struct picolcd_data *data,
2038c2ecf20Sopenharmony_ci		struct hid_report *report);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_civoid picolcd_exit_backlight(struct picolcd_data *data);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ciint picolcd_resume_backlight(struct picolcd_data *data);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_civoid picolcd_suspend_backlight(struct picolcd_data *data);
2108c2ecf20Sopenharmony_ci#else
2118c2ecf20Sopenharmony_cistatic inline int picolcd_init_backlight(struct picolcd_data *data,
2128c2ecf20Sopenharmony_ci		struct hid_report *report)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_cistatic inline void picolcd_exit_backlight(struct picolcd_data *data)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_cistatic inline int picolcd_resume_backlight(struct picolcd_data *data)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_cistatic inline void picolcd_suspend_backlight(struct picolcd_data *data)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_LCD
2318c2ecf20Sopenharmony_ciint picolcd_init_lcd(struct picolcd_data *data,
2328c2ecf20Sopenharmony_ci		struct hid_report *report);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_civoid picolcd_exit_lcd(struct picolcd_data *data);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ciint picolcd_resume_lcd(struct picolcd_data *data);
2378c2ecf20Sopenharmony_ci#else
2388c2ecf20Sopenharmony_cistatic inline int picolcd_init_lcd(struct picolcd_data *data,
2398c2ecf20Sopenharmony_ci		struct hid_report *report)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	return 0;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_cistatic inline void picolcd_exit_lcd(struct picolcd_data *data)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_cistatic inline int picolcd_resume_lcd(struct picolcd_data *data)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_LCD */
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_LEDS
2548c2ecf20Sopenharmony_ciint picolcd_init_leds(struct picolcd_data *data,
2558c2ecf20Sopenharmony_ci		struct hid_report *report);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_civoid picolcd_exit_leds(struct picolcd_data *data);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_civoid picolcd_leds_set(struct picolcd_data *data);
2608c2ecf20Sopenharmony_ci#else
2618c2ecf20Sopenharmony_cistatic inline int picolcd_init_leds(struct picolcd_data *data,
2628c2ecf20Sopenharmony_ci		struct hid_report *report)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	return 0;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_cistatic inline void picolcd_exit_leds(struct picolcd_data *data)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_cistatic inline void picolcd_leds_set(struct picolcd_data *data)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_LEDS */
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci#ifdef CONFIG_HID_PICOLCD_CIR
2768c2ecf20Sopenharmony_ciint picolcd_raw_cir(struct picolcd_data *data,
2778c2ecf20Sopenharmony_ci		struct hid_report *report, u8 *raw_data, int size);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ciint picolcd_init_cir(struct picolcd_data *data, struct hid_report *report);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_civoid picolcd_exit_cir(struct picolcd_data *data);
2828c2ecf20Sopenharmony_ci#else
2838c2ecf20Sopenharmony_cistatic inline int picolcd_raw_cir(struct picolcd_data *data,
2848c2ecf20Sopenharmony_ci		struct hid_report *report, u8 *raw_data, int size)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	return 1;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_cistatic inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_cistatic inline void picolcd_exit_cir(struct picolcd_data *data)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci#endif /* CONFIG_HID_PICOLCD_CIR */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ciint picolcd_reset(struct hid_device *hdev);
2988c2ecf20Sopenharmony_cistruct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
2998c2ecf20Sopenharmony_ci			int report_id, const u8 *raw_data, int size);
300