Skip to content

Commit

Permalink
HID: add backlight support to PicoLCD device
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Bruno Prémont authored and Jiri Kosina committed Mar 31, 2010
1 parent b8c21cf commit f1c2176
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 2 deletions.
2 changes: 1 addition & 1 deletion drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ config HID_PICOLCD
- Keypad
- Switching between Firmware and Flash mode
- Framebuffer for monochrome 256x64 display
- Backlight control (needs CONFIG_BACKLIGHT_CLASS_DEVICE)
Features that are not (yet) supported:
- Backlight control
- Contrast control
- IR
- General purpose outputs
Expand Down
115 changes: 114 additions & 1 deletion drivers/hid/hid-picolcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <linux/fb.h>
#include <linux/vmalloc.h>
#include <linux/backlight.h>

#include <linux/seq_file.h>
#include <linux/debugfs.h>
Expand Down Expand Up @@ -183,6 +184,11 @@ struct picolcd_data {
struct fb_info *fb_info;
struct fb_deferred_io fb_defio;
#endif /* CONFIG_FB */
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
struct backlight_device *backlight;
u8 lcd_brightness;
u8 lcd_power;
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */

/* Housekeeping stuff */
spinlock_t lock;
Expand Down Expand Up @@ -729,7 +735,7 @@ static void picolcd_exit_framebuffer(struct picolcd_data *data)
kfree(fb_vbitmap);
}


#define picolcd_fbinfo(d) ((d)->fb_info)
#else
static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
{
Expand All @@ -742,8 +748,107 @@ static inline int picolcd_init_framebuffer(struct picolcd_data *data)
static void picolcd_exit_framebuffer(struct picolcd_data *data)
{
}
#define picolcd_fbinfo(d) NULL
#endif /* CONFIG_FB */

#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
/*
* backlight class device
*/
static int picolcd_get_brightness(struct backlight_device *bdev)
{
struct picolcd_data *data = bl_get_data(bdev);
return data->lcd_brightness;
}

static int picolcd_set_brightness(struct backlight_device *bdev)
{
struct picolcd_data *data = bl_get_data(bdev);
struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
unsigned long flags;

if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
return -ENODEV;

data->lcd_brightness = bdev->props.brightness & 0x0ff;
data->lcd_power = bdev->props.power;
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}

static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
{
return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
}

static const struct backlight_ops picolcd_blops = {
.update_status = picolcd_set_brightness,
.get_brightness = picolcd_get_brightness,
.check_fb = picolcd_check_bl_fb,
};

static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
{
struct device *dev = &data->hdev->dev;
struct backlight_device *bdev;
struct backlight_properties props;
if (!report)
return -ENODEV;
if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
report->field[0]->report_size != 8) {
dev_err(dev, "unsupported BRIGHTNESS report");
return -EINVAL;
}

memset(&props, 0, sizeof(props));
props.max_brightness = 0xff;
bdev = backlight_device_register(dev_name(dev), dev, data,
&picolcd_blops, &props);
if (IS_ERR(bdev)) {
dev_err(dev, "failed to register backlight\n");
return PTR_ERR(bdev);
}
bdev->props.brightness = 0xff;
data->lcd_brightness = 0xff;
data->backlight = bdev;
picolcd_set_brightness(bdev);
return 0;
}

static void picolcd_exit_backlight(struct picolcd_data *data)
{
struct backlight_device *bdev = data->backlight;

data->backlight = NULL;
if (bdev)
backlight_device_unregister(bdev);
}

static inline int picolcd_resume_backlight(struct picolcd_data *data)
{
if (!data->backlight)
return 0;
return picolcd_set_brightness(data->backlight);
}

#else
static inline int picolcd_init_backlight(struct picolcd_data *data,
struct hid_report *report)
{
return 0;
}
static inline void picolcd_exit_backlight(struct picolcd_data *data)
{
}
static inline int picolcd_resume_backlight(struct picolcd_data *data)
{
return 0;
}
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */

/*
* input class device
*/
Expand Down Expand Up @@ -879,6 +984,7 @@ static int picolcd_reset(struct hid_device *hdev)
if (error)
return error;

picolcd_resume_backlight(data);
#if defined(CONFIG_FB) || defined(CONFIG_FB_MODULE)
if (data->fb_info)
schedule_delayed_work(&data->fb_info->deferred_work, 0);
Expand Down Expand Up @@ -1567,6 +1673,11 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
if (error)
goto err;

/* Setup backlight class device */
error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
if (error)
goto err;

#ifdef CONFIG_DEBUG_FS
report = picolcd_out_report(REPORT_READ_MEMORY, hdev);
if (report && report->maxfield == 1 && report->field[0]->report_size == 8)
Expand All @@ -1576,6 +1687,7 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
#endif
return 0;
err:
picolcd_exit_backlight(data);
picolcd_exit_framebuffer(data);
picolcd_exit_cir(data);
picolcd_exit_keys(data);
Expand Down Expand Up @@ -1707,6 +1819,7 @@ static void picolcd_remove(struct hid_device *hdev)
spin_unlock_irqrestore(&data->lock, flags);

/* Clean up the framebuffer */
picolcd_exit_backlight(data);
picolcd_exit_framebuffer(data);
/* Cleanup input */
picolcd_exit_cir(data);
Expand Down

0 comments on commit f1c2176

Please sign in to comment.