1*fabdbf2fSBruno Prémont /*************************************************************************** 2*fabdbf2fSBruno Prémont * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> * 3*fabdbf2fSBruno Prémont * * 4*fabdbf2fSBruno Prémont * Based on Logitech G13 driver (v0.4) * 5*fabdbf2fSBruno Prémont * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * 6*fabdbf2fSBruno Prémont * * 7*fabdbf2fSBruno Prémont * This program is free software: you can redistribute it and/or modify * 8*fabdbf2fSBruno Prémont * it under the terms of the GNU General Public License as published by * 9*fabdbf2fSBruno Prémont * the Free Software Foundation, version 2 of the License. * 10*fabdbf2fSBruno Prémont * * 11*fabdbf2fSBruno Prémont * This driver is distributed in the hope that it will be useful, but * 12*fabdbf2fSBruno Prémont * WITHOUT ANY WARRANTY; without even the implied warranty of * 13*fabdbf2fSBruno Prémont * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14*fabdbf2fSBruno Prémont * General Public License for more details. * 15*fabdbf2fSBruno Prémont * * 16*fabdbf2fSBruno Prémont * You should have received a copy of the GNU General Public License * 17*fabdbf2fSBruno Prémont * along with this software. If not see <http://www.gnu.org/licenses/>. * 18*fabdbf2fSBruno Prémont ***************************************************************************/ 19*fabdbf2fSBruno Prémont 20*fabdbf2fSBruno Prémont #include <linux/hid.h> 21*fabdbf2fSBruno Prémont #include "usbhid/usbhid.h" 22*fabdbf2fSBruno Prémont #include <linux/usb.h> 23*fabdbf2fSBruno Prémont 24*fabdbf2fSBruno Prémont #include <linux/fb.h> 25*fabdbf2fSBruno Prémont #include <linux/lcd.h> 26*fabdbf2fSBruno Prémont 27*fabdbf2fSBruno Prémont #include "hid-picolcd.h" 28*fabdbf2fSBruno Prémont 29*fabdbf2fSBruno Prémont /* 30*fabdbf2fSBruno Prémont * lcd class device 31*fabdbf2fSBruno Prémont */ 32*fabdbf2fSBruno Prémont static int picolcd_get_contrast(struct lcd_device *ldev) 33*fabdbf2fSBruno Prémont { 34*fabdbf2fSBruno Prémont struct picolcd_data *data = lcd_get_data(ldev); 35*fabdbf2fSBruno Prémont return data->lcd_contrast; 36*fabdbf2fSBruno Prémont } 37*fabdbf2fSBruno Prémont 38*fabdbf2fSBruno Prémont static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) 39*fabdbf2fSBruno Prémont { 40*fabdbf2fSBruno Prémont struct picolcd_data *data = lcd_get_data(ldev); 41*fabdbf2fSBruno Prémont struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); 42*fabdbf2fSBruno Prémont unsigned long flags; 43*fabdbf2fSBruno Prémont 44*fabdbf2fSBruno Prémont if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) 45*fabdbf2fSBruno Prémont return -ENODEV; 46*fabdbf2fSBruno Prémont 47*fabdbf2fSBruno Prémont data->lcd_contrast = contrast & 0x0ff; 48*fabdbf2fSBruno Prémont spin_lock_irqsave(&data->lock, flags); 49*fabdbf2fSBruno Prémont hid_set_field(report->field[0], 0, data->lcd_contrast); 50*fabdbf2fSBruno Prémont usbhid_submit_report(data->hdev, report, USB_DIR_OUT); 51*fabdbf2fSBruno Prémont spin_unlock_irqrestore(&data->lock, flags); 52*fabdbf2fSBruno Prémont return 0; 53*fabdbf2fSBruno Prémont } 54*fabdbf2fSBruno Prémont 55*fabdbf2fSBruno Prémont static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) 56*fabdbf2fSBruno Prémont { 57*fabdbf2fSBruno Prémont return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); 58*fabdbf2fSBruno Prémont } 59*fabdbf2fSBruno Prémont 60*fabdbf2fSBruno Prémont static struct lcd_ops picolcd_lcdops = { 61*fabdbf2fSBruno Prémont .get_contrast = picolcd_get_contrast, 62*fabdbf2fSBruno Prémont .set_contrast = picolcd_set_contrast, 63*fabdbf2fSBruno Prémont .check_fb = picolcd_check_lcd_fb, 64*fabdbf2fSBruno Prémont }; 65*fabdbf2fSBruno Prémont 66*fabdbf2fSBruno Prémont int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) 67*fabdbf2fSBruno Prémont { 68*fabdbf2fSBruno Prémont struct device *dev = &data->hdev->dev; 69*fabdbf2fSBruno Prémont struct lcd_device *ldev; 70*fabdbf2fSBruno Prémont 71*fabdbf2fSBruno Prémont if (!report) 72*fabdbf2fSBruno Prémont return -ENODEV; 73*fabdbf2fSBruno Prémont if (report->maxfield != 1 || report->field[0]->report_count != 1 || 74*fabdbf2fSBruno Prémont report->field[0]->report_size != 8) { 75*fabdbf2fSBruno Prémont dev_err(dev, "unsupported CONTRAST report"); 76*fabdbf2fSBruno Prémont return -EINVAL; 77*fabdbf2fSBruno Prémont } 78*fabdbf2fSBruno Prémont 79*fabdbf2fSBruno Prémont ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops); 80*fabdbf2fSBruno Prémont if (IS_ERR(ldev)) { 81*fabdbf2fSBruno Prémont dev_err(dev, "failed to register LCD\n"); 82*fabdbf2fSBruno Prémont return PTR_ERR(ldev); 83*fabdbf2fSBruno Prémont } 84*fabdbf2fSBruno Prémont ldev->props.max_contrast = 0x0ff; 85*fabdbf2fSBruno Prémont data->lcd_contrast = 0xe5; 86*fabdbf2fSBruno Prémont data->lcd = ldev; 87*fabdbf2fSBruno Prémont picolcd_set_contrast(ldev, 0xe5); 88*fabdbf2fSBruno Prémont return 0; 89*fabdbf2fSBruno Prémont } 90*fabdbf2fSBruno Prémont 91*fabdbf2fSBruno Prémont void picolcd_exit_lcd(struct picolcd_data *data) 92*fabdbf2fSBruno Prémont { 93*fabdbf2fSBruno Prémont struct lcd_device *ldev = data->lcd; 94*fabdbf2fSBruno Prémont 95*fabdbf2fSBruno Prémont data->lcd = NULL; 96*fabdbf2fSBruno Prémont if (ldev) 97*fabdbf2fSBruno Prémont lcd_device_unregister(ldev); 98*fabdbf2fSBruno Prémont } 99*fabdbf2fSBruno Prémont 100*fabdbf2fSBruno Prémont int picolcd_resume_lcd(struct picolcd_data *data) 101*fabdbf2fSBruno Prémont { 102*fabdbf2fSBruno Prémont if (!data->lcd) 103*fabdbf2fSBruno Prémont return 0; 104*fabdbf2fSBruno Prémont return picolcd_set_contrast(data->lcd, data->lcd_contrast); 105*fabdbf2fSBruno Prémont } 106*fabdbf2fSBruno Prémont 107